Skip to content

feat: 모임 생성 1단계 기본 정보 입력 화면 UI 개편 및 홈 리다이렉트 추가 - #71

Merged
yoohyun-1203 merged 2 commits into
devfrom
feature/32-schedule-ui
Jun 14, 2026
Merged

feat: 모임 생성 1단계 기본 정보 입력 화면 UI 개편 및 홈 리다이렉트 추가#71
yoohyun-1203 merged 2 commits into
devfrom
feature/32-schedule-ui

Conversation

@yoohyun-1203

@yoohyun-1203 yoohyun-1203 commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

🚀 작업 내용 (What)

  • 모임 일정 만들기 1단계에 디자인에서 빠져있던 날짜 입력하는거 넣었음

📣 핵심 변경 이유 (Why)

  • 모임 만드는데 날짜는 넣어야지요 ..?

📸 스크린샷 (Visuals, 선택)

image

⚠️ 체크리스트 (Checklist)

  • 브랜치 컨벤션(feature/00-name)을 지켰나요?
  • 커밋 컨벤션(feat:, fix: 등)을 지켰나요?
  • 작업 전에 관련 이슈를 생성하고 연결했나요?
  • 내 코드가 팀의 기존 코드를 망가뜨리지 않았는지 확인했나요?

🔗 관련 이슈 (Issue)

Close #

@vercel

vercel Bot commented Jun 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
moim-app Ready Ready Preview, Comment Jun 14, 2026 10:09am

@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

Summary by CodeRabbit

변경 사항

  • 새로운 기능

    • 일정 생성 시 후보 날짜 범위와 응답 마감일 설정 기능 추가
    • 캘린더에 실제 일정 데이터 표시 및 날짜 범위 검색 기능 제공
    • 로그인한 사용자 자동 리다이렉트
  • UI 개선

    • 대시보드 레이아웃 단순화 및 일정 미리보기 화면 개선
    • 일정 폼 입력 필드 확장 및 유효성 검사 강화

Walkthrough

루트 페이지(page.tsx)를 async로 전환해 Supabase 사용자 조회 후 인증된 사용자를 /dashboard로 리다이렉트하는 엔트리 가드를 추가했습니다. 대시보드 레이아웃은 복잡한 사이드바/헤더를 제거하고 MoimShell·MoimTopBar 기반 간단한 래퍼로 교체했으며, 대시보드 페이지에서 사용자 일정을 Prisma로 조회해 SchedulerPreview에 전달하도록 개편했습니다. SchedulerPreview와 CalendarBoard는 동적 데이터 기반으로 일정 블록과 "내 모임" 영역을 렌더링하도록 변경되었습니다. 동시에 일정 생성 Step1 폼에 후보 날짜 범위·응답 마감일 필드를 추가하고, 소요 시간을 자유 입력으로 변경한 뒤 날짜 순서·과거 여부·마감일 범위 검증을 강화했습니다.

Changes

대시보드 인증 및 시각화

Layer / File(s) Summary
루트 페이지 인증 리다이렉트
src/app/page.tsx
Home async 전환, Supabase 서버 클라이언트로 user 조회 후 인증 시 /dashboard 리다이렉트.
대시보드 레이아웃 및 페이지 개편
src/app/dashboard/layout.tsx, src/app/dashboard/page.tsx
레이아웃: MoimShell·MoimTopBar 기반 간단 래퍼로 교체. 페이지: prisma.schedule.findMany(creatorId) 조회 후 SchedulerPreview에 schedules 전달.
스케줄러 데이터 타입 및 시그니처
src/components/moim/reference-ui.tsx
ScheduleItem 타입 정의. SchedulerPreview 시그니처에 schedules 프롭, 시작일/종료일 상태, 검색 핸들러 추가.
스케줄러 검색 및 캘린더 동적 렌더링
src/components/moim/reference-ui.tsx
Date 범위 검색 UI, activeDays 기반 CalendarBoard 갱신. confirmedSlot 확정 블록, candidateDays 조율 블록 절대 배치. "내 모임" 영역을 schedules 기반으로 동적 렌더링.

일정 생성 Step1 폼 개편

