Skip to content

[FIX] Today 카드 서브태스크 완료가 상세 모달에 재동기화되지 않는 문제 수정#256

Merged
kimminna merged 2 commits into
developfrom
fix/web/255-subtask-modal-sync
Jul 16, 2026
Merged

[FIX] Today 카드 서브태스크 완료가 상세 모달에 재동기화되지 않는 문제 수정#256
kimminna merged 2 commits into
developfrom
fix/web/255-subtask-modal-sync

Conversation

@kimminna

Copy link
Copy Markdown
Member

ISSUE 🔗

close #255



What is this PR? 🔍

Today 카드에서 서브태스크 완료를 토글한 직후 상세 조회 모달을 열면 완료 상태가 반영되지 않던 문제를 수정했습니다.

배경

  • 기존 구조: useDetailSubtaskFieldsubtaskInputs는 모달 마운트 시 useState lazy initializer로 서버 subtasks를 한 번만 읽어와 초기화하고, 이후에는 자체 로컬 상태로만 관리됩니다.
  • 발생 문제: Today 카드에서 서브태스크를 완료 토글한 직후(뮤테이션이 아직 진행 중인 상태에서) 상세 모달을 열면, 모달의 최초 조회 요청이 완료 처리 요청보다 먼저 응답을 받아 옛 데이터로 폼이 초기화됩니다. 이후 완료 처리가 성공해 캐시가 무효화·재조회되어 todo.subtasks는 최신값으로 바뀌지만, 이미 초기화된 로컬 subtaskInputs는 재동기화 로직이 없어 계속 옛 값(미완료)에 머물렀습니다.
  • 해결 방향: 서버에서 다시 받아온 subtasks가 바뀔 때, 로컬 폼 상태의 완료 여부만 최신값으로 재동기화하는 effect를 추가했습니다.

서브태스크 완료 동기화

  • 변경 요약: useDetailSubtaskFieldsubtasks prop 변경을 감지해 subtaskInputscompleted 값만 재동기화하는 useEffect를 추가했습니다.
  • 이유: 로컬 폼 상태가 최초 마운트 시점의 서버 데이터에 고정되어, 이후 쿼리가 갱신되어도 체크박스 표시가 따라가지 못했기 때문입니다.
  • 구현 방식: subtasks 배열이 바뀔 때마다 subtaskId로 매칭되는 서버 서브태스크를 찾아 completed 값이 다르면 해당 항목만 갱신합니다. 텍스트(value)와 아직 저장되지 않은 로컬 입력행(subtaskId: null)은 건드리지 않아, 사용자가 입력 중인 텍스트가 덮어써지지 않도록 했습니다.
  • 경계 · 제약: 이번 수정은 서브태스크 완료 상태 재동기화에 한정됩니다. 텍스트 편집 동기화나 메인 투두 완료 체크박스의 동일 계열 이슈는 이번 범위에서 다루지 않았습니다.



To Reviewers

로컬 폼 상태(subtaskInputs)와 서버 쿼리 데이터(todo.subtasks) 사이의 재동기화 시점이 올바른지, 특히 사용자가 서브태스크 텍스트를 편집 중인 상태에서 completed만 갱신되는 게 의도대로 동작하는지 확인 부탁드립니다.

Screenshot 📷



Test Checklist ✔

  • pnpm check-types 통과
  • pnpm lint 통과
  • pnpm build — 미실행: CI에서 확인 예정
  • Today 카드 서브태스크 완료 토글 직후 상세 모달 오픈 시나리오 수동 확인 — 후속 확인 필요

- Today 카드에서 서브태스크를 완료 토글한 직후 상세 모달을 열면, 모달의 첫 조회가 완료 처리 요청보다 먼저 끝나 옛 데이터로 폼이 초기화되는 문제가 있었습니다
- useDetailSubtaskField의 subtaskInputs가 마운트 시 한 번만 초기화되고 이후 재동기화되지 않아, 서버 데이터가 나중에 갱신되어도 체크박스가 계속 옛 값에 머물렀습니다
- 서버에서 받아온 subtasks가 바뀔 때 완료 여부만 로컬 폼 상태에 재동기화하는 effect를 추가했습니다
@vercel

vercel Bot commented Jul 16, 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 7:16am

