feat: 캘린더 기능 구현 - #35
Conversation
📝 WalkthroughWalkthrough캘린더 이벤트 도메인 타입/mock 데이터, 워크스페이스별 캘린더 조회를 위한 Zustand 스토어, 월간 그리드 유틸리티, 일정 표시/추가 UI(CalendarView, CalendarEventChip), 그리고 Changes캘린더 기능
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant CalendarView
participant useCalendarEventsStore
participant CalendarEventChip
User->>CalendarView: 날짜 선택 및 "일정 추가" 클릭
CalendarView->>CalendarView: 모달 오픈, 폼 초기화
User->>CalendarView: 일정 정보 입력 후 제출
CalendarView->>CalendarView: 제목 유효성 검사
CalendarView->>useCalendarEventsStore: addCalendarEvent(workspaceId, event)
useCalendarEventsStore-->>CalendarView: 상태 업데이트
CalendarView->>CalendarEventChip: 이벤트 칩 렌더링
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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/entities/calendar-event/ui/CalendarEventChip.tsx`:
- Around line 4-12: The calendar event chip color mapping is inconsistent with
the color picker values, so selected colors render differently in the chip UI.
Update the `colorClassNames` mapping in `CalendarEventChip` to use the same hex
values as `CalendarView`’s `colorButtonClassNames` and `colorDotClassNames`, and
preferably move these shared color values into a common constant source such as
`calendar-event.types.ts` or a shared constants file. Keep the
`CalendarEventColor` keys aligned so both the modal selection and chip rendering
use the same definitions.
In `@src/features/manage-calendar/model/calendar-utils.ts`:
- Around line 19-36: createCalendarMonthGrid currently hardcodes a 35-cell month
grid, which can truncate the last day for months that need 6 weeks; update the
CalendarDayCell generation in createCalendarMonthGrid to compute the required
cell count dynamically from startDayIndex and the number of days in the month,
and return enough cells to cover the full calendar span. Keep the existing logic
for gridStartDate, isoDate, dayNumber, and isCurrentMonth, but replace the fixed
Array.from length with a calculated value that always includes the last day of
the month.
In `@src/features/manage-calendar/ui/CalendarView.tsx`:
- Line 87: The selectedDate state in CalendarView is not updated when the user
changes months, so actions like add event can target a hidden date. Update the
month navigation handlers in CalendarView (the previous/next month controls) to
also reset selectedDate when currentMonth changes, ideally to the first day of
the newly shown month or today. Reuse or export formatIsoDate from
calendar-utils.ts as needed so the selected date stays in sync with the visible
calendar before triggering the add-event flows from the header and side-panel
buttons.
- Around line 326-359: The form labels in CalendarView are not associated with
their inputs, so update the 일정 이름 and 시간 (선택) fields in CalendarView to use
matching label/input identifiers. Add htmlFor to each label and matching id
attributes to the corresponding input elements in the same form section so
assistive technologies can correctly announce each field’s purpose.
- Around line 35-53: colorButtonClassNames와 colorDotClassNames가 동일한 색상→클래스 매핑을
중복 정의하고 있으니 하나의 공통 맵으로 통합하세요. CalendarView의
colorButtonClassNames/colorDotClassNames 선언을 colorClassNames 같은 단일 상수로 합치고, 해당
상수를 사용하는 모든 렌더링 로직과 참조를 함께 교체해 중복을 제거하세요.
- Around line 308-396: The add-event modal in CalendarView lacks basic
accessibility behavior, so update the modal wrapper to include dialog semantics
such as role="dialog" and aria-modal="true", and make sure the existing close
controls still work. Add Escape-key handling in the CalendarView modal logic so
pressing Escape closes the modal, using the isAddEventOpen / setIsAddEventOpen
flow and the modal container around the form as the main location to wire this
up.
🪄 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: 10ca69c9-3ca9-47c2-bdfc-30e95226657b
📒 Files selected for processing (12)
src/app/workspaces/[workspaceId]/calendar/page.tsxsrc/entities/calendar-event/index.tssrc/entities/calendar-event/model/calendar-event.types.tssrc/entities/calendar-event/model/mock-calendar-events-by-workspace.tssrc/entities/calendar-event/ui/CalendarEventChip.tsxsrc/entities/workspace/model/mock-workspace.tssrc/features/manage-calendar/index.tssrc/features/manage-calendar/model/calendar-utils.tssrc/features/manage-calendar/model/use-calendar-events-store.tssrc/features/manage-calendar/ui/CalendarView.tsxsrc/views/calendar/index.tssrc/views/calendar/ui/CalendarPage.tsx
| const colorClassNames: Record<CalendarEventColor, string> = { | ||
| violet: 'bg-[#6b5cff]', | ||
| purple: 'bg-[#7f5cff]', | ||
| blue: 'bg-[#2f7df6]', | ||
| green: 'bg-[#10b74a]', | ||
| amber: 'bg-[#ff9f0a]', | ||
| coral: 'bg-[#ff6565]', | ||
| pink: 'bg-[#eb2f96]', | ||
| }; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
색상 매핑 불일치: 칩 색상이 선택 UI와 다릅니다.
colorClassNames의 purple(#7f5cff)과 blue(#2f7df6) hex 값이 CalendarView.tsx의 colorButtonClassNames/colorDotClassNames에서 사용하는 값(#8b5cf6, #3b82f6)과 다릅니다. 사용자가 모달에서 색상을 고르면 실제 칩에는 다른 색으로 렌더링됩니다. 색상 상수를 한 곳(예: calendar-event.types.ts 또는 공용 constants 파일)으로 통합하는 것을 권장합니다.
🎨 제안: 공유 색상 상수로 통합
-const colorClassNames: Record<CalendarEventColor, string> = {
- violet: 'bg-[`#6b5cff`]',
- purple: 'bg-[`#7f5cff`]',
- blue: 'bg-[`#2f7df6`]',
- green: 'bg-[`#10b74a`]',
- amber: 'bg-[`#ff9f0a`]',
- coral: 'bg-[`#ff6565`]',
- pink: 'bg-[`#eb2f96`]',
-};
+// CalendarView.tsx의 colorButtonClassNames/colorDotClassNames와 동일한 값 사용
+const colorClassNames: Record<CalendarEventColor, string> = {
+ violet: 'bg-[`#6b5cff`]',
+ purple: 'bg-[`#8b5cf6`]',
+ blue: 'bg-[`#3b82f6`]',
+ green: 'bg-[`#10b74a`]',
+ amber: 'bg-[`#ff9f0a`]',
+ coral: 'bg-[`#ff6565`]',
+ pink: 'bg-[`#eb2f96`]',
+};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const colorClassNames: Record<CalendarEventColor, string> = { | |
| violet: 'bg-[#6b5cff]', | |
| purple: 'bg-[#7f5cff]', | |
| blue: 'bg-[#2f7df6]', | |
| green: 'bg-[#10b74a]', | |
| amber: 'bg-[#ff9f0a]', | |
| coral: 'bg-[#ff6565]', | |
| pink: 'bg-[#eb2f96]', | |
| }; | |
| const colorClassNames: Record<CalendarEventColor, string> = { | |
| violet: 'bg-[`#6b5cff`]', | |
| purple: 'bg-[`#8b5cf6`]', | |
| blue: 'bg-[`#3b82f6`]', | |
| green: 'bg-[`#10b74a`]', | |
| amber: 'bg-[`#ff9f0a`]', | |
| coral: 'bg-[`#ff6565`]', | |
| pink: 'bg-[`#eb2f96`]', | |
| }; |
🤖 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/entities/calendar-event/ui/CalendarEventChip.tsx` around lines 4 - 12,
The calendar event chip color mapping is inconsistent with the color picker
values, so selected colors render differently in the chip UI. Update the
`colorClassNames` mapping in `CalendarEventChip` to use the same hex values as
`CalendarView`’s `colorButtonClassNames` and `colorDotClassNames`, and
preferably move these shared color values into a common constant source such as
`calendar-event.types.ts` or a shared constants file. Keep the
`CalendarEventColor` keys aligned so both the modal selection and chip rendering
use the same definitions.
There was a problem hiding this comment.
CalendarEventColor 색상 매핑이 CalendarView와 CalendarEventChip에 중복 정의되어 있고, purple/blue의 hex 값이 서로 달라 선택 UI와 실제 칩 색상이 다르게 보일 수 있을 것 같습니다.
색상 매핑을 공용 constants로 분리해서 두 컴포넌트가 동일한 값을 참조하도록 통일하면 좋겠습니다!
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
ast-grep outline src/features/manage-calendar/ui/CalendarView.tsx --items all
echo "---"
rg -n "ClassNames|#[0-9a-fA-F]{6}" src/features/manage-calendar/ui/CalendarView.tsx src/entities/calendar-event/ui/CalendarEventChip.tsxLength of output: 5819
🏁 Script executed:
rg -n "colorButtonClassNames\[|colorDotClassNames\[|colorClassNames\[" src/features/manage-calendar/ui/CalendarView.tsx src/entities/calendar-event/ui/CalendarEventChip.tsxLength of output: 721
Confirmed — there are exactly 3 usage sites to update:
src/entities/calendar-event/ui/CalendarEventChip.tsx:23→colorClassNames[event.color]src/features/manage-calendar/ui/CalendarView.tsx:267→colorDotClassNames[calendarEvent.color]src/features/manage-calendar/ui/CalendarView.tsx:369→colorButtonClassNames[color]
The plan already covers all three: replace each with CALENDAR_EVENT_COLOR_CLASS_NAMES[...] after importing the new shared constant from the entities/calendar-event layer (respecting the FSD feature → entity import direction). No other usages were found, so the migration is contained to these two files plus the new constants file and barrel export.
✏️ Learnings added
Learnt from: seongjinss555
Repo: TeampleRun/syncly PR: 35
File: src/entities/calendar-event/ui/CalendarEventChip.tsx:4-12
Timestamp: 2026-07-09T07:24:49.606Z
Learning: In `syncly` repo (Next.js/TypeScript, FSD architecture), calendar event color-to-Tailwind-class mappings previously existed duplicated in `src/entities/calendar-event/ui/CalendarEventChip.tsx` (as `colorClassNames`) and `src/features/manage-calendar/ui/CalendarView.tsx` (as `colorButtonClassNames` and `colorDotClassNames`), with mismatched hex values for `purple`/`blue`. Prefer defining shared `CalendarEventColor` class-name constants once in the `entities/calendar-event` layer (e.g. `calendar-event-colors.ts`) and importing them from `features/manage-calendar` to keep chip, button, and dot colors consistent, per FSD import direction (`feature → entity`).
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
There was a problem hiding this comment.
칩, 색상 선택 버튼, 오른쪽 패널 점 표시가 각각 다른 hex 값을 보던 상태여서 색상 매핑을 calendar-event-colors.ts로 공통화했습니다.
이제 CalendarEventChip, CalendarView 모두 동일한 색상 상수를 사용합니다.
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
| export function createCalendarMonthGrid(currentMonth: Date): CalendarDayCell[] { | ||
| const year = currentMonth.getFullYear(); | ||
| const monthIndex = currentMonth.getMonth(); | ||
| const firstDayOfMonth = new Date(year, monthIndex, 1); | ||
| const startDayIndex = firstDayOfMonth.getDay(); | ||
| const gridStartDate = new Date(year, monthIndex, 1 - startDayIndex); | ||
|
|
||
| return Array.from({ length: 35 }, (_, index) => { | ||
| const date = new Date(gridStartDate); | ||
| date.setDate(gridStartDate.getDate() + index); | ||
|
|
||
| return { | ||
| isoDate: formatIsoDate(date), | ||
| dayNumber: date.getDate(), | ||
| isCurrentMonth: date.getMonth() === monthIndex, | ||
| }; | ||
| }); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
월별 셀 개수를 35개로 고정하면 일부 월의 마지막 날짜가 그리드에서 잘립니다.
startDayIndex(월 시작 요일)와 daysInMonth(해당 월 일수) 조합에 따라 35개 셀(5주)로는 월 전체를 표현할 수 없는 경우가 있습니다. 예를 들어 2025년 8월은 금요일(startDayIndex=5)에 시작하고 31일이므로, 8월 31일이 인덱스 35에 위치하게 되어 배열(0~34) 밖으로 밀려나 렌더링되지 않습니다. 31일짜리 월이 금/토에 시작하거나 30일짜리 월이 토요일에 시작하는 모든 경우에 동일한 문제가 발생합니다.
🐛 셀 개수를 동적으로 계산하는 수정안
export function createCalendarMonthGrid(currentMonth: Date): CalendarDayCell[] {
const year = currentMonth.getFullYear();
const monthIndex = currentMonth.getMonth();
const firstDayOfMonth = new Date(year, monthIndex, 1);
const startDayIndex = firstDayOfMonth.getDay();
const gridStartDate = new Date(year, monthIndex, 1 - startDayIndex);
+ const daysInMonth = new Date(year, monthIndex + 1, 0).getDate();
+ const totalCells = Math.ceil((startDayIndex + daysInMonth) / 7) * 7;
- return Array.from({ length: 35 }, (_, index) => {
+ return Array.from({ length: totalCells }, (_, index) => {
const date = new Date(gridStartDate);
date.setDate(gridStartDate.getDate() + index);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export function createCalendarMonthGrid(currentMonth: Date): CalendarDayCell[] { | |
| const year = currentMonth.getFullYear(); | |
| const monthIndex = currentMonth.getMonth(); | |
| const firstDayOfMonth = new Date(year, monthIndex, 1); | |
| const startDayIndex = firstDayOfMonth.getDay(); | |
| const gridStartDate = new Date(year, monthIndex, 1 - startDayIndex); | |
| return Array.from({ length: 35 }, (_, index) => { | |
| const date = new Date(gridStartDate); | |
| date.setDate(gridStartDate.getDate() + index); | |
| return { | |
| isoDate: formatIsoDate(date), | |
| dayNumber: date.getDate(), | |
| isCurrentMonth: date.getMonth() === monthIndex, | |
| }; | |
| }); | |
| } | |
| export function createCalendarMonthGrid(currentMonth: Date): CalendarDayCell[] { | |
| const year = currentMonth.getFullYear(); | |
| const monthIndex = currentMonth.getMonth(); | |
| const firstDayOfMonth = new Date(year, monthIndex, 1); | |
| const startDayIndex = firstDayOfMonth.getDay(); | |
| const gridStartDate = new Date(year, monthIndex, 1 - startDayIndex); | |
| const daysInMonth = new Date(year, monthIndex + 1, 0).getDate(); | |
| const totalCells = Math.ceil((startDayIndex + daysInMonth) / 7) * 7; | |
| return Array.from({ length: totalCells }, (_, index) => { | |
| const date = new Date(gridStartDate); | |
| date.setDate(gridStartDate.getDate() + index); | |
| return { | |
| isoDate: formatIsoDate(date), | |
| dayNumber: date.getDate(), | |
| isCurrentMonth: date.getMonth() === monthIndex, | |
| }; | |
| }); | |
| } |
🤖 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/features/manage-calendar/model/calendar-utils.ts` around lines 19 - 36,
createCalendarMonthGrid currently hardcodes a 35-cell month grid, which can
truncate the last day for months that need 6 weeks; update the CalendarDayCell
generation in createCalendarMonthGrid to compute the required cell count
dynamically from startDayIndex and the number of days in the month, and return
enough cells to cover the full calendar span. Keep the existing logic for
gridStartDate, isoDate, dayNumber, and isCurrentMonth, but replace the fixed
Array.from length with a calculated value that always includes the last day of
the month.
There was a problem hiding this comment.
혹시 모를 상황에 대비하여 동적으로 관리하는 것으로 수정하면 좋을 거 같습니다~
There was a problem hiding this comment.
The PR description image (Image 1) shows the Syncly calendar page for "2025년 7월" with a monthly grid (일~토), colored event chips in various day cells, and a right-side detail panel for "2025년 7월 30일" showing an empty-state message ("등록된 일정이 없어요").
The PR description image (Image 2) shows the same calendar with a modal overlay titled "2025년 7월 30일 일정 추가", containing fields for 일정 이름, 시간 (선택), and 색상 (color picker dots), with 취소/추가 buttons at the bottom.
@seongjinss555 네, 동의합니다! 말씀하신 대로 월 시작 요일과 해당 월의 일수에 따라 필요한 셀 개수를 동적으로 계산하는 방식이 더 안전합니다. 위에서 제안한 diff처럼 daysInMonth와 totalCells를 계산해서 Array.from({ length: totalCells }, ...)로 바꾸시면 5주(35칸)로 부족한 달(예: 2025년 8월처럼 금요일 시작 + 31일)도 문제없이 렌더링됩니다. 반영해주시면 확인하겠습니다 🙂
There was a problem hiding this comment.
월 시작 요일과 말일 조합에 따라 5주(35칸)로는 월 전체를 표현할 수 없는 경우가 있어서, 그리드 셀 수를 동적으로 계산하도록 수정했습니다.
이제 startDayIndex + daysInMonth > 35인 경우에는 42칸(6주)으로 렌더링되고, 그 외 월은 기존처럼 35칸을 유지합니다.
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
| const colorButtonClassNames: Record<CalendarEventColor, string> = { | ||
| violet: 'bg-[#6b5cff]', | ||
| purple: 'bg-[#8b5cf6]', | ||
| blue: 'bg-[#3b82f6]', | ||
| green: 'bg-[#10b74a]', | ||
| amber: 'bg-[#ff9f0a]', | ||
| coral: 'bg-[#ff6565]', | ||
| pink: 'bg-[#eb2f96]', | ||
| }; | ||
|
|
||
| const colorDotClassNames: Record<CalendarEventColor, string> = { | ||
| violet: 'bg-[#6b5cff]', | ||
| purple: 'bg-[#8b5cf6]', | ||
| blue: 'bg-[#3b82f6]', | ||
| green: 'bg-[#10b74a]', | ||
| amber: 'bg-[#ff9f0a]', | ||
| coral: 'bg-[#ff6565]', | ||
| pink: 'bg-[#eb2f96]', | ||
| }; |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
colorButtonClassNames와 colorDotClassNames가 완전히 중복됩니다.
두 객체가 동일한 색상→클래스 매핑을 갖고 있습니다. 하나로 통합해 재사용하세요.
♻️ 중복 제거 제안
-const colorButtonClassNames: Record<CalendarEventColor, string> = {
- violet: 'bg-[`#6b5cff`]',
- purple: 'bg-[`#8b5cf6`]',
- blue: 'bg-[`#3b82f6`]',
- green: 'bg-[`#10b74a`]',
- amber: 'bg-[`#ff9f0a`]',
- coral: 'bg-[`#ff6565`]',
- pink: 'bg-[`#eb2f96`]',
-};
-
-const colorDotClassNames: Record<CalendarEventColor, string> = {
- violet: 'bg-[`#6b5cff`]',
- purple: 'bg-[`#8b5cf6`]',
- blue: 'bg-[`#3b82f6`]',
- green: 'bg-[`#10b74a`]',
- amber: 'bg-[`#ff9f0a`]',
- coral: 'bg-[`#ff6565`]',
- pink: 'bg-[`#eb2f96`]',
-};
+const colorClassNames: Record<CalendarEventColor, string> = {
+ violet: 'bg-[`#6b5cff`]',
+ purple: 'bg-[`#8b5cf6`]',
+ blue: 'bg-[`#3b82f6`]',
+ green: 'bg-[`#10b74a`]',
+ amber: 'bg-[`#ff9f0a`]',
+ coral: 'bg-[`#ff6565`]',
+ pink: 'bg-[`#eb2f96`]',
+};이후 colorButtonClassNames/colorDotClassNames 사용처를 colorClassNames로 교체하세요.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const colorButtonClassNames: Record<CalendarEventColor, string> = { | |
| violet: 'bg-[#6b5cff]', | |
| purple: 'bg-[#8b5cf6]', | |
| blue: 'bg-[#3b82f6]', | |
| green: 'bg-[#10b74a]', | |
| amber: 'bg-[#ff9f0a]', | |
| coral: 'bg-[#ff6565]', | |
| pink: 'bg-[#eb2f96]', | |
| }; | |
| const colorDotClassNames: Record<CalendarEventColor, string> = { | |
| violet: 'bg-[#6b5cff]', | |
| purple: 'bg-[#8b5cf6]', | |
| blue: 'bg-[#3b82f6]', | |
| green: 'bg-[#10b74a]', | |
| amber: 'bg-[#ff9f0a]', | |
| coral: 'bg-[#ff6565]', | |
| pink: 'bg-[#eb2f96]', | |
| }; | |
| const colorClassNames: Record<CalendarEventColor, string> = { | |
| violet: 'bg-[`#6b5cff`]', | |
| purple: 'bg-[`#8b5cf6`]', | |
| blue: 'bg-[`#3b82f6`]', | |
| green: 'bg-[`#10b74a`]', | |
| amber: 'bg-[`#ff9f0a`]', | |
| coral: 'bg-[`#ff6565`]', | |
| pink: 'bg-[`#eb2f96`]', | |
| }; |
🤖 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/features/manage-calendar/ui/CalendarView.tsx` around lines 35 - 53,
colorButtonClassNames와 colorDotClassNames가 동일한 색상→클래스 매핑을 중복 정의하고 있으니 하나의 공통 맵으로
통합하세요. CalendarView의 colorButtonClassNames/colorDotClassNames 선언을
colorClassNames 같은 단일 상수로 합치고, 해당 상수를 사용하는 모든 렌더링 로직과 참조를 함께 교체해 중복을 제거하세요.
There was a problem hiding this comment.
하나로 통합하여 관리하는 것이 좋을 거 같습니다. 확인해주세요~
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
fd CalendarView.tsx src/features/manage-calendar
rg -n 'colorButtonClassNames|colorDotClassNames' src/features/manage-calendar/ui/CalendarView.tsx -C2Length of output: 1313
@seongjinss555, 확인했습니다. 두 상수(colorButtonClassNames, colorDotClassNames)의 값이 완전히 동일하므로 하나로 통합해도 무방합니다. 아래와 같이 정리하면 됩니다.
-const colorButtonClassNames: Record<CalendarEventColor, string> = {
- violet: 'bg-[`#6b5cff`]',
- purple: 'bg-[`#8b5cf6`]',
- blue: 'bg-[`#3b82f6`]',
- green: 'bg-[`#10b74a`]',
- amber: 'bg-[`#ff9f0a`]',
- coral: 'bg-[`#ff6565`]',
- pink: 'bg-[`#eb2f96`]',
-};
-
-const colorDotClassNames: Record<CalendarEventColor, string> = {
- violet: 'bg-[`#6b5cff`]',
- purple: 'bg-[`#8b5cf6`]',
- blue: 'bg-[`#3b82f6`]',
- green: 'bg-[`#10b74a`]',
- amber: 'bg-[`#ff9f0a`]',
- coral: 'bg-[`#ff6565`]',
- pink: 'bg-[`#eb2f96`]',
-};
+const colorClassNames: Record<CalendarEventColor, string> = {
+ violet: 'bg-[`#6b5cff`]',
+ purple: 'bg-[`#8b5cf6`]',
+ blue: 'bg-[`#3b82f6`]',
+ green: 'bg-[`#10b74a`]',
+ amber: 'bg-[`#ff9f0a`]',
+ coral: 'bg-[`#ff6565`]',
+ pink: 'bg-[`#eb2f96`]',
+};그리고 사용처 2곳을 아래처럼 교체하면 됩니다.
Line 267 (날짜 상세 패널의 색상 점):
- className={`mt-1 size-2.5 shrink-0 rounded-full ${colorDotClassNames[calendarEvent.color]}`}
+ className={`mt-1 size-2.5 shrink-0 rounded-full ${colorClassNames[calendarEvent.color]}`}Line 369 (모달의 색상 선택 버튼):
- className={`size-6 rounded-full ${colorButtonClassNames[color]} ${
+ className={`size-6 rounded-full ${colorClassNames[color]} ${이렇게 하면 중복 없이 하나의 매핑으로 버튼과 점 색상을 모두 관리할 수 있습니다.
There was a problem hiding this comment.
기존의 colorButtonClassNames, colorDotClassNames 중복 매핑은 제거했고, 현재는 calendarEventColorClassNames 공용 상수를 만들어 색상 선택 버튼, 일정 칩, 오른쪽 패널 점 표시가 동일한 매핑을 재사용하고 있습니다.
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
|
|
||
| const calendarEvents = storedEvents ?? initialEvents; | ||
| const [currentMonth, setCurrentMonth] = useState(getInitialCalendarDate); | ||
| const [selectedDate, setSelectedDate] = useState('2025-07-30'); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
달 이동 시 selectedDate가 갱신되지 않아, 보이지 않는 날짜에 일정이 추가될 수 있습니다.
이전 달/다음 달 버튼(141-166)은 currentMonth만 변경하고 selectedDate(87)는 그대로 유지됩니다. 이 상태에서 상단 "일정 추가"(168-176)나 우측 패널의 "+"(247-254) 버튼을 누르면, 현재 화면에 보이지 않는 이전 달의 selectedDate에 일정이 추가됩니다. 모달 제목에는 정확한 날짜가 표시되지만 사용자가 달을 이동한 사실을 잊으면 의도치 않은 날짜에 일정이 쌓일 수 있습니다.
달 이동 시 selectedDate를 새 달의 첫날(또는 오늘)로 리셋하는 것을 권장합니다.
🐛 수정 제안
<button
type="button"
onClick={() =>
- setCurrentMonth(
- (current) => new Date(current.getFullYear(), current.getMonth() - 1, 1),
- )
+ setCurrentMonth((current) => {
+ const next = new Date(current.getFullYear(), current.getMonth() - 1, 1);
+ setSelectedDate(formatIsoDate(next));
+ return next;
+ })
}(next 달 버튼에도 동일하게 적용, formatIsoDate는 calendar-utils.ts에서 export 필요)
Also applies to: 141-166, 168-176, 247-254
🤖 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/features/manage-calendar/ui/CalendarView.tsx` at line 87, The
selectedDate state in CalendarView is not updated when the user changes months,
so actions like add event can target a hidden date. Update the month navigation
handlers in CalendarView (the previous/next month controls) to also reset
selectedDate when currentMonth changes, ideally to the first day of the newly
shown month or today. Reuse or export formatIsoDate from calendar-utils.ts as
needed so the selected date stays in sync with the visible calendar before
triggering the add-event flows from the header and side-panel buttons.
There was a problem hiding this comment.
currentMonth와 selectedDate가 분리되어 있어서 달 이동 후 일정 추가 대상 날짜가 현재 화면의 달과 달라질 수 있을 것 같습니다.
사용자가 현재 보고 있는 달 기준으로 일정을 추가한다고 기대할 가능성이 있으니, 이전/다음 달 이동 시 selectedDate도 새 달의 첫날로 갱신하거나, 현재 선택 날짜가 화면에 보이지 않을 때는 일정 추가 버튼의 기준 날짜를 명확히 처리하는 방식이 필요해 보입니다!
There was a problem hiding this comment.
@seongjinss555 말씀하신 방향에 동의합니다. 두 가지 방법 중 하나로 정리하면 될 것 같습니다.
방법 A: 달 이동 시 selectedDate를 새 달 첫날로 갱신 (더 단순)
<button
type="button"
onClick={() =>
- setCurrentMonth(
- (current) => new Date(current.getFullYear(), current.getMonth() - 1, 1),
- )
+ setCurrentMonth((current) => {
+ const next = new Date(current.getFullYear(), current.getMonth() - 1, 1);
+ setSelectedDate(formatIsoDate(next));
+ return next;
+ })
}
>다음 달 버튼에도 동일하게 적용하고, formatIsoDate를 calendar-utils.ts에서 export로 변경하면 됩니다.
방법 B: selectedDate는 유지하되, 화면에 보이는 달과 다를 경우 "일정 추가" 진입 시 기준 날짜를 명확히 처리
- 예:
openAddEventModal호출 시selectedDate가currentMonth에 속하지 않으면, 모달 열기 전에currentMonth의 1일(혹은 오늘)로 대체. - 이 방식은 "달만 이동하고 선택 날짜는 유지"하려는 의도가 있을 때 더 안전하지만, 로직이 두 곳(헤더 버튼, 사이드 패널 + 버튼)에 중복될 수 있으니 공통 헬퍼로 뽑는 게 좋겠습니다.
개인적으로는 방법 A가 사용자가 보는 화면과 실제 저장되는 날짜가 항상 일치해서 혼란이 적을 것 같습니다. 다만 "달 이동해도 선택했던 날짜를 유지하고 싶다"는 UX 의도가 있다면 방법 B가 맞을 수 있습니다. 어느 쪽으로 반영하실지 알려주시면 반영 방향에 맞춰 추가로 도와드릴게요.
There was a problem hiding this comment.
이전/다음 달 이동 시 currentMonth만 변경되고 selectedDate가 유지되던 상태여서, 보이지 않는 이전 선택 날짜에 일정이 추가될 수 있었습니다.
달 이동 로직을 changeMonth로 분리하고, 이동한 달의 1일로 selectedDate도 함께 갱신하도록 수정했습니다.
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
seongjinss555
left a comment
There was a problem hiding this comment.
리뷰 참고하시면 좋을 거 같습니다~ 고생하셨습니다~!
| const colorClassNames: Record<CalendarEventColor, string> = { | ||
| violet: 'bg-[#6b5cff]', | ||
| purple: 'bg-[#7f5cff]', | ||
| blue: 'bg-[#2f7df6]', | ||
| green: 'bg-[#10b74a]', | ||
| amber: 'bg-[#ff9f0a]', | ||
| coral: 'bg-[#ff6565]', | ||
| pink: 'bg-[#eb2f96]', | ||
| }; |
There was a problem hiding this comment.
CalendarEventColor 색상 매핑이 CalendarView와 CalendarEventChip에 중복 정의되어 있고, purple/blue의 hex 값이 서로 달라 선택 UI와 실제 칩 색상이 다르게 보일 수 있을 것 같습니다.
색상 매핑을 공용 constants로 분리해서 두 컴포넌트가 동일한 값을 참조하도록 통일하면 좋겠습니다!
|
|
||
| const calendarEvents = storedEvents ?? initialEvents; | ||
| const [currentMonth, setCurrentMonth] = useState(getInitialCalendarDate); | ||
| const [selectedDate, setSelectedDate] = useState('2025-07-30'); |
There was a problem hiding this comment.
currentMonth와 selectedDate가 분리되어 있어서 달 이동 후 일정 추가 대상 날짜가 현재 화면의 달과 달라질 수 있을 것 같습니다.
사용자가 현재 보고 있는 달 기준으로 일정을 추가한다고 기대할 가능성이 있으니, 이전/다음 달 이동 시 selectedDate도 새 달의 첫날로 갱신하거나, 현재 선택 날짜가 화면에 보이지 않을 때는 일정 추가 버튼의 기준 날짜를 명확히 처리하는 방식이 필요해 보입니다!
📝 작업 내용
entity / feature / view분리/workspaces/test/calendar진입을 위한testworkspace mock 추가📌 주요 변경 사항
src/app/workspaces/[workspaceId]/calendar/page.tsxsrc/views/calendarsrc/features/manage-calendarsrc/entities/calendar-eventsrc/entities/workspace/model/mock-workspace.tstestworkspace mock 추가✅ 확인 사항
/workspaces/test/calendar경로에서 캘린더 화면 진입 가능🧪 테스트
npm run lintnpm run typechecknpm run build📷 스크린샷
캘린더 메인 화면
일정 추가 모달
🔗 관련 이슈
Summary by CodeRabbit
New Features
Bug Fixes