Layer / File(s) Summary
스키마 및 상태 확장
src/features/schedules/schedule.schema.ts, src/app/schedule/create/CreateScheduleClient.tsx
createScheduleSchemacandidateStartDate, candidateEndDate, responseDeadline 옵션 필드 추가. Step1 상태를 5개 필드 빈 문자열로 초기화.
제출 로직 및 검증 강화
src/app/schedule/create/CreateScheduleClient.tsx
handleSubmit에서 durationMinutes 정규식 숫자 추출 후 parsedDuration 변환. validateScheduleForm에 후보 날짜 순서(종료 ≥ 시작), 과거 여부, 마감일(현재 이후·범위 내) 검증 추가. 소요 시간 15~480분 범위 강제.
폼 UI 개편
src/app/schedule/create/CreateScheduleClient.tsx
소요 시간 select → type="number" 전환. 후보 날짜 시작/종료(date), 응답 마감일(datetime-local) 입력 필드, 마감 안내 문구 추가.

Sequence Diagram(s)

sequenceDiagram
  participant Browser as 브라우저
  participant Home as Home (async)
  participant SupabaseAuth as Supabase Auth
  participant DashboardPage as DashboardPage
  participant Prisma as Prisma
  participant SchedulerUI as SchedulerPreview

  Browser->>Home: GET /
  Home->>SupabaseAuth: getUser()
  SupabaseAuth-->>Home: user | null
  alt user 존재
    Home->>Browser: redirect('/dashboard')
    Browser->>DashboardPage: GET /dashboard
    DashboardPage->>SupabaseAuth: getUser()
    SupabaseAuth-->>DashboardPage: user (인증 완료)
    DashboardPage->>Prisma: findMany({ creatorId }, orderBy createdAt desc)
    Prisma-->>DashboardPage: Schedule[]
    DashboardPage->>SchedulerUI: schedules={schedules}
    SchedulerUI-->>DashboardPage: 렌더링 (캘린더·"내 모임")
  else user 없음
    Home-->>Browser: 랜딩 페이지 렌더링
  end
Loading

추정 리뷰 노력

🎯 3 (Moderate) | ⏱️ ~25 minutes

관련 PR

  • Siul49/moim#41: CreateScheduleClientschedule.schema.ts의 후보 날짜 범위·응답 마감일 필드 추가, durationMinutes 파싱 로직이 백엔드 일정 모델·API 처리 변경에 직접 빌드됩니다.

Suggested Labels