Request Review

@github-actions github-actions Bot added the ⏰ Timo-web Timo 웹 서비스 label Jul 16, 2026
@github-actions github-actions Bot added 🐛 Bug 기능이 정상적으로 작동하지 않는 문제 수정 ♦️ 민아 민아상 labels Jul 16, 2026
@coderabbitai

coderabbitai Bot commented Jul 16, 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: 38 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: 72307ef9-affd-4847-8f81-39994e815d2a

📥 Commits

Reviewing files that changed from the base of the PR and between dfb4c7c and 3f3df54.

📒 Files selected for processing (1)
  • apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_components/todo-card/HomeTodoCard.tsx

Walkthrough

subtasks 변경 시 상세 모달의 로컬 서브태스크 완료 상태를 서버 값과 동기화하는 useEffect가 추가되었습니다.

Changes

서브태스크 상태 동기화

Layer / File(s) Summary
서버 완료 상태와 로컬 입력 동기화
apps/timo-web/hooks/todo-modal/detail/use-detail-subtask-field.ts
subtaskId로 서버 서브태스크를 찾아 완료 여부가 다를 때 로컬 completed 값을 갱신합니다.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • Team-Timo/Timo-client#190: 상세 서브태스크 입력과 완료 상태를 관리하는 훅의 기존 구현과 직접 연결됩니다.
  • Team-Timo/Timo-client#203: 수정 모달의 서브태스크 완료 상태 동기화 흐름과 관련됩니다.

Suggested reviewers: jjangminii

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 Today 서브태스크 완료 상태 재동기화 문제를 정확히 요약합니다.
Description check ✅ Passed 설명이 상세 모달의 완료 상태 재동기화 버그와 수정 방향을 명확히 설명해 변경과 잘 맞습니다.
Linked Issues check ✅ Passed 직접 링크된 #255의 기대 결과인 모달에서 방금 완료한 서브태스크를 올바르게 표시하는 동작을 구현했습니다.
Out of Scope Changes check ✅ Passed 변경은 useDetailSubtaskField의 완료 상태 동기화에 한정되어 요구 범위를 벗어난 추가 작업이 보이지 않습니다.
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/255-subtask-modal-sync

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 16, 2026

Copy link
Copy Markdown

Timo Performance Report

Bundle Size — timo-web
라우트 크기 First Load JS
/[locale]/home 212.39 kB 🔴 418.25 kB
/[locale]/today 196.57 kB 🔴 402.44 kB
/[locale]/focus 161.02 kB 🔴 366.88 kB
/[locale]/settings 167.61 kB 🔴 373.47 kB
/[locale]/statistics 154.90 kB 🔴 360.76 kB
/[locale]/[...rest] 0 B 🟡 205.87 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.98 kB
/robots.txt/route 0 B 🟡 205.87 kB
/sitemap.xml/route 0 B 🟡 205.87 kB

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

Lighthouse — timo-web
URL Perf A11y LCP CLS TBT
/en/home 🔴 59 🟢 95 🔴 15.6s 🟢 0.000 🟡 597ms
/en/today 🔴 59 🟢 95 🔴 15.6s 🟢 0.000 🟡 588ms
/en/focus 🔴 61 🟢 95 🔴 15.3s 🟢 0.000 🟡 538ms
/en/statistics 🔴 60 🟢 95 🔴 15.3s 🟢 0.000 🟡 571ms

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 변환 권장

측정 커밋: acb2100

