Skip to content

[FIX] 투두 편집 관련 버그 3건 수정 (반복 선택, 에러 토스트, 모달 오버플로우)#247

Merged
kimminna merged 7 commits into
developfrom
fix/web/246-todo-edit-bugs
Jul 16, 2026
Merged

[FIX] 투두 편집 관련 버그 3건 수정 (반복 선택, 에러 토스트, 모달 오버플로우)#247
kimminna merged 7 commits into
developfrom
fix/web/246-todo-edit-bugs

Conversation

@kimminna

Copy link
Copy Markdown
Member

ISSUE 🔗

close #246



What is this PR? 🔍

투두 편집 플로우에서 발견된 서로 다른 세 가지 버그를 모아 수정했습니다. 반복 선택자의 "매일" 선택 무반응, 홈/투데이 뷰 수정 실패 시 무음 실패, 상세 모달이 뷰포트를 넘을 때의 오버플로우/드롭다운 잘림 문제를 각각 고쳤습니다.

배경

  • 기존 구조: 세 화면 모두 겉보기엔 정상 동작하는 것처럼 보이지만, 특정 조건(반복 비활성 상태에서 매일 선택, 서버 400 응답, 모달이 뷰포트보다 큰 경우)에서만 드러나는 버그였습니다.
  • 발생 문제: 사용자가 조작해도 아무 피드백 없이 조용히 원래 상태로 돌아가거나(반복 선택, 에러 토스트), 레이아웃이 깨지는(모달) 형태로 나타났습니다.
  • 해결 방향: 각 버그의 근본 원인을 추적해 최소 변경으로 수정하고, 기존에 이미 존재하던 에러 토스트/스크롤 패턴을 최대한 재사용했습니다.

반복 선택자 "매일" 선택 버그

  • 변경 요약: RepeatSelector가 반복 활성 여부(isActive)를 알 수 있도록 하고, 사용자가 실제로 클릭했는지를 추적해 반복을 처음 활성화하는 경우에도 커밋되도록 했습니다.
  • 이유: 반복이 꺼져 있을 때도 frequency는 기본값 "DAILY"로 채워져 있는데, 닫을 때의 커밋 조건이 draftFrequency !== frequency만 검사해서 "이미 DAILY인데 DAILY를 또 선택"한 것으로 오인해 onFrequencyChange를 호출하지 않았습니다. WEEKLY/MONTHLY는 기본값과 다르므로 우연히 정상 동작했습니다.
  • 구현 방식: hasSelectedFrequencyRef로 드롭다운이 열려 있는 동안 사용자가 주기를 실제로 클릭했는지 추적합니다. 닫을 때 커밋 조건을 클릭했음 && (값이 바뀜 || 이전에 비활성이었음)으로 바꿔, 값 자체는 같아도 반복을 새로 켜는 경우엔 반드시 onFrequencyChange가 호출되도록 했습니다. TodoToolbar가 아이콘 표시에만 쓰던 isRepeatActiveRepeatSelector로 함께 전달합니다.
  • 경계 · 제약: 요일/월간 반복일 커밋 로직은 기존과 동일하게 유지했습니다.

홈/투데이 뷰 수정 실패 시 에러 토스트 누락

  • 변경 요약: 완료 토글, 서브태스크 토글, 순서 변경 실패 시 서버가 내려준 에러 메시지를 토스트로 표시하도록 했습니다.
  • 이유: 세 mutation 모두 실패 시 로컬 상태만 원래대로 되돌리고 사용자에게 아무 메시지도 보여주지 않아, 매일 반복 투두의 날짜 변경 제한(400 TODO_400) 같은 서버 검증 실패가 조용히 무시되는 것처럼 보였습니다.
  • 구현 방식: useHomeTodosByDate/useTodayTodoListonUpdateError 콜백을 추가하고, 각 mutation의 onError에서 error.response?.data.message를 그대로 전달합니다. 상위 컨테이너에서는 이미 있던 playErrorMessage 상태와 AnimatedToast를 재사용해 표시하며, 메시지가 없으면 Toast.todoUpdateFailed로 폴백합니다. 상세 모달 내부 수정(DetailTodoModalContainer)은 이미 동일한 방식의 에러 토스트가 연결되어 있어 이번 변경 대상에서 제외했습니다.
  • 경계 · 제약: 없음.