feature

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive PR 설명이 템플릿 구조를 따르고 있으나, 작업 내용이 미흡하며 핵심 변경 이유가 피상적이고 관련 이슈 번호가 미입력 상태이다. 작업 내용에 '홈 리다이렉트 추가', 'validateScheduleForm 검증 로직 확대', 'CalendarBoard 동적 렌더링' 등 전체 변경사항을 구체적으로 기술하고, 관련 이슈 번호를 입력하세요.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 'feat:' 프리픽스를 포함하고 있으며, 주요 변경사항인 모임 생성 1단계 UI 개편과 홈 리다이렉트 기능을 명확하게 반영하고 있다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/32-schedule-ui

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app/schedule/create/CreateScheduleClient.tsx`:
- Around line 322-324: The durationMinutes parsing logic has two issues: it
lacks frontend range validation (should be 15-480 per the backend schema) and
uses a silent fallback to 60 minutes when parsing fails, which can submit
unintended values without user awareness. Add explicit range validation in the
validateScheduleForm function to check that the parsed duration falls between 15
and 480 minutes, and remove the `|| 60` fallback from the parsing logic (around
line 322-324 and the consolidated site at 332-333) to throw a validation error
instead of silently defaulting, ensuring users receive immediate feedback before
submission rather than getting a 422 error from the backend.
- Around line 470-482: The responseDeadline field in CreateScheduleClient.tsx
lacks validation logic, allowing users to set deadline times in the past or at
illogical times relative to the candidate date range. Add validation when the
user changes the responseDeadline value (in the onChange handler) or during form
submission to ensure the deadline is a future date-time and falls within a
reasonable window relative to the candidate dates. This validation should check
that responseDeadline is greater than the current time and logically positioned
within the candidate date range so participants have adequate time to respond.
- Around line 432-441: The placeholder text "예: 2시간, 반나절" in the input field
creates a mismatch with the actual parsing logic which only extracts numbers.
Users will expect natural language input to work but will instead get incorrect
durations (e.g., "2시간" becomes 2 minutes instead of 120 minutes). Update the
placeholder attribute in the input element to clearly specify the expected
format as minutes-only numeric input (e.g., "예: 120 (분 단위)"), and consider
adding explanatory text or a helper label near the input field to guide users on
the correct input format and provide examples of valid numeric entries.
- Around line 59-60: The durationMinutes state variable is declared as a string
but semantically represents a number (minutes of duration), causing a
type-meaning mismatch. Either change durationMinutes to use number type by
updating useState to initialize with a number value and adjusting the input
element to type="number", or alternatively, rename the state variable to
durationInput to clarify it represents a user input string. Choose the preferred
approach and ensure the state declaration, input element type, and any related
logic that uses this state are all updated consistently.
- Around line 443-468: Add client-side validation for the candidate date range
defined by candidateStartDate and candidateEndDate. Implement three validations:
(1) ensure candidateEndDate is after candidateStartDate, (2) ensure neither date
is in the past, and (3) verify that the selected date range is consistent with
the day-of-week selections from Step 3 (i.e., at least one of the selected
weekdays must fall within the date range). Add these validations either when
transitioning from Step 1 to Step 2 or during form submission, and display
appropriate error messages to the user when any validation fails. Reference the
state setters for candidateStartDate and candidateEndDate when implementing
these checks.
- Around line 59-63: The date state variables candidateStartDate,
candidateEndDate, and responseDeadline are defined as state hooks but are not
included in the POST request body sent to the server (around lines 330-337),
causing the user-entered date data to be lost. Add these three date fields to
the request payload when creating the schedule. Additionally, ensure the backend
schema file (src/features/schedules/schedule.schema.ts) includes these same
three date fields in the createScheduleSchema so the server accepts and
validates them properly. If these fields are intended to be client-only for
reference purposes, add explicit comments to clarify and update the UI
accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 77abb369-0439-4b21-b2bd-65eec08b1bd1

📥 Commits

Reviewing files that changed from the base of the PR and between 26cf23b and d551aee.

📒 Files selected for processing (2)
  • src/app/page.tsx
  • src/app/schedule/create/CreateScheduleClient.tsx

Comment on lines +59 to +60
const [title, setTitle] = useState("");
const [durationMinutes, setDurationMinutes] = useState("");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚖️ Poor tradeoff

소요시간 상태 타입 불일치 (유지보수성 저하)

durationMinutesstring으로 선언했지만 의미론적으로는 숫자(분 단위 시간)를 나타냄. 이는 코드 가독성을 떨어뜨리고, 향후 유지보수 시 혼란을 야기할 수 있음.

Why: 타입과 의미가 일치하지 않으면 다른 개발자가 코드를 읽을 때 "왜 숫자가 아니라 문자열이지?"라는 의문을 갖게 됨. 또한 숫자 연산 시 매번 파싱이 필요함.

How:

  1. 권장: input을 type="number"로 변경하고 상태를 number로 관리
  2. 대안: 상태는 string 유지하되 이름을 durationInput처럼 변경해 "사용자 입력값"임을 명시
♻️ 타입 일치 리팩터링안 (권장하지만 선택)
-  const [durationMinutes, setDurationMinutes] = useState("");
+  const [durationMinutes, setDurationMinutes] = useState<number>(60);

그리고 input 변경:

                 <input
+                  type="number"
+                  min="15"
+                  max="480"
+                  step="15"
                   value={durationMinutes}
-                  onChange={(event) => setDurationMinutes(event.target.value)}
+                  onChange={(event) => setDurationMinutes(Number(event.target.value))}

그리고 submit 로직 단순화:

-        durationMinutes: String(
-          parseInt(durationMinutes.replace(/[^0-9]/g, "")) || 60,
-        ),
+        durationMinutes: String(durationMinutes),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/schedule/create/CreateScheduleClient.tsx` around lines 59 - 60, The
durationMinutes state variable is declared as a string but semantically
represents a number (minutes of duration), causing a type-meaning mismatch.
Either change durationMinutes to use number type by updating useState to
initialize with a number value and adjusting the input element to type="number",
or alternatively, rename the state variable to durationInput to clarify it
represents a user input string. Choose the preferred approach and ensure the
state declaration, input element type, and any related logic that uses this
state are all updated consistently.

