[FEAT] 투두 생성 모달 및 홈 투두 카드 UI 구현#138
Conversation
- overlay-kit, @dnd-kit/modifiers 의존성을 추가했습니다
- 아이콘 선택기, 날짜 선택기, 태그 입력, 투두 툴바 컴포넌트를 추가했습니다 - 우선순위/반복/태그/시간 선택기를 투두 모달 요구사항에 맞게 수정했습니다 - 투두 아이콘 SVG 8종을 추가했습니다
- 투두 생성 요청 스키마를 정의했습니다 - 오버레이 기반 모달 컴포넌트와 프로바이더를 추가하고 루트 레이아웃에 연결했습니다
- 투두 생성 모달과 태그 생성 모달을 구현했습니다 - 홈 투두 카드와 데이 헤더 UI를 구현하고 드래그 정렬을 연동했습니다 - 모달 폼 필드 바인딩을 useController 기반으로 구현했습니다 - 드래그 정렬을 세로 축으로 제한했습니다 - 관련 폴더를 기능 단위(todo-card/todo-modal/tag-modal)로 구성했습니다
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Next review available in: 14 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
Walkthrough투두 생성 API 스키마와 입력 폼, 오버레이·태그 생성 모달, 디자인시스템 컴포넌트가 추가되었다. 생성된 Todo는 홈의 날짜별 목록에 반영되며, 날짜·우선순위·반복 값과 관련 유틸리티 및 공개 export가 갱신되었다. Changes투두 생성 기능
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant HomeDayHeaderContainer
participant CreateTodoModalContent
participant TodoSchema
participant useCreateTodoSubmit
participant HomeTodoContainer
User->>HomeDayHeaderContainer: 생성 버튼 클릭
HomeDayHeaderContainer->>CreateTodoModalContent: 날짜와 모달 표시
User->>CreateTodoModalContent: Todo 입력 및 제출
CreateTodoModalContent->>TodoSchema: 요청 데이터 검증
TodoSchema-->>CreateTodoModalContent: 검증 결과
CreateTodoModalContent->>useCreateTodoSubmit: 검증된 데이터 전달
useCreateTodoSubmit->>HomeTodoContainer: Todo 생성 콜백 호출
HomeTodoContainer->>HomeTodoContainer: 날짜별 목록에 Todo 추가
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
Timo Performance ReportBundle Size — timo-web
Lighthouse — timo-web
Image Optimization — timo-web
측정 커밋: |
There was a problem hiding this comment.
Actionable comments posted: 14
🤖 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 `@apps/timo-web/api/todo/todo-schema.ts`:
- Around line 43-76: createTodoRequestSchema의 superRefine에서 repeatType과 반복 필드의
불일치를 검증하도록 보강하세요. WEEKLY가 아닐 때 repeatWeekdays가 비어 있지 않으면 해당 값을 무효화하거나 검증 오류를
추가하고, MONTHLY가 아닐 때 repeatDayOfMonth가 null이 아니면 동일하게 처리하여 stale 데이터가 백엔드로 전송되지
않도록 하세요.
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_components/todo-modal/CreateTodoMemoField.tsx:
- Around line 12-20: textarea in CreateTodoMemoField currently removes the focus
outline without a replacement. Replace the unconditional outline-none styling
with a focus-visible-based accessible focus indicator, using focus-visible:ring
or an equivalent visible border/outline style while preserving the default
non-focused appearance.
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_components/todo-modal/CreateTodoTaskFields.tsx:
- Around line 22-39: title and subtask inputs in CreateTodoTaskFields use
outline-none without a visible keyboard focus indicator. Replace the
unconditional outline removal on both inputs with focus-visible styles that
provide a clear focus outline or equivalent ring while preserving the existing
appearance otherwise.
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_containers/tag-modal/CreateTagModalContainer.tsx:
- Around line 55-62: Update the close button in CreateTagModalContainer to use a
tag-modal-specific or shared close-label translation instead of
t("createModal.close"). Prefer adding and using the createTagModal.close key, or
use the existing Common.close key consistently with the translation structure.
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_containers/todo-modal/CreateTodoModalContent.tsx:
- Around line 115-119: subtasks 매핑에서 각 항목에 동일한 Date.now() 값이 할당되지 않도록 수정하세요.
CreateTodoModalContent의 subtaskId 생성 로직을 확인해 고유한 ID를 생성하도록 인덱스나 UUID 등 안정적인 식별자를
사용하고, 토글·삭제 로직과의 일관성도 유지하세요.
- Line 122: In the reset call within CreateTodoModalContent, pass the existing
defaultDate to createDefaultValues instead of calling it without arguments, so
the form retains the selected default date after submission.
- Around line 233-237: Expose validation failures from zodResolver in
CreateTodoModalContent instead of silently ignoring them: use formState.errors
to render an inline message or provide an onInvalid callback to handleSubmit,
especially for conditions such as missing WEEKLY days. Keep the existing
title-based disabled state while ensuring users receive a clear error when
validation blocks submission.
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_hooks/useHomeTodosByDate.ts:
- Around line 35-42: handleAddTodo의 TODO API를 구현해 로컬 상태만 갱신하지 않도록 하세요. Todo 생성
API를 호출하고 성공 시 서버 응답으로 상태를 반영하며, 실패 시 낙관적으로 추가한 항목을 제거하는 rollback과 사용자에게 오류를 알리는
처리를 추가하세요.
In `@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_utils/date.ts:
- Around line 79-85: formatDateToIsoDate와 기존 formatDateKey가 동일한 날짜 포맷팅 로직을 중복
구현하고 있습니다. 두 함수의 의미가 동일하면 하나를 제거하고 기존 함수를 사용하며, 별도 공개 API가 필요하면
formatDateToIsoDate가 formatDateKey를 호출하도록 변경해 중복을 없애세요.
In `@apps/timo-web/components/modal/Modal.tsx`:
- Around line 11-17: ModalProps에 선택적 aria-label 프로퍼티를 추가하고, Modal 컴포넌트의
role="dialog" 요소에 해당 값을 전달하세요. 호출부에서 모달 목적을 설명하는 accessible name을 제공할 수 있도록 기본값
없이 구현하고, 기존 className 및 기타 속성 동작은 유지하세요.
- Around line 48-87: Modal의 포커스 관리가 없어 키보드 사용자가 대화상자 밖으로 이동할 수 있습니다. `Modal`
컴포넌트의 `useEffect`와 dialog 요소를 수정해 열리기 전 활성 요소를 저장하고 열린 직후 첫 번째 포커스 가능 요소(없으면
dialog 자체)로 포커스를 이동하세요. `keydown` 처리에서 Tab 이동을 dialog 내부의 포커스 가능 요소 사이로 순환시키고,
닫힐 때 저장한 이전 요소로 포커스를 복원하며 dialog에 필요한 `tabIndex={-1}`를 추가하세요.
In
`@packages/timo-design-system/src/components/icon/icon-graphic/IconGraphic.tsx`:
- Around line 15-23: TodoIconValue와 todoIconSchema의 아이콘 값이 중복 정의되어 있으므로,
IconGraphic.tsx에서 ICON_1~ICON_8을 담은 공용 상수를 먼저 만들고 이를 기반으로 TodoIconValue 타입과
z.enum(...) 스키마를 파생시키세요. 두 정의가 동일한 소스를 참조하도록 관련 선언을 정리하세요.
In `@packages/timo-design-system/src/components/index.ts`:
- Around line 22-42: 기존 소비자가 Modal 관련 타입을 import할 수 있도록
`src/components/index.ts`의 barrel export에서 `ModalButtonVariantTypes`,
`ModalButtonProps` 및 `Modal.tsx`의 관련 props 타입을 다시 re-export하세요. 기존 `Modal` 컴포넌트
export는 유지하고, 필요하면 호환 가능한 별도 `modal` 진입점도 함께 유지하세요.
In
`@packages/timo-design-system/src/components/tag/tag-name-input/TagNameInput.tsx`:
- Around line 30-35: TagNameInput의 입력 접근성을 개선하세요. TagNameInput 컴포넌트에서 useId()로
인스턴스별 고유 ID를 생성하고 input의 id와 접근 가능한 이름(aria-label 또는 연결된 label)에 사용하세요. input의
className에서 outline-none을 제거하고 키보드 포커스가 명확히 보이는 기본 또는 대체 focus 스타일을 유지하세요.
🪄 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: cfbe899b-c4cd-41e8-8eb9-6edf98da2264
⛔ Files ignored due to path filters (9)
packages/timo-design-system/src/icons/source/todo-icon-daily.svgis excluded by!**/*.svgpackages/timo-design-system/src/icons/source/todo-icon-etc.svgis excluded by!**/*.svgpackages/timo-design-system/src/icons/source/todo-icon-plus.svgis excluded by!**/*.svgpackages/timo-design-system/src/icons/source/todo-icon-relationship.svgis excluded by!**/*.svgpackages/timo-design-system/src/icons/source/todo-icon-rest.svgis excluded by!**/*.svgpackages/timo-design-system/src/icons/source/todo-icon-study.svgis excluded by!**/*.svgpackages/timo-design-system/src/icons/source/todo-icon-task.svgis excluded by!**/*.svgpackages/timo-design-system/src/icons/source/todo-icon-work.svgis excluded by!**/*.svgpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (46)
apps/timo-web/api/todo/todo-schema.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_components/todo-card/HomeDateInformation.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_components/todo-card/HomeTodoCard.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_components/todo-modal/CreateTodoIconField.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_components/todo-modal/CreateTodoMemoField.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_components/todo-modal/CreateTodoTaskFields.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/tag-modal/CreateTagModalContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/todo-card/HomeDayHeaderContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/todo-modal/CreateTodoModalContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/todo-modal/CreateTodoModalContent.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/todo-modal/use-icon-field.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/todo-modal/use-repeat-field.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/todo-modal/use-tag-field.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/todo-modal/use-time-field.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/todo-mock.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/todo-time.tsapps/timo-web/app/[locale]/layout.tsxapps/timo-web/components/modal/Modal.tsxapps/timo-web/messages/en.jsonapps/timo-web/messages/ko.jsonapps/timo-web/package.jsonapps/timo-web/providers/OverlayProvider.tsxapps/timo-web/providers/dnd/DndSortableListProvider.tsxpackages/timo-design-system/src/components/calendar/date-selector/DateSelector.stories.tsxpackages/timo-design-system/src/components/calendar/date-selector/DateSelector.tsxpackages/timo-design-system/src/components/icon/icon-graphic/IconGraphic.stories.tsxpackages/timo-design-system/src/components/icon/icon-graphic/IconGraphic.tsxpackages/timo-design-system/src/components/icon/icon-selector/IconSelector.stories.tsxpackages/timo-design-system/src/components/icon/icon-selector/IconSelector.tsxpackages/timo-design-system/src/components/index.tspackages/timo-design-system/src/components/priority/priority-icon/PriorityIcon.stories.tsxpackages/timo-design-system/src/components/priority/priority-icon/PriorityIcon.tsxpackages/timo-design-system/src/components/priority/priority-selector/PrioritySelector.stories.tsxpackages/timo-design-system/src/components/priority/priority-selector/PrioritySelector.tsxpackages/timo-design-system/src/components/repeat/repeat-selector/RepeatSelector.stories.tsxpackages/timo-design-system/src/components/repeat/repeat-selector/RepeatSelector.tsxpackages/timo-design-system/src/components/tag/tag-name-input/TagNameInput.stories.tsxpackages/timo-design-system/src/components/tag/tag-name-input/TagNameInput.tsxpackages/timo-design-system/src/components/tag/tag-selector/TagSelector.tsxpackages/timo-design-system/src/components/time/time-selector/TimeSelector.tsxpackages/timo-design-system/src/components/todo/todo-toolbar/TodoToolbar.tsx
- _hooks/useHomeTodayScroll.ts를 use-home-today-scroll.ts로 변경했습니다 - _hooks/useHomeTodosByDate.ts를 use-home-todos-by-date.ts로 변경했습니다 - _hooks/useHomeViewMode.ts를 use-home-view-mode.ts로 변경했습니다 - 네이밍 컨벤션에 맞춰 참조하는 컨테이너의 import 경로를 갱신했습니다
- 투두 생성(mock) 조립 로직을 use-create-todo-submit 훅으로 분리했습니다 - CreateTodoModalContainer가 useCreateTodoSubmit을 통해 생성 사이드 이펙트를 소유하도록 했습니다 - CreateTodoModalContent는 onSubmit prop만 호출하도록 하여 폼 검증·렌더링만 담당하게 했습니다
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx (1)
94-94: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win선택한 날짜를
handleAddTodo까지 전달하세요.
HomeTodoContainer.tsx:94에서dateKey만 쓰면 모달에서 바꾼data.date가 반영되지 않습니다.use-create-todo-submit.ts:8-38에서buildTodoFromRequest가data.date를 버리고 있어서, 날짜를 수정해도 원래 컬럼에 추가됩니다.data.date를 상위로 넘겨dateKey를 다시 계산하거나,Todo에date를 포함해 저장 경로를 유지하세요. React Hook FormhandleSubmit처럼 제출값은 중간에서 잃지 않는 구조가 좋습니다: https://react-hook-form.com/docs/useform/handlesubmit🤖 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/_containers/HomeTodoContainer.tsx at line 94, 모달에서 변경한 날짜가 저장 경로에서 유실되고 있습니다. HomeTodoContainer의 onCreateTodo와 handleAddTodo 호출 흐름에서 제출된 data.date를 상위로 전달하고, use-create-todo-submit의 buildTodoFromRequest가 해당 날짜를 보존하도록 수정하세요. 필요하면 data.date로 dateKey를 재계산해 올바른 날짜 컬럼에 추가되게 하며, React Hook Form handleSubmit처럼 제출값을 중간에서 버리지 않도록 전체 호출 체인을 점검하세요.
🤖 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
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_hooks/todo-modal/use-create-todo-submit.ts:
- Line 12: use-create-todo-submit.ts의 서브태스크 생성 로직에서 .map() 내부의 Date.now() 기반
todoId가 모든 항목에 동일하게 생성되고 상위 todoId와 충돌할 수 있습니다. 고유 ID 생성 유틸리티 또는 충돌을 방지하는 안정적인
ID 생성 방식을 사용해 각 서브태스크의 todoId를 독립적으로 생성하고, 관련 23–24행의 ID 할당도 동일하게 수정하세요.
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-todos-by-date.ts:
- Around line 16-20: When apiDays changes, the useEffect currently replaces
todosByDate and discards todos added locally by handleAddTodo. Preserve pending
local additions by tracking them in a separate overlay state and merging it with
the API-derived entries, or by merging additions into the incoming apiDays
result; update handleAddTodo and the apiDays synchronization logic consistently
so filter/baseDate refreshes retain unsynced todos.
---
Outside diff comments:
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx:
- Line 94: 모달에서 변경한 날짜가 저장 경로에서 유실되고 있습니다. HomeTodoContainer의 onCreateTodo와
handleAddTodo 호출 흐름에서 제출된 data.date를 상위로 전달하고, use-create-todo-submit의
buildTodoFromRequest가 해당 날짜를 보존하도록 수정하세요. 필요하면 data.date로 dateKey를 재계산해 올바른 날짜
컬럼에 추가되게 하며, React Hook Form handleSubmit처럼 제출값을 중간에서 버리지 않도록 전체 호출 체인을 점검하세요.
🪄 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: efcb067f-3026-495d-8a71-204b9d87d5f0
📒 Files selected for processing (8)
apps/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/todo-modal/CreateTodoModalContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/todo-modal/CreateTodoModalContent.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/todo-modal/use-create-todo-submit.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-today-scroll.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-todos-by-date.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-view-mode.ts
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx (1)
94-94: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win선택한 날짜를
handleAddTodo까지 전달하세요.
HomeTodoContainer.tsx:94에서dateKey만 쓰면 모달에서 바꾼data.date가 반영되지 않습니다.use-create-todo-submit.ts:8-38에서buildTodoFromRequest가data.date를 버리고 있어서, 날짜를 수정해도 원래 컬럼에 추가됩니다.data.date를 상위로 넘겨dateKey를 다시 계산하거나,Todo에date를 포함해 저장 경로를 유지하세요. React Hook FormhandleSubmit처럼 제출값은 중간에서 잃지 않는 구조가 좋습니다: https://react-hook-form.com/docs/useform/handlesubmit🤖 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/_containers/HomeTodoContainer.tsx at line 94, 모달에서 변경한 날짜가 저장 경로에서 유실되고 있습니다. HomeTodoContainer의 onCreateTodo와 handleAddTodo 호출 흐름에서 제출된 data.date를 상위로 전달하고, use-create-todo-submit의 buildTodoFromRequest가 해당 날짜를 보존하도록 수정하세요. 필요하면 data.date로 dateKey를 재계산해 올바른 날짜 컬럼에 추가되게 하며, React Hook Form handleSubmit처럼 제출값을 중간에서 버리지 않도록 전체 호출 체인을 점검하세요.
🤖 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
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_hooks/todo-modal/use-create-todo-submit.ts:
- Line 12: use-create-todo-submit.ts의 서브태스크 생성 로직에서 .map() 내부의 Date.now() 기반
todoId가 모든 항목에 동일하게 생성되고 상위 todoId와 충돌할 수 있습니다. 고유 ID 생성 유틸리티 또는 충돌을 방지하는 안정적인
ID 생성 방식을 사용해 각 서브태스크의 todoId를 독립적으로 생성하고, 관련 23–24행의 ID 할당도 동일하게 수정하세요.
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-todos-by-date.ts:
- Around line 16-20: When apiDays changes, the useEffect currently replaces
todosByDate and discards todos added locally by handleAddTodo. Preserve pending
local additions by tracking them in a separate overlay state and merging it with
the API-derived entries, or by merging additions into the incoming apiDays
result; update handleAddTodo and the apiDays synchronization logic consistently
so filter/baseDate refreshes retain unsynced todos.
---
Outside diff comments:
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx:
- Line 94: 모달에서 변경한 날짜가 저장 경로에서 유실되고 있습니다. HomeTodoContainer의 onCreateTodo와
handleAddTodo 호출 흐름에서 제출된 data.date를 상위로 전달하고, use-create-todo-submit의
buildTodoFromRequest가 해당 날짜를 보존하도록 수정하세요. 필요하면 data.date로 dateKey를 재계산해 올바른 날짜
컬럼에 추가되게 하며, React Hook Form handleSubmit처럼 제출값을 중간에서 버리지 않도록 전체 호출 체인을 점검하세요.
🪄 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: efcb067f-3026-495d-8a71-204b9d87d5f0
📒 Files selected for processing (8)
apps/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/todo-modal/CreateTodoModalContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/todo-modal/CreateTodoModalContent.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/todo-modal/use-create-todo-submit.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-today-scroll.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-todos-by-date.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-view-mode.ts
🛑 Comments failed to post (2)
apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/todo-modal/use-create-todo-submit.ts (1)
12-12: 🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win
Date.now()기반 ID 충돌 — 서브태스크가 모두 동일한subtaskId를 갖습니다.이전 리뷰에서
CreateTodoModalContent.tsx의 동일한 문제를 지적했고 수정되었으나, 리팩토링으로 로직이 이 파일로 이동하면서 수정이 유실되었습니다..map()내Date.now()가 동기 호출되어 모든 서브태스크가 같은 ID를 갖게 되고,todoId와도 충돌할 수 있습니다.): Todo => ({ - todoId: Date.now(), + todoId: Date.now(), icon: data.icon, title: data.title, completed: false, durationSeconds: convertApiDurationToSeconds(data.duration), priority: data.priority ?? "MEDIUM", tag: { tagId: tag.id, name: tag.name }, hasMemo: Boolean(data.memo?.trim()), isRepeated: data.repeatType !== "NONE", timerStatus: "STOPPED", sortOrder: 0, subtasks: (data.subtasks ?? []).map((content, index) => ({ - subtaskId: Date.now(), + subtaskId: Date.now() + index, content, completed: false, })), }),참고: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now
Also applies to: 23-24
🤖 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/_hooks/todo-modal/use-create-todo-submit.ts at line 12, use-create-todo-submit.ts의 서브태스크 생성 로직에서 .map() 내부의 Date.now() 기반 todoId가 모든 항목에 동일하게 생성되고 상위 todoId와 충돌할 수 있습니다. 고유 ID 생성 유틸리티 또는 충돌을 방지하는 안정적인 ID 생성 방식을 사용해 각 서브태스크의 todoId를 독립적으로 생성하고, 관련 23–24행의 ID 할당도 동일하게 수정하세요.apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-todos-by-date.ts (1)
16-20: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash set -euo pipefail FILE='apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-todos-by-date.ts' echo "== file exists ==" git ls-files "$FILE" echo "== outline ==" ast-grep outline "$FILE" --view expanded || true echo "== file contents ==" cat -n "$FILE"Repository: Team-Timo/Timo-client
Length of output: 4349
🏁 Script executed:
#!/bin/bash set -euo pipefail # Find related usages and the hook's consumers to understand state ownership. rg -n "useHomeTodosByDate|handleAddTodo|todosByDate|apiDays" apps/timo-web/app/[locale]/\(main\)/\(with-time-sidebar\)/home -S # Show nearby files if present. fd -a "use-home-todos-by-date" apps/timo-web/app/[locale]/\(main\)/\(with-time-sidebar\)/home || trueRepository: Team-Timo/Timo-client
Length of output: 2864
🏁 Script executed:
#!/bin/bash set -euo pipefail FILE='apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-todos-by-date.ts' # Show only the hook and its immediate neighborhood with line numbers. sed -n '1,220p' "$FILE" | cat -n echo echo "== related search ==" rg -n "setTodosByDate|handleAddTodo|apiDays" "$FILE" -n -SRepository: Team-Timo/Timo-client
Length of output: 4629
🏁 Script executed:
#!/bin/bash set -euo pipefail FILE='apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx' sed -n '1,180p' "$FILE" | cat -nRepository: Team-Timo/Timo-client
Length of output: 6861
🏁 Script executed:
#!/bin/bash set -euo pipefail # Check whether apiDays is stable/memoized and how todosByDate is consumed. rg -n "useMemo|useHomeTodosByDate|todosByDate\[dateKey\]|day\.todos|isWeekView" \ apps/timo-web/app/[locale]/\(main\)/\(with-time-sidebar\)/home/_containers/HomeTodoContainer.tsx -n -SRepository: Team-Timo/Timo-client
Length of output: 850
🏁 Script executed:
#!/bin/bash set -euo pipefail FILE='apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx' echo "== file exists ==" git ls-files "$FILE" echo "== outline ==" ast-grep outline "$FILE" --view expanded || true echo "== contents ==" sed -n '1,220p' "$FILE" | cat -nRepository: Team-Timo/Timo-client
Length of output: 7279
apiDays갱신 시 로컬 추가 투두를 보존하세요. 구조는 깔끔합니다. 다만handleAddTodo가 만든 항목은 로컬 상태에만 남아 있어서,filter/baseDate변경으로apiDays가 다시 들어오면useEffect가todosByDate를 통째로 덮어씁니다. 아직 API에 반영되지 않은 추가분은 별도 오버레이 상태로 분리하거나 새apiDays와 병합해 주세요. React의 derived state 안내도 참고할 만합니다: https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes🤖 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/_hooks/use-home-todos-by-date.ts around lines 16 - 20, When apiDays changes, the useEffect currently replaces todosByDate and discards todos added locally by handleAddTodo. Preserve pending local additions by tracking them in a separate overlay state and merging it with the API-derived entries, or by merging additions into the incoming apiDays result; update handleAddTodo and the apiDays synchronization logic consistently so filter/baseDate refreshes retain unsynced todos.
…to feat/web/137-create-todo-modal
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@apps/timo-web/messages/ko.json`:
- Around line 68-82: Update the Korean strings in the Error and GlobalError
entries to use “잠시 후” and “이동해 주세요” with proper spacing, and add a final period
to the NotFound description. Preserve the existing translations and structure.
🪄 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: c2696c17-ea4f-4e67-9ff2-ee234dd233e3
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (3)
apps/timo-web/messages/en.jsonapps/timo-web/messages/ko.jsonapps/timo-web/package.json
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
Actionable comments posted: 1
🤖 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 `@apps/timo-web/messages/ko.json`:
- Around line 68-82: Update the Korean strings in the Error and GlobalError
entries to use “잠시 후” and “이동해 주세요” with proper spacing, and add a final period
to the NotFound description. Preserve the existing translations and structure.
🪄 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: c2696c17-ea4f-4e67-9ff2-ee234dd233e3
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (3)
apps/timo-web/messages/en.jsonapps/timo-web/messages/ko.jsonapps/timo-web/package.json
🛑 Comments failed to post (1)
apps/timo-web/messages/ko.json (1)
68-82: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
한국어 문구의 띄어쓰기와 마침표를 다듬어 주세요.
잠시후는잠시 후,이동해주세요는이동해 주세요로 띄어 쓰고, NotFound 설명 끝에 마침표를 추가하면 문구 일관성이 좋아집니다.권장 수정
- "description": "더 나은 경험을 위해 잠시 점검 중입니다. 잠시후 다시 이용해 주세요.", + "description": "더 나은 경험을 위해 잠시 점검 중입니다. 잠시 후 다시 이용해 주세요.", ... - "description": "존재하지 않는 주소를 입력하셨거나, 잘못된 경로를 이용하셨어요", + "description": "존재하지 않는 주소를 입력하셨거나, 잘못된 경로를 이용하셨어요.", ... - "description": "잠시 후 다시 시도하거나 홈으로 이동해주세요.", + "description": "잠시 후 다시 시도하거나 홈으로 이동해 주세요.",📝 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."Error": { "title": "잠시 문제가 발생했어요.", "description": "더 나은 경험을 위해 잠시 점검 중입니다. 잠시 후 다시 이용해 주세요.", "homeButton": "홈으로 돌아가기" }, "NotFound": { "title": "페이지를 찾을 수 없어요.", "description": "존재하지 않는 주소를 입력하셨거나, 잘못된 경로를 이용하셨어요.", "homeButton": "홈으로 돌아가기" }, "GlobalError": { "title": "문제가 발생했어요.", "description": "잠시 후 다시 시도하거나 홈으로 이동해 주세요.", "homeButton": "홈으로 돌아가기" },🤖 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/messages/ko.json` around lines 68 - 82, Update the Korean strings in the Error and GlobalError entries to use “잠시 후” and “이동해 주세요” with proper spacing, and add a final period to the NotFound description. Preserve the existing translations and structure.
- useId()로 input에 고유 id를 부여했습니다 - ariaLabel prop을 추가해 접근 가능한 이름을 제공하도록 했습니다 - outline-none만 있던 포커스 스타일을 focus-visible:ring으로 교체했습니다
- 신규 필수 prop ariaLabel에 기존 시각적 라벨 텍스트를 전달하도록 반영했습니다
- home/statistics/today 기능에 흩어져 있던 날짜 유틸을 apps/timo-web/utils/date.ts 하나로 모았습니다 - statistics/_utils/statistics-calendar.ts에 완전히 중복 구현돼 있던 formatDateKey를 제거했습니다 - 기존 apps/timo-web/utils/format-date.ts의 formatDate도 함께 통합했습니다
- PRIORITY_MAP이 PriorityIcon이 기대하는 VERY_HIGH/HIGH/MEDIUM/LOW 대신 소문자 값으로 잘못 매핑되어 있던 타입 에러를 수정했습니다
- ICON_1~ICON_8을 담은 TODO_ICON_VALUES 상수를 만들고 TodoIconValue 타입을 이로부터 파생시켰습니다 - TODO_ICON_OPTIONS도 같은 상수를 참조하도록 정리했습니다
- ICON_1~ICON_8을 하드코딩하던 z.enum 목록을 제거하고 TODO_ICON_VALUES에서 파생하도록 했습니다
- 모달 포커스 트랩 구현에 사용할 focus-trap-react를 추가했습니다
- 디자인시스템의 Modal 컴포넌트와 이름이 겹쳐 헷갈리지 않도록 OverlayModal로 이름을 바꿨습니다 - aria-label을 받아 대화상자에 접근 가능한 이름을 제공할 수 있도록 했습니다 - focus-trap-react로 Tab 포커스를 다이얼로그 내부로 트랩하고, 열릴 때 초기 포커스를, 닫힐 때 이전 포커스를 복원하도록 했습니다
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/todo-modal/CreateTodoModalContent.tsx (1)
110-114:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
OverlayModal에ariaLabelprop이 누락되었습니다.
OverlayModal은 내부적으로aria-label={ariaLabel}을 렌더링하지만, 현재 prop이 전달되지 않아 dialog 요소에 접근 가능한 이름(accessible name)이 없습니다. 스크린 리더 사용자가 모달의 목적을 파악하기 어렵습니다.🛡️ 제안 수정
<OverlayModal isOpen={isOpen} onClose={onClose} onExited={onExited} + ariaLabel={t("createModal.title")} className="w-[490px] items-center gap-2.5 px-6 py-4" >As per coding guidelines,
**/*.{ts,tsx}파일에서 텍스트 없는 버튼에aria-label이 필수이며, 시맨틱 태그와 접근성 규칙을 준수해야 합니다.[accessibility]
🤖 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/_containers/todo-modal/CreateTodoModalContent.tsx around lines 110 - 114, Update the OverlayModal invocation in CreateTodoModalContent to pass an ariaLabel describing the todo-creation modal, ensuring the rendered dialog has an accessible name while preserving the existing modal behavior.Source: Path instructions
apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/tag-modal/CreateTagModalContainer.tsx (1)
45-49:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
OverlayModal에ariaLabelprop이 누락되었습니다.
CreateTodoModalContent와 동일한 문제입니다.OverlayModal이aria-label={ariaLabel}을 렌더링하지만 prop이 전달되지 않아 dialog에 접근 가능한 이름이 없습니다.🛡️ 제안 수정
<OverlayModal isOpen={isOpen} onClose={onClose} onExited={onExited} + ariaLabel={t("createTagModal.title")} className="w-[490px] items-center gap-3 px-6 py-4" >As per coding guidelines,
**/*.{ts,tsx}파일에서 접근성 규칙을 준수해야 하며, 시맨틱 태그와aria-label사용이 권장됩니다.[accessibility]
🤖 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/_containers/tag-modal/CreateTagModalContainer.tsx around lines 45 - 49, Update the OverlayModal usage in CreateTagModalContainer to pass an appropriate ariaLabel value, using the modal’s existing title or accessible-label source. Ensure the dialog receives a non-empty accessible name while preserving the existing open, close, and exit behavior.Source: Path instructions
apps/timo-web/components/modal/OverlayModal.tsx (1)
33-50: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winonClose/onExited를 ref로 고정하세요
apps/timo-web/components/modal/OverlayModal.tsx:33-67에서 콜백을 deps에 직접 넣으면 부모가 새 함수를 넘길 때onExited타이머가 리셋되어 닫힘 완료가 지연될 수 있고,keydown리스너도 불필요하게 재등록됩니다.useRef로 최신 콜백만 읽고 effect deps는isOpen/shouldRender만 유지하는 쪽이 더 단단합니다. ReactuseEffect/useRef참고: https://react.dev/reference/react/useEffect, https://react.dev/reference/react/useRef🤖 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/components/modal/OverlayModal.tsx` around lines 33 - 50, Update OverlayModal’s useEffect and keydown-listener logic to store the latest onClose and onExited callbacks in useRef values, then read those refs when invoking them. Remove callback identities from the effect dependencies so changing parent callbacks does not restart the exit timer or re-register listeners; retain only the necessary isOpen/shouldRender dependencies.
♻️ Duplicate comments (3)
apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/todo-modal/CreateTodoModalContent.tsx (2)
102-102: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
reset()호출 시defaultDate가 여전히 누락되어 있습니다.이전 리뷰에서 제안된 수정이 아직 적용되지 않은 것으로 보입니다.
reset(createDefaultValues())대신reset(createDefaultValues(defaultDate))를 사용해야 제출 후에도 선택했던 날짜가 유지됩니다.💚 제안 수정
- reset(createDefaultValues()); + reset(createDefaultValues(defaultDate));🤖 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/_containers/todo-modal/CreateTodoModalContent.tsx at line 102, Update the reset call in CreateTodoModalContent to pass defaultDate into createDefaultValues, using reset(createDefaultValues(defaultDate)), so the selected date remains preserved after submission.
213-217: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win검증 실패 시 에러가 여전히 사용자에게 보이지 않습니다.
이전 리뷰에서 지적된 내용이 아직 적용되지 않았습니다.
zodResolver(createTodoRequestSchema)가WEEKLY요일 누락 등의 조건을 막을 때,handleSubmit이 조용히 종료되어 사용자가 제출이 안 되는 원인을 알 수 없습니다.formState.errors를 화면에 노출하거나handleSubmit(onSubmit, onInvalid)패턴으로 에러 피드백을 추가해 주세요.참고: react-hook-form handleSubmit 문서
🤖 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/_containers/todo-modal/CreateTodoModalContent.tsx around lines 213 - 217, Update the CreateTodoModalContent submission flow around handleSubmit(handleFormSubmit) so validation failures from zodResolver are surfaced to the user instead of being silently ignored. Expose formState.errors in the UI or add an onInvalid callback to handleSubmit that provides clear validation feedback, while preserving the existing valid-submit behavior.apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/tag-modal/CreateTagModalContainer.tsx (1)
57-57: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win닫기 버튼
aria-label이 여전히createModal네임스페이스를 참조합니다.이전 리뷰에서 지적된 내용이 아직 적용되지 않았습니다. 태그 모달의 닫기 버튼이
t("createModal.close")를 사용하고 있습니다.createTagModal.close키를 추가하거나 공통Common.close키를 사용하는 것이 더 일관성 있습니다.💚 제안 수정
- aria-label={t("createModal.close")} + aria-label={t("createTagModal.close")}🤖 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/_containers/tag-modal/CreateTagModalContainer.tsx at line 57, Update the close button’s translation reference in the tag modal container from the createModal namespace to the tag modal’s createTagModal.close key, or the shared Common.close key if that is the established convention; ensure the rendered aria-label remains localized.
🤖 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 `@apps/timo-web/components/modal/OverlayModal.tsx`:
- Around line 12-19: Update OverlayModalProps and both OverlayModal consumers so
every role="dialog" instance has an accessible name. Prefer making ariaLabel
required and passing a meaningful label from each caller, or connect the
existing rendered title through aria-labelledby; do not leave either usage
without a dialog name.
---
Outside diff comments:
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_containers/tag-modal/CreateTagModalContainer.tsx:
- Around line 45-49: Update the OverlayModal usage in CreateTagModalContainer to
pass an appropriate ariaLabel value, using the modal’s existing title or
accessible-label source. Ensure the dialog receives a non-empty accessible name
while preserving the existing open, close, and exit behavior.
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_containers/todo-modal/CreateTodoModalContent.tsx:
- Around line 110-114: Update the OverlayModal invocation in
CreateTodoModalContent to pass an ariaLabel describing the todo-creation modal,
ensuring the rendered dialog has an accessible name while preserving the
existing modal behavior.
In `@apps/timo-web/components/modal/OverlayModal.tsx`:
- Around line 33-50: Update OverlayModal’s useEffect and keydown-listener logic
to store the latest onClose and onExited callbacks in useRef values, then read
those refs when invoking them. Remove callback identities from the effect
dependencies so changing parent callbacks does not restart the exit timer or
re-register listeners; retain only the necessary isOpen/shouldRender
dependencies.
---
Duplicate comments:
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_containers/tag-modal/CreateTagModalContainer.tsx:
- Line 57: Update the close button’s translation reference in the tag modal
container from the createModal namespace to the tag modal’s createTagModal.close
key, or the shared Common.close key if that is the established convention;
ensure the rendered aria-label remains localized.
In
`@apps/timo-web/app/`[locale]/(main)/(with-time-sidebar)/home/_containers/todo-modal/CreateTodoModalContent.tsx:
- Line 102: Update the reset call in CreateTodoModalContent to pass defaultDate
into createDefaultValues, using reset(createDefaultValues(defaultDate)), so the
selected date remains preserved after submission.
- Around line 213-217: Update the CreateTodoModalContent submission flow around
handleSubmit(handleFormSubmit) so validation failures from zodResolver are
surfaced to the user instead of being silently ignored. Expose formState.errors
in the UI or add an onInvalid callback to handleSubmit that provides clear
validation feedback, while preserving the existing valid-submit behavior.
🪄 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: 97309454-285f-433f-a753-6ec18195f641
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (20)
apps/timo-web/api/todo/todo-schema.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/tag-modal/CreateTagModalContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/todo-card/HomeDayHeaderContainer.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/todo-modal/CreateTodoModalContent.tsxapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-view-mode.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/_utils/date.tsapps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoListContainer.tsxapps/timo-web/app/[locale]/(main)/statistics/_components/StatisticsCalendar.tsxapps/timo-web/app/[locale]/(main)/statistics/_utils/statistics-calendar.tsapps/timo-web/components/modal/OverlayModal.tsxapps/timo-web/package.jsonapps/timo-web/utils/date.tsapps/timo-web/utils/format-date.tspackages/timo-design-system/src/components/icon/icon-graphic/IconGraphic.tsxpackages/timo-design-system/src/components/index.tspackages/timo-design-system/src/components/tag/tag-name-input/TagNameInput.stories.tsxpackages/timo-design-system/src/components/tag/tag-name-input/TagNameInput.tsx
💤 Files with no reviewable changes (2)
- apps/timo-web/utils/format-date.ts
- apps/timo-web/app/[locale]/(main)/statistics/_utils/statistics-calendar.ts
- clickOutsideDeactivates: false가 트랩 바깥 클릭을 preventDefault/stopImmediatePropagation으로 완전히 삼켜 배경 클릭 onClose가 호출되지 않던 문제를 true로 바꿔 수정했습니다
- ariaLabel을 선택 prop에서 필수 prop으로 바꿔 모든 다이얼로그가 접근 가능한 이름을 갖도록 강제했습니다 - CreateTodoModalContent/CreateTagModalContainer 모두 이미 화면에 보이는 타이틀 텍스트를 ariaLabel로 전달하도록 했습니다
jjangminii
left a comment
There was a problem hiding this comment.
복잡한 로직이라 구현하기 힘들었을텐데 고생하셨습니다-!
코멘트 간단하게 한번만 확인해주세요~
| active={shouldRender} | ||
| focusTrapOptions={{ | ||
| escapeDeactivates: false, | ||
| clickOutsideDeactivates: true, |
There was a problem hiding this comment.
clickOutsideDeactivates 대신 allowOutsideClick은 어떨까요?
clickOutsideDeactivates: true는 "바깥 클릭 시 트랩만 해제"라서, 백드롭이 아닌 바깥 요소를 클릭하면 모달은 열려 있는데 포커스 트랩만 풀리는 상태가 될 수 있을 것 같아요. 이 상태에서 Tab을 누르면 모달 뒤 요소로 포커스가 빠져나가서 aria-modal과 실제 동작이 어긋나게 돼요.
tsxfocusTrapOptions={{
escapeDeactivates: false,
clickOutsideDeactivates: false,
allowOutsideClick: true, // 바깥 클릭 이벤트를 차단하지 않고 통과
fallbackFocus: () => dialogRef.current ?? document.body,
}}
allowOutsideClick: true를 쓰면 백드롭 onClick -> onClose -> 언마운트 흐름으로 트랩이 함께 정리돼서, 트랩 해제 시점이 항상 모달 언마운트에 묶이게 되는데 어떻게 생각하시나요?
There was a problem hiding this comment.
좋습니다! 해당 속성으로 변경해서 반영해 두었어요. 언마운트 흐름에서만 트랩이 해제되게 변경하는 게 좋을 것 같아요!
|
|
||
| onSubmit(data, { id: data.tagId ?? tag.id, name: tag.name }); | ||
|
|
||
| reset(createDefaultValues()); |
There was a problem hiding this comment.
지금은 제출 직후 모달이 닫혀서 티가 안 나지만, 인자가 없으면 날짜가 오늘로 리셋돼요. 예를 들어 7월 20일 컬럼에서 모달을 열었는데 리셋 후에는 오늘 날짜가 되는 거죠. 나중에 "연속 추가" 같은 UX가 들어오면 바로 버그로 드러날 수 있어서 미리 맞춰두면 좋을 것 같아요-!
There was a problem hiding this comment.
그렇네요. defaultValues 로 변경해 두었어요!
| </p> | ||
| <button | ||
| type="button" | ||
| aria-label={t("createModal.close")} |
There was a problem hiding this comment.
지금은 문자열이 같아서 문제없지만, 태그 모달이 투두 모달 키에 의존하는 구조라 나중에 createModal.close를 수정/삭제할 때 태그 모달까지 확인할 생각을 못 하게 될 것 같아요. "닫기"는 앞으로 모든 모달에서 쓸 테니 Common.close로 빼두면 어떨까요?
There was a problem hiding this comment.
전체 json 파일에 추가해서 반영해 두겠습니돵
| subtasks: (data.subtasks ?? []).map((content) => ({ | ||
| subtaskId: Date.now(), |
There was a problem hiding this comment.
| subtasks: (data.subtasks ?? []).map((content) => ({ | |
| subtaskId: Date.now(), | |
| .map((content, index) => ({ | |
| subtaskId: Date.now() + index, |
지금은 handleSubtaskInputChange가 배열에 최대 1개만 넣어서 잠재적 이슈지만, 코드 형태는 "여러 개를 처리하는 map"이라 나중에 subtask 다중 입력이 붙을 때 이 로직을 그대로 재사용하면 handleToggleSubtaskCompleted 같은 ID 기반 로직이 꼬일 수 있을 것 같아요-! Date.now() + index로만 바꿔도 방어가 될 수 있을 것 같은데 어떻게 생각하세요?
There was a problem hiding this comment.
미리 변경해 두는 게 좋을 것 같네요. 반영했습니댱!
ehye1
left a comment
There was a problem hiding this comment.
zod로 schema 하나에 타입이랑 검증을 같이 관리할 수 있어서 좋네요!!
동적으로 모달을 열 수 있게 하는 overlay-kit 라이브러리도 처음 알게됐어요
수고하셨습니다!!👍🏻👍🏻
- clickOutsideDeactivates를 false로, allowOutsideClick을 true로 변경해 트랩 해제가 onClose/언마운트 흐름에만 종속되도록 수정했습니다
- 제출 후 reset 시 defaultDate를 전달하지 않아 날짜가 오늘로 초기화되던 버그를 수정했습니다 - 닫기 버튼 aria-label을 Common.close 키로 통합하고 기존 Home.createModal.close는 제거했습니다
- subtaskId 생성에 index를 더해 다중 subtask 입력 시 Date.now() 충돌 가능성을 방지했습니다
ISSUE 🔗
close #137
What is this PR? 🔍
홈 화면에서 할 일을 생성·조회·정렬할 수 있는 투두 생성 모달과 투두 카드 UI를 구현했습니다.
배경
의존성
overlay-kit,@dnd-kit/modifiers의존성을 추가했습니다.overlay-kit이, 드래그를 세로 축으로 제한하기 위해@dnd-kit/modifiers가 필요했습니다.overlay.open()으로 모달의isOpen/close/unmount를 관리하고,DndContext의modifiersprop에restrictToVerticalAxis를 전달했습니다.디자인시스템 컴포넌트
IconSelector/IconGraphic/DateSelector/TagNameInput/TodoToolbar를 새로 추가하고, 기존PriorityIcon/PrioritySelector/RepeatSelector/TagSelector/TimeSelector를 모달 요구사항에 맞게 수정했습니다.API 스키마 및 오버레이 모달 인프라
createTodoRequestSchema)를 정의하고, 오버레이 기반Modal컴포넌트와OverlayProvider를 루트 레이아웃에 연결했습니다.date/duration포맷을 정규식으로 검증하고,repeatType에 따라repeatWeekdays/repeatDayOfMonth필수 여부를superRefine으로 처리했습니다.OverlayProvider는layout.tsx의QueryProvider내부에 배치했습니다.@repo/timo-design-system의Modal(Modal.Root+Trigger+Panel)은Trigger와Panel이 같은 트리에 선언되고isOpen을 내부 state로만 관리하는 비제어(uncontrolled) 컴파운드 컴포넌트입니다. 반면 이번 요구사항은overlay.open()으로 트리거와 무관한 위치(날짜 컬럼별 추가 버튼)에서 모달을 열고, 닫힘 애니메이션이 끝난 뒤에만unmount()를 호출해야 해서isOpen/onClose/onExited를 외부에서 제어할 수 있는 형태가 필요했습니다. 디자인시스템 Modal은 이 "외부 제어 + exit-aware unmount" 계약을 지원하지 않아 그대로 재사용할 수 없었고, 그래서apps/timo-web/components/modal/Modal.tsx를 앱 레이어에 별도로 만들어overlay-kit과 연결했습니다.홈 투두 생성 모달 및 투두 카드
todo-card/todo-modal/tag-modal기능 단위로 재구성했습니다._components/_containers/_hooks가 타입별로만 분리돼 있어 하나의 기능을 수정할 때 여러 폴더를 오가야 했고, 모달 폼도watch/setValue를 필드마다 직접 호출해 필드 하나가 바뀌어도 폼 전체가 리렌더되는 구조였습니다.useIconField/useTagField/useTimeField/useRepeatField각 훅이control을 받아 내부에서useController로 해당 폼 필드를 직접 구독하도록 바꿔, 컨테이너 컴포넌트는 훅이 반환한 값을 JSX에 배치하기만 하면 되도록 했습니다. 홈 투두 카드는@dnd-kit/sortable의useSortable로 정렬 가능하게 만들었고,restrictToVerticalAxis로 드래그 축을 세로로 제한했습니다. 디자인에 없던 카드 그랩(드래그 핸들) 아이콘은 제거했습니다.To Reviewers
CreateTodoModalContent의 필드 훅들이watch/setValue대신useController를 직접 구독하는 구조로 바뀌었으니, 필드별 리렌더링 범위가 의도대로 좁혀졌는지 봐주세요.투두/태그 API가 아직 없어
todoId/tagId채번과 저장이 클라이언트 로컬 상태로만 처리됩니다. 의도된 범위이며 후속 API 연동 PR에서 대체될 예정입니다.pnpm --filter timo-web check-types가 실패하는데,origin/develop에 이미 있는 온보딩 아이콘(export 누락) 문제로 이번 PR 변경사항과는 무관함을 확인했습니다.Screenshot 📷
Test Checklist ✔
pnpm --filter timo-web lint통과pnpm --filter @repo/timo-design-system check-types통과pnpm --filter @repo/timo-design-system lint통과pnpm --filter timo-web check-types— origin/develop에 이미 있는 온보딩 아이콘 export 누락 오류로 실패 (이번 PR과 무관함을 확인)pnpm build— 미실행