상세 모달 오버플로우 / 드롭다운 잘림

  • 변경 요약: OverlayModal의 다이얼로그 위치 방식을 뷰포트 중앙 고정에서, 뷰포트 전체를 덮는 스크롤 래퍼 + flex 중앙 정렬 방식으로 바꿨습니다.
  • 이유: 기존에는 fixed top-1/2 left-1/2 -translate-*로 뷰포트 정중앙에 고정돼 있어, 모달 콘텐츠가 뷰포트보다 커지면 위아래로 잘린 채 스크롤할 방법이 없었습니다. 처음에 모달 박스 자체에 max-h-[90vh] overflow-y-auto를 주는 방식으로 시도했으나, 그러면 모달 내부의 날짜/우선순위 드롭다운(Dropdown.Panel, position: absolute)이 모달 박스의 스크롤 경계에 잘려 밖으로 열리지 못하는 회귀가 생겨 되돌렸습니다.
  • 구현 방식: fixed inset-0 overflow-y-auto 래퍼가 뷰포트 전체 크기이므로 평소(모달이 뷰포트보다 작을 때)는 스크롤이 전혀 발생하지 않아 드롭다운도 그대로 밖으로 열립니다. 모달이 뷰포트보다 커질 때만 이 래퍼가 스크롤 가능해집니다. 배경 클릭으로 닫는 로직을 이 래퍼 안쪽 flex 컨테이너로 옮기고(event.target === event.currentTarget으로 빈 여백 클릭만 판별), 기존 backdrop div의 가려져서 동작하지 않던 클릭 핸들러는 정리했습니다. 새로 추가한 클릭 핸들러는 aria-hidden 처리를 할 수 없는 위치(실제 다이얼로그를 감싸는 요소)라 jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events를 의도적으로 예외 처리했습니다. 키보드 사용자는 기존 Escape 핸들러로 동일하게 닫을 수 있습니다.
  • 경계 · 제약: apps/timo-web/components/modal/OverlayModal.tsx 한 곳만 변경했고, 이 컴포넌트를 쓰는 투두 상세/생성, 회원탈퇴, 태그 생성 모달 4곳 모두에 공통 적용됩니다.

기타

  • DropdownView.tsx의 드롭다운 아이템 좌우 패딩(px-1.5)을 제거했습니다.



To Reviewers

OverlayModal 변경은 공용 컴포넌트라 투두 상세/생성, 회원탈퇴, 태그 생성 모달 4곳 전부에 영향을 줍니다. 특히 드롭다운이 모달 밖으로 정상적으로 열리는지, 배경 클릭으로 닫히는 동작이 예전과 동일한지 확인 부탁드립니다.
반복 선택자 수정은 "반복이 꺼진 상태에서 매일을 선택" 케이스가 핵심이니 그 시나리오 위주로 봐주시면 좋겠습니다.
이번 세션 안에서 브라우저로 직접 조작해보지는 못했고, 코드 추적과 타입체크/린트로만 검증했습니다. 리뷰 시 실제 화면에서 한 번씩 확인 부탁드립니다.



Screenshot 📷



Test Checklist ✔

  • pnpm check-types 통과
  • pnpm lint 통과
  • 반복 선택자 "매일" 선택 → 저장 확인 — 미실행: 브라우저 미확인
  • 매일 반복 투두 순서변경/완료토글 실패 시 에러 토스트 확인 — 미실행: 브라우저 미확인
  • 서브태스크 많은 투두 상세 모달 오버플로우 시 스크롤/드롭다운 확인 — 미실행: 브라우저 미확인

kimminna added 4 commits July 16, 2026 04:55
- 반복 비활성 상태에서 frequency 기본값이 "DAILY"로 채워져 있어 "매일"을 선택해도 변경 없음으로 판단되던 문제를 수정했습니다
- RepeatSelector에 isActive prop을 추가해 반복 활성 여부를 함께 판단하도록 했습니다
- 사용자가 실제로 항목을 클릭했는지 추적해, 값이 기본값과 같아도 반복을 처음 활성화하는 경우엔 반드시 커밋하도록 했습니다
- TodoToolbar가 이미 갖고 있던 isRepeatActive를 RepeatSelector로 전달하도록 했습니다
- 완료 토글, 서브태스크 토글, 순서 변경 실패 시 로컬 상태만 되돌리고 사용자에게 아무 메시지도 보여주지 않던 문제를 수정했습니다
- onUpdateError 콜백을 추가해 서버가 내려준 에러 메시지(error.response.data.message)를 그대로 토스트로 노출하도록 했습니다
- 메시지가 없을 때는 todoUpdateFailed 문구로 폴백하도록 했습니다
- 모달 콘텐츠가 뷰포트보다 커지면 화면 밖으로 잘리던 문제를 수정했습니다
- 다이얼로그를 뷰포트 전체를 덮는 스크롤 래퍼와 flex 중앙 정렬 컨테이너로 감싸, 콘텐츠가 뷰포트보다 클 때만 래퍼가 스크롤되도록 했습니다
- 모달 박스 자체에는 overflow 제약을 두지 않아, 내부 드롭다운(날짜/우선순위 등)이 모달 경계에 잘리지 않고 정상적으로 열리도록 했습니다
- 배경 클릭으로 닫는 로직을 새 스크롤 래퍼로 옮기고, 가려져서 동작하지 않던 기존 backdrop의 클릭 핸들러를 정리했습니다
- DropdownView 아이템의 좌우 패딩(px-1.5)을 제거했습니다
@vercel

vercel Bot commented Jul 15, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
timo Ready Ready Preview, Comment Jul 16, 2026 6:07am

Request Review

@github-actions github-actions Bot added ⏰ Timo-web Timo 웹 서비스 ⌚ Timo-Design-system Timo 디자인 시스템 labels Jul 15, 2026
@github-actions github-actions Bot added 🐛 Bug 기능이 정상적으로 작동하지 않는 문제 수정 ♦️ 민아 민아상 labels Jul 15, 2026
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@kimminna, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 11 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 87a47032-a8ca-4c81-9a4f-3db5d15e8480

📥 Commits

Reviewing files that changed from the base of the PR and between 1306460 and 99c0377.

📒 Files selected for processing (8)
  • apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx
  • apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-todos-by-date.ts
  • apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoListContainer.tsx
  • apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/useTodayTodoList.ts
  • apps/timo-web/app/[locale]/(main)/focus/_hooks/use-focus-session.ts
  • apps/timo-web/components/layout/sidebar/time/TimerPanel.tsx
  • apps/timo-web/components/modal/OverlayModal.tsx
  • apps/timo-web/hooks/timer/use-timer-query-invalidation.ts

Walkthrough

투두 업데이트 실패 시 롤백과 서버 메시지 전달을 추가하고, 반복 선택 저장 조건을 보완했습니다. 모달의 외부 클릭·스크롤 레이아웃과 드롭다운 항목 여백도 수정했습니다.

Changes

투두 편집 버그 수정