Comment thread src/app/schedule/create/CreateScheduleClient.tsx
Comment thread src/app/schedule/create/CreateScheduleClient.tsx Outdated
Comment thread src/app/schedule/create/CreateScheduleClient.tsx
Comment on lines +443 to +468
<div className="grid grid-cols-2 gap-4">
<label className="grid gap-3 text-sm font-bold text-brand-text-primary">
후보 날짜 범위 (시작)
<input
type="date"
value={candidateStartDate}
onChange={(event) =>
setCandidateStartDate(event.target.value)
}
className="h-12 rounded-xl border border-brand-border-gray px-4 text-base font-normal outline-none focus:border-brand-purple-light focus:ring-2 focus:ring-brand-purple-ring transition-all text-brand-text-primary"
required
/>
</label>
<label className="grid gap-3 text-sm font-bold text-brand-text-primary">
후보 날짜 범위 (종료)
<input
type="date"
value={candidateEndDate}
onChange={(event) =>
setCandidateEndDate(event.target.value)
}
className="h-12 rounded-xl border border-brand-border-gray px-4 text-base font-normal outline-none focus:border-brand-purple-light focus:ring-2 focus:ring-brand-purple-ring transition-all text-brand-text-primary"
required
/>
</label>
</div>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

후보 날짜 범위 검증 로직 누락 (데이터 무결성 위험)

  1. 시작일 < 종료일 검증 없음: 사용자가 종료일을 시작일보다 이전으로 설정해도 막지 않음.
  2. 과거 날짜 검증 없음: 사용자가 과거 날짜를 선택해도 허용됨.
  3. 요일 선택과의 정합성 미검증: 날짜 범위가 월~금요일인데 Step 3에서 토요일만 선택하면 실제 후보 시간이 없는 모순 발생 가능.

Why: 잘못된 날짜 범위는 일정 조율 알고리즘을 무의미하게 만들고, 사용자 혼란을 야기함. 백엔드 검증만으로는 UX가 떨어짐.

How: 클라이언트 측에서 즉시 검증하고 에러 메시지를 표시해야 함.

🔍 날짜 범위 검증 추가안
+              {candidateStartDate && candidateEndDate && candidateStartDate > candidateEndDate && (
+                <p className="text-sm text-destructive font-semibold">
+                  종료일은 시작일보다 늦어야 합니다.
+                </p>
+              )}

그리고 handleSubmit 또는 Step 1→2 전환 시점에 검증:

               <div className="pt-4 flex justify-end">
                 <PurpleButton
                   type="button"
-                  onClick={() => setStep(2)}
+                  onClick={() => {
+                    if (!title.trim()) {
+                      setError("모임 제목을 입력해 주세요.");
+                      return;
+                    }
+                    if (!candidateStartDate || !candidateEndDate) {
+                      setError("후보 날짜 범위를 모두 입력해 주세요.");
+                      return;
+                    }
+                    if (candidateStartDate > candidateEndDate) {
+                      setError("종료일은 시작일보다 늦어야 합니다.");
+                      return;
+                    }
+                    const today = new Date().toISOString().split('T')[0];
+                    if (candidateStartDate < today) {
+                      setError("시작일은 오늘 이후여야 합니다.");
+                      return;
+                    }
+                    setError("");
+                    setStep(2);
+                  }}
                   className="px-6 text-sm font-bold tracking-wide active:scale-95"
                 >
                   다음 단계로 →
                 </PurpleButton>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/schedule/create/CreateScheduleClient.tsx` around lines 443 - 468, Add
client-side validation for the candidate date range defined by
candidateStartDate and candidateEndDate. Implement three validations: (1) ensure
candidateEndDate is after candidateStartDate, (2) ensure neither date is in the
past, and (3) verify that the selected date range is consistent with the
day-of-week selections from Step 3 (i.e., at least one of the selected weekdays
must fall within the date range). Add these validations either when
transitioning from Step 1 to Step 2 or during form submission, and display
appropriate error messages to the user when any validation fails. Reference the
state setters for candidateStartDate and candidateEndDate when implementing
these checks.

Comment thread src/app/schedule/create/CreateScheduleClient.tsx
@yoohyun-1203
yoohyun-1203 merged commit 984b3b7 into dev Jun 14, 2026
2 of 5 checks passed
kokkumong added a commit that referenced this pull request Jun 14, 2026
#71에서 소요시간이 select→자유입력 필드로 바뀌며 기본값이 비어
제출이 막혀 5개 테스트가 4단계에 도달하지 못하던 문제를 해결.
헬퍼에서 "예상 소요시간"을 채운 뒤 단계 진행하도록 수정.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
kokkumong added a commit that referenced this pull request Jun 14, 2026
#71에서 소요시간이 select→자유입력으로 바뀌며 getByLabel("소요 시간")
.selectOption이 타임아웃되던 문제를 "예상 소요시간" 입력으로 수정.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant