[FEAT] 홈 화면 7일 뷰 퍼블리싱 및 투두 드래그 정렬/타이머 연동 구현#124
Conversation
useSearchParams 등 클라이언트 훅 사용 시 필요한 Suspense 경계와, 향후 비동기 데이터 페칭 시 필요한 에러 처리를 공통 AsyncBoundary 컴포넌트로 추가했습니다.
- 고정 min-width를 제거하고 부모 폭에 맞춰 유동적으로 늘어나거나 줄어들도록 했습니다 - default와 폭 차이가 유일한 구분점이던 weekly variant를 제거했습니다 - 텍스트 span을 항상 truncate 가능하도록 통일했습니다
- 필터(DEFAULT/WEEK)·기준일 기반 home-view mock 데이터 레이어를 구성했습니다 - 헤더의 뷰 전환(기본/7일)을 실제 데이터 조회 및 오늘로 스크롤 이동과 연결했습니다 - 7일 뷰에서 날짜 컬럼과 투두 카드가 남은 공간을 유동적으로 나눠 갖도록 하고, 최소 150px 폭을 보장하며 부족하면 가로 스크롤되도록 했습니다 - priority/요일 i18n 메시지 키를 API enum 값(대문자)과 통일해 중복된 라벨 매핑 유틸을 제거했습니다
…to feat/web/121-home-view-publishing # Conflicts: # apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx
- 투두 순서 변경을 위해 dnd-kit 패키지를 추가했습니다 - 타이머 사이드바 전역 상태 관리를 위해 zustand 패키지를 추가했습니다
- 투두 카드를 드래그로 순서 변경할 수 있는 기능을 추가했습니다 - 헤더/투두 상태 로직을 HomeDayHeaderContainer, useHomeTodosByDate로 분리했습니다 - 태그 이름을 i18n 키 기반으로 매핑하도록 변경했습니다
- 토스트 컨테이너를 home/_containers/toast/ 하위로 이동했습니다 - QueryProvider를 providers/query/ 하위로 이동했습니다
- date, day-of-week, home-view, todo-time 유틸 함수에 동작 설명을 추가했습니다
- 카드가 부모 컨테이너의 높이를 강제로 채우면서 여러 개일 때 서로 겹치던 문제를 수정했습니다 - 카드 높이를 콘텐츠 크기에 맞게 자연스럽게 계산되도록 변경했습니다
- 타이머 사이드바 열림/탭 상태를 zustand 전역 스토어로 옮겨 깊은 트리와 공유했습니다 - 투두 카드의 재생 버튼을 눌러 타이머가 시작되면 사이드바가 열리고 Timer 탭으로 전환되도록 연동했습니다
…view-publishing # Conflicts: # apps/timo-web/components/boundary/AsyncBoundary.tsx # apps/timo-web/components/boundary/ErrorBoundary.tsx
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Timo Performance ReportBundle Size — timo-web
Lighthouse — timo-web
Image Optimization — timo-web
측정 커밋: |
|
Caution Review failedAn error occurred during the review process. Please try again later. 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. Comment |
📝 WalkthroughWalkthrough홈 화면에 일간(15일 스크롤)/주간(7일) 뷰와 드래그 앤 드롭 투두 재정렬 기능이 추가되었다. 관련하여 홈 뷰/Todo 타입이 Zod 스키마 기반으로 전환되고, mock 데이터/날짜 유틸/신규 훅이 추가되었다. 별도로 타임 사이드바 상태가 Zustand 스토어로 전환되고, 디자인 시스템 Changes홈 화면 일간/주간 뷰 및 정렬 기능
타임 사이드바 상태의 Zustand 전환
AddTaskButton weekly variant 제거
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant HomeHeaderContainer
participant useHomeViewMode
participant HomeTodoContainer
participant useHomeTodosByDate
participant DndSortableListProvider
HomeHeaderContainer->>useHomeViewMode: setViewMode(basic/week)
useHomeViewMode-->>HomeTodoContainer: isWeekView, referenceDate
HomeTodoContainer->>useHomeTodosByDate: apiDays 전달
useHomeTodosByDate-->>HomeTodoContainer: todosByDate, handleReorderTodo
DndSortableListProvider->>useHomeTodosByDate: handleReorderTodo(fromIndex, toIndex)
useHomeTodosByDate->>useHomeTodosByDate: reorderTodos 적용 후 patchTodoOrderMock 호출, 실패 시 롤백
sequenceDiagram
participant WithTimeSidebarContainer
participant useTimeSidebarStore
participant TimeSidebar
WithTimeSidebarContainer->>useTimeSidebarStore: isOpen 구독
TimeSidebar->>useTimeSidebarStore: toggleOpen() 호출
useTimeSidebarStore-->>WithTimeSidebarContainer: isOpen 갱신
useTimeSidebarStore-->>TimeSidebar: activeTab 갱신
Possibly related PRs
Suggested labels: Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (4)
apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_types/home-view-type.ts (1)
18-18: 🗄️ Data Integrity & Integration | 🔵 Trivial | 💤 Low value
date필드에 날짜 형식 검증 추가를 권장합니다.
homeViewDaySchema의date필드가z.string()으로 정의되어 있어"yyyy-MM-dd"형식을 보장하지 않습니다. 현재 mock 단계에서는 문제가 없으나, 실제 API 연동 시 잘못된 형식의 날짜가 들어올 수 있습니다.z.iso.date()또는 정규식 패턴 검증을 추가하는 것을 권장합니다.♻️ 제안: 날짜 형식 검증 추가
export const homeViewDaySchema = z.object({ - date: z.string(), + date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "date must be yyyy-MM-dd format"), dayOfWeek: apiDayOfWeekSchema,🤖 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 `@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_types/home-view-type.ts at line 18, The homeViewDaySchema in home-view-type.ts currently uses z.string() for date, so it does not enforce the expected yyyy-MM-dd format. Update the date field validation in homeViewDaySchema to use a date-specific check such as z.iso.date() or an equivalent regex-based refinement, while keeping the existing schema shape intact for the home view types.apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_mocks/home-view-mock.ts (1)
36-48: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value
getToday()호출을 반복문 밖으로 이동하는 것을 권장합니다.
dates.map콜백 내에서getToday()가 매 반복마다 호출됩니다. 자정 직후 실행 시 반복 중 날짜가 넘어가는 극단적 엣지 케이스에서isToday판정이 일관되지 않을 수 있습니다.getToday()를 반복문 밖에서 한 번만 호출하여 재사용하는 것이 더 안전합니다.♻️ 제안: getToday()를 반복문 밖으로 이동
+ const today = getToday(); + const days: HomeViewDay[] = dates.map((date) => { const todos = getTodoMocksByDate(date); return { date: formatDateKey(date), dayOfWeek: getApiDayOfWeek(date), isHoliday: false, - isToday: isSameDate(date, getToday()), + isToday: isSameDate(date, today), totalCount: todos.length, completedCount: todos.filter((todo) => todo.completed).length, todos, }; });🤖 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 `@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_mocks/home-view-mock.ts around lines 36 - 48, The `dates.map` callback in `home-view-mock.ts` calls `getToday()` for every item, so move that call outside the loop in the `HomeViewDay` निर्माण logic and reuse a single captured “today” value when computing `isToday`. Keep the rest of the mapping unchanged, and update the `isToday` check to compare each `date` against the shared value rather than calling `getToday()` repeatedly.apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_utils/day-of-week.ts (1)
10-11: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
as ApiDayOfWeek타입 단언 대신 타입 안전성을 강화하는 것을 권장합니다.
getDayOfWeekKey(date)의 반환 타입이ApiDayOfWeek와 일치하도록getDayOfWeekKey자체의 반환 타입을 조정하거나, 런타임 검증을 추가하는 것이 더 안전합니다. 현재as단언은getDayOfWeekKey가 예상과 다른 값을 반환할 경우 타입 오류를 발생시키지 않습니다.♻️ 제안: 타입 단언 제거 방안
- export const getApiDayOfWeek = (date: Date): ApiDayOfWeek => - getDayOfWeekKey(date) as ApiDayOfWeek; + // getDayOfWeekKey의 반환 타입을 ApiDayOfWeek와 일치시키거나 + // apiDayOfWeekSchema로 런타임 파싱 추가 + export const getApiDayOfWeek = (date: Date): ApiDayOfWeek => + apiDayOfWeekSchema.parse(getDayOfWeekKey(date));🤖 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 `@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_utils/day-of-week.ts around lines 10 - 11, The `getApiDayOfWeek` helper is relying on an unsafe `as ApiDayOfWeek` cast, so update `getDayOfWeekKey` or `getApiDayOfWeek` to make the return type type-safe instead of asserting it. Prefer aligning `getDayOfWeekKey`’s return type with `ApiDayOfWeek`, or add a runtime check in `getApiDayOfWeek` before returning the value, so the conversion is validated without a blind cast.apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_components/HomeTodoCard.tsx (1)
76-80: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value완료된 todo 카드의
touchAction: "none"불필요 적용 및 전체 카드 드래그 핸들.
useSortable({ disabled: isCompleted })로 완료된 todo는 드래그가 비활성화되지만,sortableStyle의touchAction: "none"은 항상 적용됩니다. 완료된 카드에서는 불필요하게 터치 스크롤이 차단됩니다. 또한{...listeners}가 전체<article>에 spread되어 있어 터치 환경에서 카드 영역 세로 스크롤이 어려울 수 있습니다.♻️ 제안: disabled 시 touchAction 조건부 적용
const sortableStyle = { transform: CSS.Transform.toString(transform), transition, - touchAction: "none", + ...(isCompleted ? {} : { touchAction: "none" }), };Also applies to: 122-125
🤖 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 `@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_components/HomeTodoCard.tsx around lines 76 - 80, In HomeTodoCard’s sortable styling and drag setup, `touchAction: "none"` is being applied even when `useSortable({ disabled: isCompleted })` disables dragging, and `{...listeners}` on the full `<article>` makes the whole card act like a drag handle. Update `sortableStyle` so `touchAction` is applied conditionally only when dragging is enabled, and move the drag listeners to a dedicated handle area instead of the entire card so completed cards and touch scrolling behave normally.
🤖 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.
Nitpick comments:
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_components/HomeTodoCard.tsx:
- Around line 76-80: In HomeTodoCard’s sortable styling and drag setup,
`touchAction: "none"` is being applied even when `useSortable({ disabled:
isCompleted })` disables dragging, and `{...listeners}` on the full `<article>`
makes the whole card act like a drag handle. Update `sortableStyle` so
`touchAction` is applied conditionally only when dragging is enabled, and move
the drag listeners to a dedicated handle area instead of the entire card so
completed cards and touch scrolling behave normally.
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_mocks/home-view-mock.ts:
- Around line 36-48: The `dates.map` callback in `home-view-mock.ts` calls
`getToday()` for every item, so move that call outside the loop in the
`HomeViewDay` निर्माण logic and reuse a single captured “today” value when
computing `isToday`. Keep the rest of the mapping unchanged, and update the
`isToday` check to compare each `date` against the shared value rather than
calling `getToday()` repeatedly.
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_types/home-view-type.ts:
- Line 18: The homeViewDaySchema in home-view-type.ts currently uses z.string()
for date, so it does not enforce the expected yyyy-MM-dd format. Update the date
field validation in homeViewDaySchema to use a date-specific check such as
z.iso.date() or an equivalent regex-based refinement, while keeping the existing
schema shape intact for the home view types.
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_utils/day-of-week.ts:
- Around line 10-11: The `getApiDayOfWeek` helper is relying on an unsafe `as
ApiDayOfWeek` cast, so update `getDayOfWeekKey` or `getApiDayOfWeek` to make the
return type type-safe instead of asserting it. Prefer aligning
`getDayOfWeekKey`’s return type with `ApiDayOfWeek`, or add a runtime check in
`getApiDayOfWeek` before returning the value, so the conversion is validated
without a blind cast.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: d213e673-54b6-4770-b92c-de4fcae56de0
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (33)
apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/_containers/WithTimeSidebarContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_components/HomeTodoCard.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeDayHeaderContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeHeaderContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/toast/TagLimitToastContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/toast/TodoLimitToastContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/useHomeTodayScroll.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/useHomeTodosByDate.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/useHomeViewMode.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_mocks/home-view-mock.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_mocks/todo-mock.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_mocks/todo-order-mock.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_types/home-view-type.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_types/todo-type.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_utils/date.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_utils/day-of-week.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_utils/home-view.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_utils/todo-order.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_utils/todo-time.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/page.tsxapps/timo-web/app/[locale]/layout.tsxapps/timo-web/components/layout/sidebar/time/TimeSidebar.tsxapps/timo-web/messages/en.jsonapps/timo-web/messages/ko.jsonapps/timo-web/package.jsonapps/timo-web/providers/dnd/DndSortableListProvider.tsxapps/timo-web/providers/query/QueryProvider.tsxapps/timo-web/stores/.gitkeepapps/timo-web/stores/time-sidebar/useTimeSidebarStore.tsapps/timo-web/utils/get-day-of-week-key.tspackages/timo-design-system/src/components/button/add-task-button/AddTaskButton.stories.tsxpackages/timo-design-system/src/components/button/add-task-button/AddTaskButton.tsx
jjangminii
left a comment
There was a problem hiding this comment.
handleReorderTodo에서 드롭 즉시 로컬 상태를 업데이트하고 API 실패 시 이전 상태로 롤백하는 낙관적 업데이트 패턴이 깔끔하게 잘 구현해주셨네요 👍
DndSortableListProvider로 dnd-kit 설정을 분리해서 HomeTodoContainer가 드래그 세부사항을 몰라도 되는 구조도 좋아요-! 나중에 다른 도메인에서도 재사용하기 좋을 것 같아요.
투두 카드에서 타임 사이드바를 열어야 하는데 두 컴포넌트가 완전히 다른 트리에 있어서 props로 넘길 방법이 없는 상황이라 Zustand 도입 판단도 적절한 것 같아요! 제가 전역상태관리는 처음이라 열심히 공부해볼게요..
코멘트만 확인해주세요-! 고생하셨습니다~
| <article | ||
| ref={setNodeRef} | ||
| style={sortableStyle} | ||
| {...attributes} | ||
| {...listeners} | ||
| className={cn( | ||
| "border-timo-gray-500 flex size-full flex-col items-start gap-2 overflow-hidden rounded-[4px] border border-solid px-3.5 py-3", | ||
| "border-timo-gray-500 flex w-full shrink-0 flex-col items-start gap-2 overflow-hidden rounded-[4px] border border-solid px-3.5 py-3", | ||
| isCompleted ? "bg-timo-gray-200" : "bg-white", | ||
| )} | ||
| > |
There was a problem hiding this comment.
체크박스나 재생 버튼 클릭할 때도 드래그가 시작될 수 있어보여요. distance: 8 제약으로 어느 정도 방어는 되지만 완전하지 않다고 생각이 들어요. 별도 드래그 핸들 아이콘을 만들고 거기에만 {...listeners}를 붙이는 게 안전할것 같은데 어떤가요?
| } | ||
|
|
||
| const query = params.toString(); | ||
| router.replace(query ? `${pathname}?${query}` : pathname); |
There was a problem hiding this comment.
뷰 전환이 히스토리에 안 남아서 브라우저 뒤로가기를 누르면 이전 뷰가 아닌 이전 페이지로 이동하는데 의도한 UX가 맞나요?
혹시 뒤로가기로 이전 뷰로 돌아올 수 있길 원한다면 router.push로 바꿔야 할 것 같아요-!
There was a problem hiding this comment.
좋네요! 뷰 전환은 사용자가 명시적으로 선택하는 부분이라 뒤로가기 클릭 시 복원되는 걸 기대할 것 같아요. 반영하겠습니다!
There was a problem hiding this comment.
생각해 보니 query 형태로 URL이 명시적으로 토글 시 쿼리가 전환되는 거라 router.push는 필요 없을 것 같긴 합니다. 이건 조금 더 고민해 보고 반영할게요!
|
|
||
| export interface DndSortableListProviderProps { | ||
| dndId: string; | ||
| itemIds: number[]; |
There was a problem hiding this comment.
지금 당장 문제가 되는 건 아닌데, dnd-kit의 UniqueIdentifier는 string | number를 모두 지원하는데 DndSortableListProvider의 itemIds가 number[]로 고정되어 있어요. 나중에 다른 도메인에서 string id를 쓰게 되면 이 Provider를 재사용하지 못하고 새로 만들어야 할 수 있어서요. 지금은 todoId: number라 문제없지만 한번 고려해보시면 좋을 것 같아요 😊
| /** | ||
| * 기본 뷰(가로 스크롤)에서 오늘 날짜가 맨 앞에 오도록 days 배열을 회전시킨다. | ||
| * 오늘 이전의 날짜들은 순서를 유지한 채 배열 끝으로 옮겨진다. | ||
| * @param days - 재정렬할 날짜 목록 | ||
| * @returns 오늘부터 시작하도록 재정렬된 날짜 목록 (오늘이 없으면 원본 그대로 반환) | ||
| */ |
There was a problem hiding this comment.
JSDoc도 꼼꼼하게 챙겨주셨네요.. 👍 저도 유틸에는 습관을 들여볼게요.
ehye1
left a comment
There was a problem hiding this comment.
Zustand 써본 적 없는데 이번 PR보면서 서로 다른 컴포넌트에서 같은 상태를 공유하는 흐름을 코드로 많이 배웠습니다! 드래그앤드롭 라이브러리로 dnd-kit도 처음 알게되었는데 자연스럽게 드래그가 돼서 좋아보이네요,,
두 가지 뷰 함께 구현하시느라 넘넘 고생많으셧어요~~~ 👍🏻👍🏻
| <Checkbox | ||
| checked={isCompleted} | ||
| onChange={onToggleCompleted} | ||
| disabled={isCompleted} |
There was a problem hiding this comment.
todo 완료되면 체크박스도 잠기는 걸로 보이는데 화면설계서에서 [Home-Default 4-4]에 완료 투두에서 체크 박스는 수정할 수가 있어서 확인부탁드립니다!
(TodayTodoCard처럼 완료되어도 hover시에 체크박스 수정가능한걸로 알고있습니다.)
There was a problem hiding this comment.
체크박스 수정 시 완료 토글 API를 호출하고, 재정렬된 데이터를 받아와야 해서 지금 프론트 로직에서 추가할 건 없어보입니다. 추후에 수정해 둘게요~!!
| const handleTogglePlay = (dateKey: string, todoId: number) => { | ||
| // TODO: API | ||
| const willRun = | ||
| todosByDate[dateKey]?.find((todo) => todo.todoId === todoId) | ||
| ?.timerStatus !== "RUNNING"; | ||
|
|
||
| updateTodo(dateKey, todoId, (todo) => ({ | ||
| ...todo, | ||
| timerStatus: todo.timerStatus === "RUNNING" ? "STOPPED" : "RUNNING", | ||
| })); | ||
|
|
||
| if (willRun) { | ||
| openTimerPanel(); | ||
| } | ||
| }; |
There was a problem hiding this comment.
handleTogglePlay가 클릭한 투두의 timerStatus만 토글해서 이미 RUNNING중인 다른 투두가 있어도 그대로 유지되어서 동시에 두 개가 실행이 가능한 것으로 보여요!
새로 재생 시작할 때 기존에 돌고 있던 투두를 STOPPED로 함께 전환하는 로직이 필요할 것 같습니다!
There was a problem hiding this comment.
이것 또한 실제 API 연동 시 상태 관리를 실데이터를 통해 전환해야 해서 해당 부분 구현할 때 함께 구현해 둘게요!
| export const reorderDaysTodayFirst = (days: HomeViewDay[]): HomeViewDay[] => { | ||
| const todayIndex = days.findIndex((day) => day.isToday); | ||
|
|
||
| if (todayIndex === -1) { | ||
| return days; | ||
| } | ||
|
|
||
| const upcoming = days.slice(todayIndex); | ||
| const past = days.slice(0, todayIndex); | ||
| return [...upcoming, ...past]; | ||
| }; |
There was a problem hiding this comment.
reorderDaysTodayFirst로 배열을 오늘 -> 미래 -> 과거 순으로 배치하고 있는데 이러면 스크롤 방향이 실제 날짜 흐름과 어긋나서 어색해보이는 것 같아요!
배열은 과거→오늘→미래 시간 순서 그대로 두고, 진입 시 "오늘" 카드 위치로 스크롤 포커스만 옮기는 방식(오늘 카드에 ref 걸고 scrollIntoView)이 더 직관적일 것 같은데 기획의도가 그렇다면 넘어가겠습니다,,
There was a problem hiding this comment.
API 연동 전 목데이터를 위한 함수라서 이대로 두고 실제 연동 시에 구현해 두면 될 것 같습니다!
ISSUE 🔗
close #121
What is this PR? 🔍
홈 화면을 기본 뷰(가로 스크롤)와 7일 뷰로 퍼블리싱하고, 투두 카드 드래그 정렬과 재생 버튼 클릭 시 타이머 사이드바 자동 오픈을 구현했습니다. 진행 중 발견한 세로 스크롤 레이아웃 붕괴 버그를 함께 수정했습니다.
배경
DEFAULT/WEEK) mock 데이터 레이어를 분리하고, 카드 높이를 콘텐츠 기준으로 되돌린 뒤 dnd-kit·zustand를 도입해 정렬과 사이드바 상태를 연결했습니다.홈 7일 뷰 & 데이터 레이어
DEFAULT/WEEK)와 기준일 기반home-viewmock 데이터 레이어를 구성하고, 헤더의 뷰 전환을 실제 데이터 조회 및 "오늘"로 스크롤 이동과 연결했습니다.useHomeViewMode가 뷰 모드와 기준일을 관리하고,getHomeViewMock({ filter, baseDate })가 이를 받아 날짜별Todo[]를 생성합니다. 기본 뷰는reorderDaysTodayFirst로 오늘 날짜를 맨 앞으로 회전시키고, 7일 뷰는 날짜 컬럼과 카드가 남은 공간을 유동적으로 나눠 가지되 최소 150px 폭을 보장하며 부족하면 가로 스크롤되도록 했습니다. priority/요일 i18n 메시지 키를 API enum 값(대문자)과 통일해 중복 라벨 매핑 유틸을 제거했습니다.투두 드래그 앤 드롭 정렬
@dnd-kit/core,@dnd-kit/sortable를 도입해DndSortableListProvider(providers/dnd/)가DndContext+SortableContext를 구성하고, 각HomeTodoCard는useSortable로 드래그 핸들을 갖습니다. 드롭 시useHomeTodosByDate.handleReorderTodo가 로컬 상태를 낙관적으로 재정렬한 뒤patchTodoOrderMock을 호출하고, 실패하면 이전 상태로 롤백합니다. 헤더/투두 상태 로직은 각각HomeDayHeaderContainer,useHomeTodosByDate로 분리해HomeTodoContainer의 책임을 줄였습니다.patchTodoOrderMock으로 대체했습니다 (// TODO: API).재생 버튼 → 타이머 사이드바 연동
WithTimeSidebarContainer·TimeSidebar각각의 로컬useState였기 때문에, 트리 깊숙한 곳(투두 카드)에서 상태를 바꿀 방법이 없었습니다.docs/architecture/state.md의 "클라이언트 전역 상태 → Zustand" 컨벤션에 따라zustand를 새로 추가하고stores/time-sidebar/useTimeSidebarStore.ts에isOpen/activeTab/openTimerPanel등을 정의했습니다.WithTimeSidebarContainer와TimeSidebar는 각자의 로컬 상태를 이 스토어로 교체했고,useHomeTodosByDate.handleTogglePlay는 타이머가 STOPPED→RUNNING으로 전환될 때만openTimerPanel()을 호출합니다(정지 시에는 호출하지 않음).파일 구조 정리
QueryProvider를providers/query/로, 토스트 컨테이너 2종을home/_containers/toast/로 이동했습니다(내용 변경 없는 순수 이동).docs/architecture/web/coding-style.md의 "파일 타입이 아닌 기능 단위 폴더" 컨벤션에 맞추기 위함입니다.layout.tsx의QueryProvider,HomeTodoContainer.tsx의DndSortableListProvider)를 함께 수정했습니다.AddTaskButton 유동 너비 (
@repo/timo-design-system)min-width를 제거해 부모 폭에 맞춰 유동적으로 늘어나거나 줄어들도록 하고, default와 폭 차이만 있던weeklyvariant를 제거했습니다.유틸 함수 문서화
date,day-of-week,home-view,todo-time유틸 함수에 동작을 설명하는 JSDoc을 추가했습니다.To Reviewers
handleReorderTodo)과 재생(handleTogglePlay) 모두 실제 API 대신 mock 함수를 호출합니다. 실제 API 연동은 후속 작업입니다.Screenshot 📷
Test Checklist ✔
pnpm check-types통과pnpm lint통과pnpm build— 미실행: 로컬에서 실행하지 않음Summary by CodeRabbit