Layer / File(s) Summary
투두 업데이트 오류 피드백
apps/timo-web/.../home/_hooks/use-home-todos-by-date.ts, apps/timo-web/.../today/_hooks/useTodayTodoList.ts, apps/timo-web/.../*TodoContainer.tsx
완료 토글, 서브태스크 토글, 재정렬 실패 시 이전 상태로 복원하고 서버 오류 메시지를 토스트 상태로 전달합니다.
반복 주파수 선택 커밋
packages/timo-design-system/src/components/repeat/repeat-selector/RepeatSelector.tsx, packages/timo-design-system/src/components/todo/todo-toolbar/TodoToolbar.tsx
반복 선택 여부와 활성 상태를 추적해 DAILY가 기존 값이어도 사용자가 선택하면 변경 콜백을 호출합니다.
모달 및 드롭다운 레이아웃
apps/timo-web/components/modal/OverlayModal.tsx, packages/timo-design-system/src/components/dropdown-view/DropdownView.tsx
모달 외부 클릭 닫기와 중앙 정렬 래퍼를 변경하고, 드롭다운 항목의 좌우 여백을 세로 여백으로 조정했습니다.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related issues

Possibly related PRs

Suggested labels: ♻ Refactor

Suggested reviewers: yumin-kim2, jjangminii, ehye1

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning DropdownView의 좌우 패딩 제거는 #246의 세 가지 버그 수정 목표와 직접 관련이 없어 범위를 벗어납니다. 해당 스타일 변경은 별도 PR로 분리하거나, 이슈 범위에 맞게 필요한 경우만 유지하세요.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 반복 선택, 에러 토스트, 모달 오버플로우 수정이라는 핵심 변경을 잘 요약합니다.
Description check ✅ Passed 설명이 PR의 세 가지 버그 수정 내용과 일치해 관련성이 높습니다.
Linked Issues check ✅ Passed 연결된 #246의 반복 선택, 실패 토스트, 모달 스크롤/드롭다운 문제를 모두 해결하는 변경이 포함되어 있습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/web/246-todo-edit-bugs

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

❤️ Share

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

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

Storybook Preview

항목 링크
Storybook 열기
Chromatic 빌드 확인

마지막 업데이트: 2026-07-16 06:06 UTC

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

Timo Performance Report

Bundle Size — timo-web
라우트 크기 First Load JS
/[locale]/home 212.29 kB 🔴 418.16 kB
/[locale]/today 196.47 kB 🔴 402.33 kB
/[locale]/focus 161.02 kB 🔴 366.88 kB
/[locale]/settings 167.55 kB 🔴 373.41 kB
/[locale]/statistics 154.90 kB 🔴 360.76 kB
/[locale]/[...rest] 0 B 🟡 205.86 kB
/[locale]/login 212.98 kB 🔴 418.84 kB
/[locale]/oauth/callback 119.67 kB 🟡 325.54 kB
/[locale]/onboarding 233.49 kB 🔴 439.35 kB
/[locale] 118.99 kB 🟡 324.85 kB
/[locale]/policy 125.11 kB 🟡 330.97 kB

공유 번들: 205.86 kB
🟢 < 200kB  |  🟡 < 350kB  |  🔴 ≥ 350kB (First Load JS · gzip)

Lighthouse — timo-web
URL Perf A11y LCP CLS TBT
/en/home 🔴 67 🟢 95 🔴 15.8s 🟢 0.000 🟡 337ms
/en/today 🔴 61 🟢 95 🔴 15.6s 🟢 0.000 🟡 513ms
/en/focus 🔴 61 🟢 95 🔴 15.3s 🟢 0.000 🟡 511ms
/en/statistics 🔴 63 🟢 95 🔴 15.3s 🟢 0.000 🟡 479ms

Perf ≥ 70 / A11y ≥ 85 목표
LCP 🟢 < 2.5s 🟡 < 4s 🔴 ≥ 4s  |  CLS 🟢 < 0.1 🟡 < 0.25 🔴 ≥ 0.25  |  TBT 🟢 < 200ms 🟡 < 600ms 🔴 ≥ 600ms

Image Optimization — timo-web
파일 크기 포맷 상태
favicon.png 27.84 kB PNG ⚠️ 🟢
images/google-calendar.png 36.20 kB PNG ⚠️ 🟢
images/google-logo.png 26.79 kB PNG ⚠️ 🟢
og.png 437.44 kB PNG ⚠️ 🟡

총 4개 · 528.28 kB  |  🟢 < 200KB  |  🟡 < 500KB  |  🔴 ≥ 500KB
⚠️ 4개 파일 WebP/AVIF 변환 권장

측정 커밋: 34a8d77

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/timo-design-system/src/components/dropdown-view/DropdownView.tsx (1)

47-59: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

시맨틱한 DOM 구조와 접근성 향상을 위해 border-b 사용을 제안해요.

드롭다운 아이템의 불필요한 여백을 깔끔하게 정리해주셨네요! ✨

추가적으로, 접근성(A11y) 관점에서 작은 개선을 제안드립니다. role="listbox"를 가진 부모(Dropdown.Panel) 내부에는 role="option" 역할을 하는 요소들만 직접적인 자식(논리적 구조상)으로 배치되는 것이 스크린 리더 환경에서 가장 이상적입니다.

현재처럼 별도의 div를 구분선으로 사용하기보다는, 마지막 아이템을 제외한 Dropdown.Item 자체에 border-b 스타일을 추가하면 DOM 구조도 단순해지고 접근성도 한층 더 좋아집니다. ARIA Listbox 패턴 가이드를 함께 살펴보시면 실무에 활용하기 좋으실 거예요! 📚

🛠️ 제안하는 리팩토링 코드
-            <Fragment key={item}>
-              <Dropdown.Item
-                role="option"
-                aria-selected={isSelected}
-                onClick={() => onChange(item)}
-                className="typo-body-m-12 text-timo-gray-900 py-1"
-              >
-                {item}
-              </Dropdown.Item>
-              {i < items.length - 1 && (
-                <div className="bg-timo-gray-500 h-px w-full" />
-              )}
-            </Fragment>
+            <Dropdown.Item
+              key={item}
+              role="option"
+              aria-selected={isSelected}
+              onClick={() => onChange(item)}
+              className={cn(
+                "typo-body-m-12 text-timo-gray-900 py-1",
+                i < items.length - 1 && "border-timo-gray-500 border-b",
+              )}
+            >
+              {item}
+            </Dropdown.Item>
🤖 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 `@packages/timo-design-system/src/components/dropdown-view/DropdownView.tsx`
around lines 47 - 59, Update the DropdownView item rendering to remove the
separate divider div and apply the equivalent border-b styling directly to each
Dropdown.Item except the last item. Preserve the existing role="option",
selection behavior, and spacing while ensuring Dropdown.Panel has only option
elements as direct children.
🤖 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)/today/_hooks/useTodayTodoList.ts:
- Around line 102-104: Update the onError handler in the today todo mutation to
avoid restoring the entire previous array; use a functional setTodos update that
reverts only the specific todo changed by the failed request while preserving
concurrent edits to other todos, then keep the existing onUpdateError call.

In `@apps/timo-web/components/modal/OverlayModal.tsx`:
- Around line 99-121: Update the modal layout around the wrapper div and
dialogRef element: remove the parent’s items-center and justify-center alignment
classes, and add m-auto to the dialog’s className composition. Preserve the
existing visibility, sizing, and transition classes so small modals remain
centered while oversized content can scroll from the top.

---

Outside diff comments:
In `@packages/timo-design-system/src/components/dropdown-view/DropdownView.tsx`:
- Around line 47-59: Update the DropdownView item rendering to remove the
separate divider div and apply the equivalent border-b styling directly to each
Dropdown.Item except the last item. Preserve the existing role="option",
selection behavior, and spacing while ensuring Dropdown.Panel has only option
elements as direct children.
🪄 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: 904ece68-d582-43eb-a591-f396241c51a0

📥 Commits

Reviewing files that changed from the base of the PR and between dd18e8a and 1306460.

📒 Files selected for processing (8)
  • apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_containers/HomeTodoContainer.tsx
  • apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-todos-by-date.ts
  • apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_containers/TodayTodoListContainer.tsx
  • apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/today/_hooks/useTodayTodoList.ts
  • apps/timo-web/components/modal/OverlayModal.tsx
  • packages/timo-design-system/src/components/dropdown-view/DropdownView.tsx
  • packages/timo-design-system/src/components/repeat/repeat-selector/RepeatSelector.tsx
  • packages/timo-design-system/src/components/todo/todo-toolbar/TodoToolbar.tsx

Comment on lines +102 to +104
onError: (error: ErrorType<ErrorDto>) => {
setTodos(previous);
onUpdateError(error.response?.data.message);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

상태 롤백 시 동시 업데이트(Concurrent Update) 유실을 방지해 보세요.

에러 발생 시 previous 배열 전체로 상태를 덮어씌우면, 서버 요청이 진행되는 동안 사용자가 다른 투두를 수정했을 때 그 변경 사항까지 함께 날아갈 수 있습니다. 배열 전체를 되돌리기보다는, 변경을 시도했던 특정 투두의 상태만 함수형 업데이트(setTodos((prev) => ...))로 원상 복구하는 방식이 더 안전합니다. 😊

(공식 문서 참고: React State Updates)

Also applies to: 214-216

🤖 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)/today/_hooks/useTodayTodoList.ts
around lines 102 - 104, Update the onError handler in the today todo mutation to
avoid restoring the entire previous array; use a functional setTodos update that
reverts only the specific todo changed by the failed request while preserving
concurrent edits to other todos, then keep the existing onUpdateError call.

Comment on lines +99 to +121
<div
className="flex min-h-full items-center justify-center py-8"
onPointerDownCapture={() => {
wasFloatingLayerOpenRef.current = hasOpenFloatingLayer();
}}
onClick={(event) => {
if (event.target !== event.currentTarget) return;
if (wasFloatingLayerOpenRef.current) return;
onClose();
}}
>
<div
ref={dialogRef}
role="dialog"
aria-modal="true"
aria-label={ariaLabel}
tabIndex={-1}
className={cn(
"flex flex-col rounded-[4px] bg-white transition-all duration-200 ease-out",
isVisible ? "scale-100 opacity-100" : "scale-95 opacity-0",
className,
)}
>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Flexbox의 콘텐츠 잘림 현상을 방지하기 위해 m-auto 활용을 추천해요.

모달이 뷰포트보다 길어질 때 잘리는 문제를 해결하기 위해 flex 레이아웃을 도입하신 점 멋집니다! 👍

다만, 부모 요소에 items-centerjustify-center를 사용하면 내부 콘텐츠가 뷰포트보다 길어질 때 위쪽(Top) 영역이 화면 밖으로 잘려서 스크롤로도 도달할 수 없는 CSS Flexbox의 고질적인 문제가 발생할 수 있어요.

이를 방지하려면 부모의 items-center justify-center를 제거하고, 자식 요소(모달창)에 m-auto를 부여하는 방식을 제안합니다. 이렇게 하면 모달이 작을 때는 완벽하게 중앙 정렬되고, 길어지면 자연스럽게 상단부터 스크롤되도록 만들 수 있습니다. 💡

접근성 및 Flexbox 동작에 대한 MDN 문서도 참고해 보시면 레이아웃 설계에 큰 도움이 될 거예요!

✨ 제안하는 CSS 레이아웃 수정안
-          <div
-            className="flex min-h-full items-center justify-center py-8"
-            onPointerDownCapture={() => {
-              wasFloatingLayerOpenRef.current = hasOpenFloatingLayer();
-            }}
-            onClick={(event) => {
-              if (event.target !== event.currentTarget) return;
-              if (wasFloatingLayerOpenRef.current) return;
-              onClose();
-            }}
-          >
-            <div
-              ref={dialogRef}
-              role="dialog"
-              aria-modal="true"
-              aria-label={ariaLabel}
-              tabIndex={-1}
-              className={cn(
-                "flex flex-col rounded-[4px] bg-white transition-all duration-200 ease-out",
-                isVisible ? "scale-100 opacity-100" : "scale-95 opacity-0",
-                className,
-              )}
-            >
+          <div
+            className="flex min-h-full py-8"
+            onPointerDownCapture={() => {
+              wasFloatingLayerOpenRef.current = hasOpenFloatingLayer();
+            }}
+            onClick={(event) => {
+              if (event.target !== event.currentTarget) return;
+              if (wasFloatingLayerOpenRef.current) return;
+              onClose();
+            }}
+          >
+            <div
+              ref={dialogRef}
+              role="dialog"
+              aria-modal="true"
+              aria-label={ariaLabel}
+              tabIndex={-1}
+              className={cn(
+                "m-auto flex flex-col rounded-[4px] bg-white transition-all duration-200 ease-out",
+                isVisible ? "scale-100 opacity-100" : "scale-95 opacity-0",
+                className,
+              )}
+            >
📝 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.

Suggested change
<div
className="flex min-h-full items-center justify-center py-8"
onPointerDownCapture={() => {
wasFloatingLayerOpenRef.current = hasOpenFloatingLayer();
}}
onClick={(event) => {
if (event.target !== event.currentTarget) return;
if (wasFloatingLayerOpenRef.current) return;
onClose();
}}
>
<div
ref={dialogRef}
role="dialog"
aria-modal="true"
aria-label={ariaLabel}
tabIndex={-1}
className={cn(
"flex flex-col rounded-[4px] bg-white transition-all duration-200 ease-out",
isVisible ? "scale-100 opacity-100" : "scale-95 opacity-0",
className,
)}
>
<div
className="flex min-h-full py-8"
onPointerDownCapture={() => {
wasFloatingLayerOpenRef.current = hasOpenFloatingLayer();
}}
onClick={(event) => {
if (event.target !== event.currentTarget) return;
if (wasFloatingLayerOpenRef.current) return;
onClose();
}}
>
<div
ref={dialogRef}
role="dialog"
aria-modal="true"
aria-label={ariaLabel}
tabIndex={-1}
className={cn(
"m-auto flex flex-col rounded-[4px] bg-white transition-all duration-200 ease-out",
isVisible ? "scale-100 opacity-100" : "scale-95 opacity-0",
className,
)}
>
🤖 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 99 - 121,
Update the modal layout around the wrapper div and dialogRef element: remove the
parent’s items-center and justify-center alignment classes, and add m-auto to
the dialog’s className composition. Preserve the existing visibility, sizing,
and transition classes so small modals remain centered while oversized content
can scroll from the top.

- 타이머 완료·정지 성공 시 투두 상세 조회 쿼리 캐시를 무효화하지 않았습니다
- 조회 모달을 열어둔 채 타이머가 끝나도 timerStatus가 갱신되지 않아 편집이 계속 막히는 문제를 해결했습니다

@jjangminii jjangminii left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

checkout 해서 테스트 완료했습니다~ 굿!

@kimminna kimminna merged commit d686aa2 into develop Jul 16, 2026
14 checks passed
@kimminna kimminna deleted the fix/web/246-todo-edit-bugs branch July 16, 2026 06:17
@kimminna kimminna mentioned this pull request Jul 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⌚ Timo-Design-system Timo 디자인 시스템 ⏰ Timo-web Timo 웹 서비스 ♦️ 민아 민아상 🐛 Bug 기능이 정상적으로 작동하지 않는 문제 수정 🚬 QA QA 반영

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FIX] 투두 편집 관련 버그 3건 수정 (반복 선택, 에러 토스트, 모달 오버플로우)

2 participants