Skip to content

[FIX] 통계 페이지 QA 반영#233

Open
yumin-kim2 wants to merge 7 commits into
developfrom
fix/web/222-statistics-layout
Open

[FIX] 통계 페이지 QA 반영#233
yumin-kim2 wants to merge 7 commits into
developfrom
fix/web/222-statistics-layout

Conversation

@yumin-kim2

@yumin-kim2 yumin-kim2 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

ISSUE 🔗

close #222


What is this PR? 🔍

QA때 진행한 통계 페이지의 레이아웃과 상태 표시 방식을 개선했습니다.

  • 통계 캘린더 로딩/에러 상태에서 페이지 전용 상태 래퍼를 제거하고 로띠만 렌더링하도록 수정
  • LottiePlayer의 기본 w-full 스타일 제거
  • 통계 캘린더 헤더 고정 해제
  • 캘린더 영역과 오른쪽 사이드 패널이 각각 필요한 경우에만 스크롤되도록 수정
  • 오른쪽 패널 todo 목록에서 마지막 항목 하단 border 제거
  • 초과/단축 텍스트가 없는 경우에도 동일한 줄 높이를 유지하도록 수정
  • 캘린더 영역의 불필요한 흰색 배경 제거



To Reviewers

통계 페이지에서 캘린더 영역과 오른쪽 패널의 스크롤이 각각 독립적으로 동작하는지 확인 부탁드립니다.

Note

추가로, 홈 탭에서 투두 수정 후 통계 데이터가 즉시 반영되지 않는 케이스가 있습니다.
이를 해결하려면 통계 관련 query invalidation을 추가해야 하는데, 여러 mutation 성공 지점마다 invalidateStatistics()를 붙이는 방식은 유지보수 부담이 있어 보입니다.
이번 이슈에서 함께 처리할지, 별도 이슈로 분리해 useTodoQueryInvalidation 같은 도메인 단위 helper로 정리할지 의견 부탁드립니다.

--> 이번 PR에서 진행했습니다


  • 통계 관련 query invalidation helper를 추가했습니다.
    • 월별 요약, 일별 기록, 캘린더 통계 쿼리를 함께 stale 처리하도록 구성했습니다.
  • 투두 생성/수정/삭제 후 통계 데이터가 새로고침 없이 반영되도록 수정했습니다.
    • 투두 제목, 날짜, 예상 시간, 태그 등 통계 화면에 노출될 수 있는 값이 변경될 때 통계 쿼리를 갱신합니다.
  • 홈 카드에서 완료 상태 또는 서브태스크 상태를 변경한 뒤 통계 데이터가 갱신되도록 수정했습니다.
    • 완료율, 누적 태스크 수, 일별 기록 목록 등에 영향을 줄 수 있는 변경을 통계 화면에서 즉시 다시 가져오도록 처리했습니다.
  • 타이머 상태 갱신 흐름에서 통계 데이터도 함께 stale 처리되도록 수정했습니다.
    • 타이머 종료/완료 등 기록 시간이 바뀔 수 있는 흐름 이후 통계 화면에서 최신 데이터를 조회할 수 있도록 했습니다.



Test Checklist ✔

  • 통계 캘린더가 넘칠 때 캘린더 영역만 스크롤되는지 확인
  • 오른쪽 패널 todo 목록이 넘칠 때 패널만 스크롤되는지 확인
  • 오른쪽 패널 마지막 todo 아래에 불필요한 border가 없는지 확인
  • pnpm lint:web
  • pnpm check-types:web

@yumin-kim2 yumin-kim2 linked an issue Jul 15, 2026 that may be closed by this pull request
@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 15, 2026 5:44pm

Request Review

@github-actions github-actions Bot requested review from jjangminii and kimminna July 15, 2026 13:24
@github-actions github-actions Bot added the ⏰ Timo-web Timo 웹 서비스 label Jul 15, 2026
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

통계 화면의 내부 스크롤과 목록 스타일을 조정하고, 로딩·오류 표시를 Lottie로 단순화했습니다. todo 및 타이머 상태 변경 성공 시 요약·일별·캘린더 통계 쿼리를 무효화하도록 갱신 흐름도 확장했습니다.