@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: 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/hooks/todo-modal/detail/use-detail-subtask-field.ts`:
- Around line 43-56: Update the state updater in the useEffect synchronization
for subtasks to track whether any completed value changes; return the original
prev reference when no matching subtask requires an update, and only return a
new mapped array when at least one value changes.
🪄 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: 0fd604c3-0e5d-4f95-917f-3a9a5f1d318d

📥 Commits

Reviewing files that changed from the base of the PR and between 3cc33b4 and dfb4c7c.

📒 Files selected for processing (1)
  • apps/timo-web/hooks/todo-modal/detail/use-detail-subtask-field.ts

Comment on lines +43 to +56
useEffect(() => {
setSubtaskInputs((prev) =>
prev.map((input) => {
const serverSubtask = subtasks.find(
(subtask) => subtask.subtaskId === input.subtaskId,
);
if (!serverSubtask || serverSubtask.completed === input.completed) {
return input;
}
return { ...input, completed: serverSubtask.completed };
}),
);
}, [subtasks]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

불필요한 재렌더링을 방지하도록 상태 업데이트 로직 개선

서브태스크 동기화 로직, 필요한 부분만 잘 캐치해서 작성해주셨네요! 센스 최고예요! 👏

현재 prev.map을 사용하면 실제 completed 값이 변경되지 않았더라도 항상 새로운 배열이 생성되어 반환됩니다. 이로 인해 subtasks 배열의 참조가 바뀔 때마다 상태가 업데이트되어 불필요한 재렌더링이 발생할 수 있습니다.

상태를 업데이트할 때 실제 변경 사항이 있는지를 추적하여, 변경이 없을 경우에는 이전 상태(prev)의 참조를 그대로 반환하도록 개선하면 React가 렌더링을 건너뛰게 할 수 있습니다.

관련해서는 React 공식 문서: State 업데이트 건너뛰기를 참고해 보시면 더 깊이 이해하는 데 도움이 될 거예요!

💡 재렌더링 방지를 위한 개선 제안
   useEffect(() => {
-    setSubtaskInputs((prev) =>
-      prev.map((input) => {
+    setSubtaskInputs((prev) => {
+      let hasChanges = false;
+      const next = prev.map((input) => {
         const serverSubtask = subtasks.find(
           (subtask) => subtask.subtaskId === input.subtaskId,
         );
         if (!serverSubtask || serverSubtask.completed === input.completed) {
           return input;
         }
+        hasChanges = true;
         return { ...input, completed: serverSubtask.completed };
-      }),
-    );
+      });
+      return hasChanges ? next : prev;
+    });
   }, [subtasks]);
📝 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
useEffect(() => {
setSubtaskInputs((prev) =>
prev.map((input) => {
const serverSubtask = subtasks.find(
(subtask) => subtask.subtaskId === input.subtaskId,
);
if (!serverSubtask || serverSubtask.completed === input.completed) {
return input;
}
return { ...input, completed: serverSubtask.completed };
}),
);
}, [subtasks]);
useEffect(() => {
setSubtaskInputs((prev) => {
let hasChanges = false;
const next = prev.map((input) => {
const serverSubtask = subtasks.find(
(subtask) => subtask.subtaskId === input.subtaskId,
);
if (!serverSubtask || serverSubtask.completed === input.completed) {
return input;
}
hasChanges = true;
return { ...input, completed: serverSubtask.completed };
});
return hasChanges ? next : prev;
});
}, [subtasks]);
🤖 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/hooks/todo-modal/detail/use-detail-subtask-field.ts` around
lines 43 - 56, Update the state updater in the useEffect synchronization for
subtasks to track whether any completed value changes; return the original prev
reference when no matching subtask requires an update, and only return a new
mapped array when at least one value changes.

@ehye1 ehye1 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.

굿굿 subtask가 업데이트가 안되고 있었군요
오류 수정 감사합니다!!

- 체크박스가 checked 상태일 때만 렌더링되는 체크마크 아이콘이 SVGElement라서 HTMLElement의 인스턴스가 아니었습니다
- isInteractiveElement가 target instanceof HTMLElement로 검사해, 체크 해제를 위해 체크마크를 직접 클릭하면 인터랙티브 요소로 인식하지 못하고 카드 클릭(상세 모달 오픈)으로 새어나갔습니다
- instanceof Element로 변경해 HTML/SVG 요소 모두 정상적으로 감지하도록 했습니다

@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.

서브테스크 오늘/홈/수정모달/포커스 각각 동기화 되는 것 확인 했습니다.

@kimminna
kimminna merged commit 6615042 into develop Jul 16, 2026
11 checks passed
@kimminna
kimminna deleted the fix/web/255-subtask-modal-sync branch July 16, 2026 07:57
@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-web Timo 웹 서비스 ♦️ 민아 민아상 🐛 Bug 기능이 정상적으로 작동하지 않는 문제 수정

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FIX] Today 카드 서브태스크 완료가 상세 모달에 재동기화되지 않는 문제 수정

3 participants