Changes

통계 화면 및 데이터 갱신

Layer / File(s) Summary
통계 레이아웃과 목록 표시
apps/timo-web/app/[locale]/(main)/statistics/_containers/StatisticsContainer.tsx, apps/timo-web/app/[locale]/(main)/statistics/_components/StatisticsCalendar.tsx, apps/timo-web/app/[locale]/(main)/statistics/_components/StatisticsSidePanel.tsx
콘텐츠 영역의 내부 스크롤을 적용하고 캘린더의 고정·흰색 배경을 제거했습니다. 사이드 패널에는 세로 스크롤을 추가했으며 마지막 todo의 보더와 diff 라벨 최소 높이를 조정했습니다.
캘린더 상태 표시
apps/timo-web/app/[locale]/(main)/statistics/_containers/StatisticsCalendarContainer.tsx, apps/timo-web/components/lottie/LottiePlayer.tsx
로딩·오류 상태 래퍼를 제거하고 LottiePlayer를 직접 렌더링하도록 변경했으며, LottiePlayer의 기본 w-full 클래스를 제거했습니다.
통계 쿼리 무효화 연결
apps/timo-web/hooks/statistics/use-statistics-query-invalidation.ts, apps/timo-web/hooks/timer/use-timer-query-invalidation.ts, apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-todos-by-date.ts, apps/timo-web/hooks/todo-modal/{create,detail}/*
todo 생성·수정·삭제와 완료·타이머 상태 변경 성공 후 통계 관련 세 쿼리를 무효화하도록 추가했습니다.

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

Possibly related PRs

Suggested reviewers: jjangminii, kimminna

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning UI 수정은 범위 내지만, 통계 쿼리 무효화와 여러 todo/timer 훅 변경은 #222의 UI·레이아웃 요구를 벗어납니다. 쿼리 무효화는 별도 이슈로 분리하거나, 이번 PR에서는 #222 범위의 UI·레이아웃 수정만 유지하세요.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 통계 페이지 QA 반영이라는 핵심 변경을 정확히 요약합니다.
Description check ✅ Passed 설명이 레이아웃·Lottie·스크롤·통계 갱신 등 변경 내용과 잘 맞습니다.
Linked Issues check ✅ Passed #222의 Lottie, 스크롤, 헤더 고정 해제 요구를 코드가 충족합니다.
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/222-statistics-layout

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed: dependency version conflict. Check your lock file or package.json.


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 added 🐛 Bug 기능이 정상적으로 작동하지 않는 문제 수정 ♣️ 유민 유민양 labels Jul 15, 2026
@yumin-kim2 yumin-kim2 added the 🚬 QA QA 반영 label Jul 15, 2026
@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 211.68 kB 🔴 417.54 kB
/[locale]/today 195.79 kB 🔴 401.64 kB
/[locale]/focus 160.85 kB 🔴 366.70 kB
/[locale]/settings 167.12 kB 🔴 372.97 kB
/[locale]/statistics 233.49 kB 🔴 439.35 kB
/[locale]/[...rest] 0 B 🟡 205.86 kB
/[locale]/login 212.96 kB 🔴 418.82 kB
/[locale]/oauth/callback 119.66 kB 🟡 325.51 kB
/[locale]/onboarding 233.42 kB 🔴 439.27 kB
/[locale] 118.97 kB 🟡 324.83 kB
/[locale]/policy 125.09 kB 🟡 330.95 kB

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

Lighthouse — timo-web
URL Perf A11y LCP CLS TBT
/en/home 🔴 60 🟢 95 🔴 15.6s 🟢 0.000 🟡 570ms
/en/today 🔴 59 🟢 95 🔴 15.5s 🟢 0.000 🔴 627ms
/en/focus 🔴 59 🟢 95 🔴 15.3s 🟢 0.000 🔴 618ms
/en/statistics 🔴 59 🟢 95 🔴 15.2s 🟢 0.000 🔴 614ms

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 ⚠️ 🟢

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

측정 커밋: 4a71ba1

@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/app/`[locale]/(main)/statistics/_components/StatisticsSidePanel.tsx:
- Around line 105-116: In the todo list rendering around detail.todos.map,
remove the isLastTodo index calculation and apply the border styling with
Tailwind’s last: modifier on each li instead of conditionally checking the array
position. Preserve the existing spacing and ensure the last item does not
receive the bottom border.
🪄 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: df705934-30e2-4c9e-a9fc-37735c72cbde

📥 Commits

Reviewing files that changed from the base of the PR and between 590c15d and b57fea8.

📒 Files selected for processing (5)
  • apps/timo-web/app/[locale]/(main)/statistics/_components/StatisticsCalendar.tsx
  • apps/timo-web/app/[locale]/(main)/statistics/_components/StatisticsSidePanel.tsx
  • apps/timo-web/app/[locale]/(main)/statistics/_containers/StatisticsCalendarContainer.tsx
  • apps/timo-web/app/[locale]/(main)/statistics/_containers/StatisticsContainer.tsx
  • apps/timo-web/components/lottie/LottiePlayer.tsx

Comment on lines +105 to +116
{detail.todos.map((todo, index) => {
const diffMinutes =
todo.actualTimeMinutes - todo.estimatedTimeMinutes;
const isLastTodo = index === detail.todos.length - 1;

return (
<li
key={todo.todoId}
className="border-timo-gray-500 flex justify-between border-b py-2.5"
className={cn(
"flex justify-between py-2.5 pt-5",
!isLastTodo && "border-timo-gray-500 border-b",
)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Tailwind의 last: 모디파이어를 활용해 보세요.

JS에서 배열 인덱스를 계산하여 조건부로 스타일을 적용하는 대신, Tailwind CSS의 의사 클래스(pseudo-class) 모디파이어인 last:를 사용하면 코드를 한결 간결하게 작성할 수 있습니다. 렌더링 성능과 가독성 측면에서도 CSS 기반 처리가 권장됩니다! ✨

자세한 내용은 Tailwind CSS 공식 문서: Pseudo-classes를 참고해 보세요.

💡 제안하는 리팩토링 코드
-        {detail.todos.map((todo, index) => {
+        {detail.todos.map((todo) => {
           const diffMinutes =
             todo.actualTimeMinutes - todo.estimatedTimeMinutes;
-          const isLastTodo = index === detail.todos.length - 1;
 
           return (
             <li
               key={todo.todoId}
-              className={cn(
-                "flex justify-between py-2.5 pt-5",
-                !isLastTodo && "border-timo-gray-500 border-b",
-              )}
+              className="border-timo-gray-500 flex justify-between border-b py-2.5 pt-5 last:border-b-0"
             >
📝 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
{detail.todos.map((todo, index) => {
const diffMinutes =
todo.actualTimeMinutes - todo.estimatedTimeMinutes;
const isLastTodo = index === detail.todos.length - 1;
return (
<li
key={todo.todoId}
className="border-timo-gray-500 flex justify-between border-b py-2.5"
className={cn(
"flex justify-between py-2.5 pt-5",
!isLastTodo && "border-timo-gray-500 border-b",
)}
{detail.todos.map((todo) => {
const diffMinutes =
todo.actualTimeMinutes - todo.estimatedTimeMinutes;
return (
<li
key={todo.todoId}
className="border-timo-gray-500 flex justify-between border-b py-2.5 pt-5 last:border-b-0"
>
🤖 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)/statistics/_components/StatisticsSidePanel.tsx
around lines 105 - 116, In the todo list rendering around detail.todos.map,
remove the isLastTodo index calculation and apply the border styling with
Tailwind’s last: modifier on each li instead of conditionally checking the array
position. Preserve the existing spacing and ensure the last item does not
receive the bottom border.

@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/statistics/use-statistics-query-invalidation.ts`:
- Around line 14-18: Update invalidateStatistics in
apps/timo-web/hooks/statistics/use-statistics-query-invalidation.ts lines 14-18
to return a Promise.all containing all queryClient.invalidateQueries calls. Also
update invalidateTimerState in
apps/timo-web/hooks/timer/use-timer-query-invalidation.ts lines 20-25 to return
a Promise.all containing invalidateActiveTimer(), invalidateHomeView(), and the
other existing invalidation calls, preserving their current behavior while
exposing completion to callers.
🪄 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: c0d9d769-62fd-4139-9387-037617fe8e6a

📥 Commits

Reviewing files that changed from the base of the PR and between b57fea8 and e8700fb.

📒 Files selected for processing (6)
  • apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_hooks/use-home-todos-by-date.ts
  • apps/timo-web/hooks/statistics/use-statistics-query-invalidation.ts
  • apps/timo-web/hooks/timer/use-timer-query-invalidation.ts
  • apps/timo-web/hooks/todo-modal/create/use-create-todo-submit.ts
  • apps/timo-web/hooks/todo-modal/detail/use-delete-todo-submit.ts
  • apps/timo-web/hooks/todo-modal/detail/use-update-todo-submit.ts

Comment on lines +14 to +18
const invalidateStatistics = () => {
queryClient.invalidateQueries({ queryKey: getGetSummaryQueryKey() });
queryClient.invalidateQueries({ queryKey: getGetDailyQueryKey() });
queryClient.invalidateQueries({ queryKey: getGetCalendarQueryKey() });
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Promise.all을 활용해 비동기 무효화 작업의 Promise를 반환해 보세요.

현재 invalidateQueries는 실행 후 무효화 처리에 대한 Promise를 반환하지만, 여러 무효화 함수를 묶어서 호출하는 래퍼 함수들(invalidateStatistics, invalidateTimerState)이 해당 결과 Promise를 반환(return)하지 않고 있습니다.

이렇게 되면 호출부(예: Mutation의 onSuccess 콜백)에서 쿼리 무효화 완료 시점을 명시적으로 기다려야 할 때 후속 처리가 불가능해집니다. 각 호출을 Promise.all 배열로 묶어 반환하면 보다 유연하고 안정적인 사용자 경험(UX) 제어가 가능해집니다. 멋진 통계 기능이 더욱 견고하게 동작할 수 있을 거예요! ✨

  • apps/timo-web/hooks/statistics/use-statistics-query-invalidation.ts#L14-L18: 내부의 queryClient.invalidateQueries 호출들을 Promise.all([ ... ])로 감싸서 반환하도록 수정해 보세요.
  • apps/timo-web/hooks/timer/use-timer-query-invalidation.ts#L20-L25: 내부의 무효화 함수 호출들(invalidateActiveTimer(), invalidateHomeView() 등)을 Promise.all([ ... ])로 감싸서 반환하도록 수정해 보세요.

관련하여 TanStack Query 공식 문서 - Query Invalidation 가이드를 확인해 보시면 더욱 도움이 될 것입니다.

📍 Affects 2 files
  • apps/timo-web/hooks/statistics/use-statistics-query-invalidation.ts#L14-L18 (this comment)
  • apps/timo-web/hooks/timer/use-timer-query-invalidation.ts#L20-L25
🤖 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/statistics/use-statistics-query-invalidation.ts` around
lines 14 - 18, Update invalidateStatistics in
apps/timo-web/hooks/statistics/use-statistics-query-invalidation.ts lines 14-18
to return a Promise.all containing all queryClient.invalidateQueries calls. Also
update invalidateTimerState in
apps/timo-web/hooks/timer/use-timer-query-invalidation.ts lines 20-25 to return
a Promise.all containing invalidateActiveTimer(), invalidateHomeView(), and the
other existing invalidation calls, preserving their current behavior while
exposing completion to callers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

♣️ 유민 유민양 🐛 Bug 기능이 정상적으로 작동하지 않는 문제 수정 🚬 QA QA 반영 ⏰ Timo-web Timo 웹 서비스

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FIX] 통계 페이지 QA 반영

1 participant