Skip to content

[FEAT] 타이머 종료·완료·연장·중단 모달 연결 및 다국어 지원 - #140

Merged
jjangminii merged 10 commits into
developfrom
feat/web/136-connect-modal
Jul 12, 2026
Merged

[FEAT] 타이머 종료·완료·연장·중단 모달 연결 및 다국어 지원#140
jjangminii merged 10 commits into
developfrom
feat/web/136-connect-modal

Conversation

@jjangminii

@jjangminii jjangminii commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

ISSUE 🔗

close #136



What is this PR? 🔍

Focus 뷰와 홈 사이드바 타이머에 종료·완료·연장·중단(재생 중 조기 종료) 4가지 확인 모달을 연결하고, 관련 텍스트 전체를 next-intl로 옮겨 한/영을 지원하도록 했습니다.

배경

  • 기존 구조: packages/timo-design-systemModal 컴포넌트는 이미 구현돼 있었지만 실제 타이머 화면(Focus 뷰, 홈 사이드바)에는 전혀 연결돼 있지 않았고, 종료 버튼을 눌러도 아무 동작이 없었습니다.
  • 발생 문제: 타이머 종료·완료·시간 연장 시 사용자에게 확인/입력을 받을 UI가 없어 의도치 않게 세션이 끝나거나 계획 시간을 조정할 방법이 없었고, 관련 문구도 전부 한국어로 하드코딩돼 있어 영문 로케일에서도 그대로 노출됐습니다.
  • 해결 방향: Figma 화면설계서·디자인 시스템 파일을 기준으로 종료·완료·연장·중단 4가지 모달을 하나의 Modal 인스턴스 안에서 step으로 분기하는 구조로 구현하고, 텍스트는 next-intl로 옮겨 한/영을 지원하도록 했습니다.

타이머 모달 (TimerSessionControls 외)

  • 변경 요약: 타이머 종료·완료·연장·중단 흐름을 하나의 Modal 컨트롤러(TimerSessionControls)로 통합해 신규 구현했습니다.
  • 이유: ModalModal.Trigger 클릭으로만 열 수 있는 비제어(uncontrolled) 컴포넌트라, 여러 확인 단계(종료→연장/완료)를 하나의 열린 모달 안에서 전환하려면 버튼이 아닌 지점(체크박스)에서도 여는 방법이 필요했습니다. Modal에 controlled prop을 추가하는 대신 기존 API를 유지하는 방향으로 진행했습니다.
  • 구현 방식: TimerSessionControls 내부에서 step state(end | stop | extend | complete)로 어떤 패널을 보여줄지 분기합니다. TimerControls의 종료/연장 버튼은 Modal.Trigger를 직접 사용해 클릭 시 step을 먼저 세팅한 뒤 모달이 열립니다. 상위 체크박스처럼 버튼이 아닌 지점에서 모달을 열어야 할 때를 위해 TimerSessionControlsopenStopModal imperative handle을 추가하고, 내부에 숨긴 Modal.Trigger를 ref로 프로그래밍적으로 클릭하는 방식을 택했습니다. 이를 위해 Modal.Triggerref를 받을 수 있도록 최소 수정했습니다(React 19라 forwardRef 없이 ref를 prop으로 추가).
  • 경계 · 제약: 타이머가 재생 중일 때만 종료 버튼/체크박스가 "중단" 모달을 띄우도록 isRunning 기준으로 분기했습니다. 실시간 카운트다운 로직 자체는 이번 범위 밖이라 "실제 소요 시간"은 계획 시간과 동일한 값을 임시로 사용합니다.

다국어(i18n)

  • 변경 요약: 타이머 모달·컨트롤·요일 라벨의 하드코딩된 한국어 텍스트를 next-intlFocus / Common.weekday 네임스페이스로 옮겼습니다.
  • 이유: 새로 만든 모달 텍스트가 전부 한국어로 하드코딩돼 있었고, 기존 Focus 뷰의 요일 라벨(토요일 등)도 로케일과 무관하게 고정 배열에서 가져오고 있었습니다.
  • 구현 방식: messages/{ko,en}.jsonFocus.controls, Focus.endModal, Focus.stopModal, Focus.extendModal, Focus.completeModal, Focus.duration 키를 추가했습니다. 소요 시간은 60분 미만이면 {m}분/{m}m, 정각이면 {h}시간/{h}h, 그 외엔 {h}시간 {m}분/{h}h {m}m로 변환하는 formatDurationLabel 유틸을 만들어 완료·중단 모달에서 공유합니다. 중단 모달의 소요 시간 값은 t.rich() + <blue> 태그로 강조색을 적용했습니다(기존 TagLimitToastContainer와 동일한 패턴). 연장 모달의 프리셋 단위는 한국어 "분/시간", 영어 "M/H"로 Figma 원본 표기를 그대로 따라 언어별 문자열 자체를 다르게 관리합니다.
  • 경계 · 제약: Settings 네임스페이스처럼 이미 있던 다른 미완성 i18n 갭은 이번 PR 범위에 포함하지 않았습니다.

포커스 접근성

  • 변경 요약: 모달 버튼·타이머 컨트롤·연장 모달의 키보드 포커스 스타일을 ring(box-shadow) 방식에서 버튼 자체 border 색상 전환 방식으로 바꿨습니다.
  • 이유: 기존 ring-2 방식은 흰/회색 배경 버튼에서 테두리 바깥에 별도 그림자 링이 겹쳐 보여 실제 버튼 경계와 시각적으로 불일치했습니다.
  • 구현 방식: 이미 테두리가 있는 요소(ModalButtonborder variant, 연장 모달 직접입력 인풋 컨테이너)는 focus-visible:border-timo-blue-300으로 색상만 바꿉니다. 테두리가 없는 요소(연장 모달 프리셋 칩, 타이머 컨트롤 원형 버튼)는 border-2 border-transparent를 기본값으로 깔아두고 포커스 시 색만 바꿔 레이아웃 흔들림 없이 표시합니다. 파란 배경의 fill 버튼(완료하기류)은 테두리 색을 바꿔도 배경과 구분이 안 되어 기존 ring-2 + ring-offset-2 방식을 유지했습니다.

상위 체크박스 연동

  • 변경 요약: Focus 뷰에서 타이머가 재생 중일 때 상위(부모) 태스크 체크박스를 클릭하면 즉시 완료 처리하는 대신 타이머 중단 모달을 띄우도록 했습니다.
  • 이유: 타이머가 도는 중에 체크박스만으로 작업을 완료 처리하면 진행 중인 세션이 사용자 확인 없이 끊기는 문제가 있었습니다.
  • 구현 방식: FocusSessionContainerhandleToggleCompleted에서 completed && task.isRunning이면 상태를 바꾸지 않고 timerSessionControlsRef.current?.openStopModal()만 호출합니다. Checkbox가 controlled 컴포넌트라 상태를 업데이트하지 않으면 체크 표시도 그대로 유지됩니다.



To Reviewers

Modal.Triggerref를 추가한 부분이 Modal 컴포넌트의 기존 API 방향과 맞는지 봐주세요. controlled prop 추가는 피했지만, "숨은 트리거를 프로그래밍적으로 클릭"하는 방식이 다소 우회적이라 더 나은 대안이 있다면 의견 부탁드립니다.

"실제 소요 시간"이 실시간 카운트다운 없이 계획 시간과 동일하게 표시되는 부분은 미리 알고 계셔야 할 것 같아 남깁니다. 실제 타이머 엔진 구현은 이번 PR 범위 밖입니다.

완료 모달의 버튼 개수(현재 1개)와 관련해, Figma 파일 자체가 한국어 프레임(1개 버튼)과 영문 프레임(2개, Close+Finish)이 서로 다른 상태였습니다. 우선 기존 1개 구조를 유지했고, 어느 쪽이 최신 의도인지 확인되면 후속 처리하겠습니다.

Screenshot 📷

로컬 Playwright로 /ko/focus, /en/focus에서 아래 상태들을 직접 클릭해 확인했습니다 (이미지 업로드 환경이 아니라 표는 생략합니다).

  • 재생 중 종료 클릭 → 중단 모달("지금 멈출까요? / Shall we stop now?") 노출, 소요 시간이 파란색 2시간/2h로 표시
  • 중단 모달 "전환하기/Switch" → 완료 모달로 전환, "계획/실제" 값이 2h 30m 형식으로 표시
  • 일시정지 상태에서 종료 클릭 → 종료 모달("타이머 종료! / Timer Finished!") 즉시 노출
  • 연장 모달에서 프리셋 선택·직접입력(25분/25M) 시 포커스링이 버튼 테두리 색 전환으로 표시
  • 상위 체크박스를 재생 중에 클릭 시 체크 표시가 바뀌지 않고 중단 모달만 노출, 완료 확정 후에야 체크됨
  • Focus 뷰 상단 요일 라벨이 /en/focus에서 Saturday로 표시
image image image



Test Checklist ✔

  • pnpm --filter timo-web lint 통과
  • pnpm --filter @repo/timo-design-system lint 통과
  • pnpm --filter @repo/timo-design-system exec tsc --noEmit 통과
  • pnpm --filter timo-web exec tsc --noEmit — 이번 브랜치가 건드리지 않은 onboarding 아이콘 export 누락 에러 4건이 develop에도 이미 있어 통과로 표시하지 않았습니다 (별도 확인 필요)
  • 위 Screenshot 항목들을 로컬 Playwright로 직접 클릭해 확인
  • pnpm build — 미실행

- 타이머 컨트롤의 종료·시간추가 버튼을 Modal.Trigger로 전환했습니다
- 종료 모달에서 완료/연장 단계로 전환되는 TimerSessionControls를 추가했습니다
- 종료·완료·연장 각 단계의 모달 콘텐츠를 Figma 디자인대로 구현했습니다
- FocusSessionContainer와 홈 사이드바 TimerPanel에 모달 플로우를 연결했습니다
- 분 단위 변환 유틸(convertDurationToMinutes)을 추가했습니다
- 타이머가 실행 중일 때 종료를 누르면 뜨는 "지금 멈출까요?" 중단 모달을 추가했습니다
- 종료·완료·연장 모달과 타이머 컨트롤 라벨을 next-intl Focus 네임스페이스로 옮겨 한/영 전환되게 했습니다
- 연장 모달의 프리셋·직접입력 단위를 언어별(분/시간 vs M/H)로 분리했습니다
- 모달 버튼·타이머 컨트롤·연장 모달의 포커스링을 그림자(ring) 대신 버튼 테두리 색상 전환 방식으로 교체했습니다
- 타이머 재생 중 상위 체크박스를 누르면 완료 처리 대신 타이머 중단 모달을 띄우도록 연결했습니다
- Modal.Trigger가 ref를 받을 수 있도록 수정해 외부에서 정지 모달을 프로그래밍적으로 열 수 있게 했습니다
- 완료·중단 모달의 소요 시간을 60분 이상일 때 시/분(h m) 단위로 표기하고, 중단 모달의 시간 값을 파란색으로 강조했습니다
- 포커스 화면 상단의 요일 라벨을 next-intl Common.weekday로 교체해 영문 버전에서도 표시되게 했습니다
@vercel

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

Request Review

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 54 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: 141a83c6-2ae4-488b-acd4-a6d625e2d82a

📥 Commits

Reviewing files that changed from the base of the PR and between 220182d and b0fa9b6.

📒 Files selected for processing (2)
  • apps/timo-web/components/timer/TimerEndModalPanel.tsx
  • apps/timo-web/components/timer/TimerStopModalPanel.tsx

Walkthrough

포커스 타이머가 직접 콜백 방식에서 종료·중지·연장·완료 모달을 포함한 세션 제어 방식으로 전환되었습니다. 요일·지속시간 표시를 번역 및 공통 시간 유틸리티와 연결하고, 포커스 화면과 사이드바에 새 세션 컨트롤을 적용했습니다.

Changes

포커스 타이머 모달 흐름

Layer / File(s) Summary
시간 및 표시 계약
apps/timo-web/app/[locale]/(main)/focus/_utils/date.ts, apps/timo-web/constants/time.ts, apps/timo-web/utils/*, apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_utils/todo-time.ts
요일 텍스트 변환을 번역 키 기반으로 변경하고, 분·시간 변환 상수와 지속시간 포맷 유틸리티를 추가했습니다.
모달 트리거와 컨트롤 계약
apps/timo-web/components/timer/TimerControls.tsx, apps/timo-web/components/timer/TimerControlButton.tsx, packages/timo-design-system/src/components/button/modal-button/ModalButton.tsx, packages/timo-design-system/src/components/layout/modal/Modal.tsx
종료·연장 버튼을 모달 트리거로 변경하고, Modal.Trigger의 ref 전달 및 포커스 스타일을 추가했습니다.
세션 단계와 모달 패널
apps/timo-web/components/timer/TimerSessionControls.tsx, apps/timo-web/components/timer/Timer*ModalPanel.tsx
end, stop, extend, complete 단계를 관리하며 각 모달 패널의 선택, 입력, 제출 및 외부 콜백을 연결했습니다.
포커스 화면 통합
apps/timo-web/app/[locale]/(main)/focus/_containers/FocusSessionContainer.tsx, apps/timo-web/components/layout/sidebar/time/TimerPanel.tsx, apps/timo-web/messages/*.json
포커스 컨테이너와 사이드바를 TimerSessionControls에 연결하고, 실행 중 완료 요청을 중지 모달로 전환하며 Focus 번역 메시지를 추가했습니다.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant FocusSessionContainer
  participant TimerSessionControls
  participant TimerEndModalPanel
  participant TimerExtendModalPanel
  participant TimerCompleteModalPanel
  FocusSessionContainer->>TimerSessionControls: 타이머 세션 props 전달
  TimerSessionControls->>TimerEndModalPanel: 종료 모달 표시
  TimerEndModalPanel->>TimerSessionControls: 계속 또는 완료 선택
  TimerSessionControls->>TimerExtendModalPanel: 연장 모달 표시
  TimerExtendModalPanel->>TimerSessionControls: 연장 시간 제출
  TimerSessionControls->>TimerCompleteModalPanel: 완료 모달 표시
  TimerCompleteModalPanel->>FocusSessionContainer: 완료 콜백 호출
Loading

Possibly related PRs

  • Team-Timo/Timo-client#96: 공유 ModalModalButton 구현을 추가해 새 타이머 모달 흐름의 기반을 제공합니다.
  • Team-Timo/Timo-client#103: 기존 TimerControls 구현과 이번 컨트롤 인터페이스 변경에 직접 연결됩니다.
  • Team-Timo/Timo-client#116: FocusSessionContainerTimerSessionControls 연결과 실행 중 중지 모달 흐름을 다룹니다.

Suggested labels: ✨ Feature

Suggested reviewers: yumin-kim2, ehye1, kimminna

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning 포커스 세션 종료 모달 연결은 반영됐지만, #136의 설정 회원탈퇴 window.confirm 교체가 보이지 않습니다. SettingsWithdrawalContainer의 window.confirm을 Modal로 교체하거나, 해당 작업을 별도 이슈로 분리해 #136 범위를 조정하세요.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 타이머 모달 연결과 다국어 지원이라는 핵심 변경을 잘 요약합니다.
Description check ✅ Passed 설명은 포커스/홈 타이머에 모달과 i18n을 연결한 변경과 일치합니다.
Out of Scope Changes check ✅ Passed 변경 내용은 모달 연결, i18n, 포커스 스타일, 시간 포맷 유틸 추가로 모두 목표와 맞습니다.
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 feat/web/136-connect-modal

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.

…to feat/web/136-connect-modal

# Conflicts:
#	apps/timo-web/app/[locale]/(main)/focus/_containers/FocusSessionContainer.tsx
@github-actions github-actions Bot added ⏰ Timo-web Timo 웹 서비스 ⌚ Timo-Design-system Timo 디자인 시스템 labels Jul 10, 2026

@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: 10

🤖 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)/focus/_containers/FocusSessionContainer.tsx:
- Around line 125-126: FocusSessionContainer의 actualMinutes에 plannedMinutes를
전달하지 말고, 실제 경과 시간 필드가 추가될 때까지 0을 임시값으로 사용하거나 명확한 TODO를 추가하세요.
TimerCompleteModalPanel과 TimerStopModalPanel에 계획 시간이 실제 시간으로 표시되지 않도록 수정하고,
TimerPanel의 PLANNED_MINUTES 전달부에도 동일한 처리를 적용하세요.
- Line 27: Remove the duplicated SECONDS_PER_MINUTE declaration from
FocusSessionContainer and import the shared exported constant from duration.ts,
updating duration.ts to export it if necessary.

In `@apps/timo-web/components/layout/sidebar/time/TimerPanel.tsx`:
- Around line 34-35: TimerPanel의 FocusSessionContainer 호출에서 actualMinutes에 계획값인
PLANNED_MINUTES를 전달하는 문제를 수정하세요. 실제 집중 세션 시간을 추적하는 상태나 계산값을 사용해 actualMinutes를
전달하고, plannedMinutes에는 계속 PLANNED_MINUTES를 유지하여 완료 모달에 계획 시간과 실제 시간이 올바르게 표시되도록
하세요.
- Line 18: TimerPanel의 handleExtendTimer가 no-op 상태이므로, FocusSessionContainer의 동일
핸들러 동작을 참고해 연장 시 durationSeconds를 업데이트하고 필요한 TODO 주석을 추가하세요.

In `@apps/timo-web/components/timer/TimerEndModalPanel.tsx`:
- Around line 61-97: The TimerEndModalPanel currently uses TimerEndIcon
directly; replace it with the finalized SVG component once available, remove the
related TODO comment, and track any pending asset work through the appropriate
issue rather than leaving inline TODO text.
- Around line 4-59: TimerEndIcon과 TimerStopModalPanel의 TimerStopIcon에 동일한 SVG
마크업이 중복되어 있습니다. SVG를 공용 아이콘 컴포넌트로 추출한 뒤 두 컴포넌트가 해당 공용 컴포넌트를 렌더링하도록 변경하고, 기존 아이콘과
동일한 크기·속성·외형을 유지하세요.

In `@apps/timo-web/components/timer/TimerExtendModalPanel.tsx`:
- Around line 73-89: Replace the input’s outline-none class in the custom
minutes field with an accessible focus-visible treatment, such as
focus-visible:outline and an appropriate focus-visible outline color, or use
outline-hidden if the parent focus-within styling is sufficient. Update the
input element in TimerExtendModalPanel’s custom minutes control while preserving
the existing parent focus-within indicator.

In `@apps/timo-web/components/timer/TimerSessionControls.tsx`:
- Around line 49-54: TimerSessionControls의 openStopModal에서 숨겨진 트리거의
stopModalTriggerRef.current?.click() 호출을 제거하고, 모달 컨텍스트가 제공하는 open 함수를 직접 사용해 모달을
열도록 변경하세요. setStep("stop")과 모달 열기 동작을 기존 순서대로 유지하되, 트리거 ref 및 관련 의존 코드는 정리하고 동일한
방식이 적용된 다른 구간도 함께 수정하세요.

In `@apps/timo-web/messages/ko.json`:
- Line 75: Update the completeModal.title Korean translation from “테스크가 완료
되었어요!” to the correctly spaced and spelled “태스크가 완료되었어요!”.

In `@packages/timo-design-system/src/components/layout/modal/Modal.tsx`:
- Around line 75-77: ModalTriggerProps를 type 교차 타입 대신 interface로 선언하도록 변경하세요.
ButtonHTMLAttributes<HTMLButtonElement>를 extends하고 기존 ref?:
Ref<HTMLButtonElement> 속성을 유지하며, ModalTriggerProps를 사용하는 코드가 동일하게 동작하는지 확인하세요.
🪄 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: 20e3b7cc-9e49-406d-88fc-105f236ba739

📥 Commits

Reviewing files that changed from the base of the PR and between f18156f and e1571a4.

📒 Files selected for processing (16)
  • apps/timo-web/app/[locale]/(main)/focus/_containers/FocusSessionContainer.tsx
  • apps/timo-web/app/[locale]/(main)/focus/_utils/date.ts
  • apps/timo-web/app/[locale]/(main)/focus/_utils/duration.ts
  • apps/timo-web/components/layout/sidebar/time/TimerPanel.tsx
  • apps/timo-web/components/timer/TimerCompleteModalPanel.tsx
  • apps/timo-web/components/timer/TimerControlButton.tsx
  • apps/timo-web/components/timer/TimerControls.tsx
  • apps/timo-web/components/timer/TimerEndModalPanel.tsx
  • apps/timo-web/components/timer/TimerExtendModalPanel.tsx
  • apps/timo-web/components/timer/TimerSessionControls.tsx
  • apps/timo-web/components/timer/TimerStopModalPanel.tsx
  • apps/timo-web/components/timer/durationLabel.ts
  • apps/timo-web/messages/en.json
  • apps/timo-web/messages/ko.json
  • packages/timo-design-system/src/components/button/modal-button/ModalButton.tsx
  • packages/timo-design-system/src/components/layout/modal/Modal.tsx

Comment thread apps/timo-web/app/[locale]/(main)/focus/_containers/FocusSessionContainer.tsx Outdated
Comment on lines +125 to +126
plannedMinutes={plannedMinutes}
actualMinutes={plannedMinutes}

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

actualMinutesplannedMinutes를 그대로 전달하여 "계획"과 "실제"가 항상 동일하게 표시됩니다

FocusTask 인터페이스에 경과 시간 필드(elapsedSeconds 등)가 없어 현재 데이터 모델로는 실제 시간 추적이 불가능합니다. 하지만 actualMinutes={plannedMinutes}로 전달하면:

  • TimerCompleteModalPanel의 "계획"과 "실제"가 항상 같은 값을 보여줌 (예: 둘 다 "2h")
  • TimerStopModalPanel의 "지금까지 수행한 {minutes}"에 계획 시간이 표시됨

경과 시간 추적이 구현될 때까지 TODO 주석 추가 또는 actualMinutes={0} 임시값 사용을 고려하세요. TimerPanel.tsxPLANNED_MINUTES 전달에도 동일한 패턴이 나타납니다.

🛡️ proposed fix: TODO 주석 추가
           <TimerSessionControls
             ref={timerSessionControlsRef}
             isRunning={task.isRunning}
             onTogglePlay={handleTogglePlay}
             plannedMinutes={plannedMinutes}
-            actualMinutes={plannedMinutes}
+            // TODO: actualMinutes에 실제 경과 시간 연결 필요 (FocusTask에 elapsedSeconds 필드 추가)
+            actualMinutes={0}
             onExtend={handleExtendTimer}
             onComplete={handleCompleteTimer}
           />
🤖 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)/focus/_containers/FocusSessionContainer.tsx
around lines 125 - 126, FocusSessionContainer의 actualMinutes에 plannedMinutes를
전달하지 말고, 실제 경과 시간 필드가 추가될 때까지 0을 임시값으로 사용하거나 명확한 TODO를 추가하세요.
TimerCompleteModalPanel과 TimerStopModalPanel에 계획 시간이 실제 시간으로 표시되지 않도록 수정하고,
TimerPanel의 PLANNED_MINUTES 전달부에도 동일한 처리를 적용하세요.

setStatus((prev) => (prev === "RUNNING" ? "PAUSED" : "RUNNING"));
const handleEnd = () => setStatus("PAUSED");
const handleAddTime = () => {};
const handleExtendTimer = () => {};

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 | 🟡 Minor | ⚡ Quick win

handleExtendTimer가 빈 구현입니다

FocusSessionContainer의 동일 핸들러는 durationSeconds 업데이트와 TODO 주석을 포함하지만, TimerPanelhandleExtendTimer는 no-op이고 TODO도 없습니다. 연장 모달은 표시되지만 "시간 추가하기" 버튼이 아무 동작도 수행하지 않습니다.

✏️ proposed fix: TODO 주석 추가
-  const handleExtendTimer = () => {};
+  // TODO: 사이드바 타이머 시간 연장 로직 구현 필요
+  const handleExtendTimer = () => {};
🤖 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/layout/sidebar/time/TimerPanel.tsx` at line 18,
TimerPanel의 handleExtendTimer가 no-op 상태이므로, FocusSessionContainer의 동일 핸들러 동작을
참고해 연장 시 durationSeconds를 업데이트하고 필요한 TODO 주석을 추가하세요.

Comment on lines +34 to +35
plannedMinutes={PLANNED_MINUTES}
actualMinutes={PLANNED_MINUTES}

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

actualMinutesPLANNED_MINUTES를 전달하여 "계획"과 "실제"가 동일하게 표시됩니다

FocusSessionContainer에서 지적한 것과 동일한 패턴입니다. actualMinutes={PLANNED_MINUTES}로 인해 완료 모달의 "계획"과 "실제"가 항상 같은 값을 보여줍니다.

🛡️ proposed fix: TODO 주석 추가
       <TimerSessionControls
         isRunning={status === "RUNNING"}
         onTogglePlay={handleTogglePlay}
         plannedMinutes={PLANNED_MINUTES}
-        actualMinutes={PLANNED_MINUTES}
+        // TODO: actualMinutes에 실제 경과 시간 연결 필요
+        actualMinutes={0}
         onExtend={handleExtendTimer}
         onComplete={handleCompleteTimer}
       />
🤖 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/layout/sidebar/time/TimerPanel.tsx` around lines 34
- 35, TimerPanel의 FocusSessionContainer 호출에서 actualMinutes에 계획값인
PLANNED_MINUTES를 전달하는 문제를 수정하세요. 실제 집중 세션 시간을 추적하는 상태나 계산값을 사용해 actualMinutes를
전달하고, plannedMinutes에는 계속 PLANNED_MINUTES를 유지하여 완료 모달에 계획 시간과 실제 시간이 올바르게 표시되도록
하세요.

Comment thread apps/timo-web/components/timer/TimerEndModalPanel.tsx Outdated
Comment thread apps/timo-web/components/timer/TimerEndModalPanel.tsx
Comment on lines +73 to +89
<input
type="text"
inputMode="numeric"
value={customMinutes}
onChange={(e) => {
const digitsOnly = e.target.value.replace(/\D/g, "");
const clamped =
digitsOnly === ""
? ""
: String(Math.min(Number(digitsOnly), MAX_CUSTOM_MINUTES));

onCustomMinutesChange(clamped);
}}
aria-label={t("customInputLabel")}
style={{ width: `${Math.max(customMinutes.length, 1)}ch` }}
className="typo-headline-r-14 text-timo-black shrink-0 text-center outline-none"
/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

입력 필드에 outline-none이 직접적인 focus-visible 대체 스타일 없이 사용되었습니다.

부모 divfocus-within:border-timo-blue-300로 간접적으로 포커스를 표시하지만, 컨벤션에서는 outline: none으로 포커스 테두리 제거를 금지하고 있습니다. 입력 요소 자체에 focus-visible 스타일을 추가하거나, outline-none 대신 outline-hidden 사용을 고려하세요.

🛡️ 제안하는 변경
             className="typo-headline-r-14 text-timo-black shrink-0 text-center outline-none"
+            // focus-visible 스타일 추가 또는 outline-none 제거
           />
🤖 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/timer/TimerExtendModalPanel.tsx` around lines 73 -
89, Replace the input’s outline-none class in the custom minutes field with an
accessible focus-visible treatment, such as focus-visible:outline and an
appropriate focus-visible outline color, or use outline-hidden if the parent
focus-within styling is sufficient. Update the input element in
TimerExtendModalPanel’s custom minutes control while preserving the existing
parent focus-within indicator.

Source: Path instructions

Comment on lines +49 to +54
useImperativeHandle(ref, () => ({
openStopModal: () => {
setStep("stop");
stopModalTriggerRef.current?.click();
},
}));

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

히든 트리거 .click() 패턴이 동작은 하지만 fragile합니다.

openStopModal에서 setStep("stop") 직후 stopModalTriggerRef.current?.click()로 모달을 여는 패턴은 React 배칭 덕분에 동작하지만, 모달 컨텍스트의 open 함수를 직접 호출할 수 있는 방법을 고려해 보세요. 향후 Modal API가 변경되면 .click() 가정이 깨질 수 있습니다.

Also applies to: 91-96

🤖 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/timer/TimerSessionControls.tsx` around lines 49 -
54, TimerSessionControls의 openStopModal에서 숨겨진 트리거의
stopModalTriggerRef.current?.click() 호출을 제거하고, 모달 컨텍스트가 제공하는 open 함수를 직접 사용해 모달을
열도록 변경하세요. setStep("stop")과 모달 열기 동작을 기존 순서대로 유지하되, 트리거 ref 및 관련 의존 코드는 정리하고 동일한
방식이 적용된 다른 구간도 함께 수정하세요.

Comment thread apps/timo-web/messages/ko.json Outdated
Comment on lines +75 to +77
export type ModalTriggerProps = ButtonHTMLAttributes<HTMLButtonElement> & {
ref?: Ref<HTMLButtonElement>;
};

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

typeinterface 변경을 권장합니다.

ModalTriggerPropsButtonHTMLAttributes와 교차 타입으로 구성된 Props입니다. 컨벤션에 따라 Props 접미사가 붙은 타입은 interface로 선언하는 것이 권장됩니다.

♻️ 제안하는 변경
-export type ModalTriggerProps = ButtonHTMLAttributes<HTMLButtonElement> & {
-  ref?: Ref<HTMLButtonElement>;
-};
+export interface ModalTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
+  ref?: Ref<HTMLButtonElement>;
+}
📝 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
export type ModalTriggerProps = ButtonHTMLAttributes<HTMLButtonElement> & {
ref?: Ref<HTMLButtonElement>;
};
export interface ModalTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
ref?: Ref<HTMLButtonElement>;
}
🤖 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/layout/modal/Modal.tsx` around
lines 75 - 77, ModalTriggerProps를 type 교차 타입 대신 interface로 선언하도록 변경하세요.
ButtonHTMLAttributes<HTMLButtonElement>를 extends하고 기존 ref?:
Ref<HTMLButtonElement> 속성을 유지하며, ModalTriggerProps를 사용하는 코드가 동일하게 동작하는지 확인하세요.

Source: Path instructions

@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown

Timo Performance Report

Bundle Size — timo-web
라우트 크기 First Load JS
/[locale]/home 167.33 kB 🔴 373.15 kB
/[locale]/today 64.79 kB 🟡 270.61 kB
/[locale]/focus 61.47 kB 🟡 267.29 kB
/[locale]/settings/account 0 B 🟡 205.82 kB
/[locale]/settings 71.49 kB 🟡 277.30 kB
/[locale]/statistics 58.75 kB 🟡 264.57 kB
/[locale]/[...rest] 0 B 🟡 205.82 kB
/[locale]/login 116.05 kB 🟡 321.86 kB
/[locale]/onboarding 134.84 kB 🟡 340.66 kB
/[locale] 0 B 🟡 205.82 kB

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

Lighthouse — timo-web
URL Perf A11y LCP CLS TBT
/en/home 🔴 64 🟢 96 🔴 14.5s 🟢 0.000 🟡 418ms
/en/today 🟡 71 🟡 93 🔴 13.8s 🟢 0.000 🟡 227ms
/en/focus 🟡 72 🟡 91 🔴 13.8s 🟢 0.000 🟢 156ms
/en/statistics 🟡 73 🟢 96 🔴 13.8s 🟢 0.000 🟢 159ms

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

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

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

측정 커밋: e0e12e3

- "테스크"를 "태스크"로, "완료 되었어요"를 "완료되었어요"로 맞춤법과 띄어쓰기를 수정했습니다
@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown

Storybook Preview

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

마지막 업데이트: 2026-07-12 08:15 UTC

@jjangminii jjangminii self-assigned this Jul 11, 2026
@ehye1 ehye1 added the ♠️ 정민 정민양 label Jul 12, 2026
Comment thread apps/timo-web/app/[locale]/(main)/focus/_containers/FocusSessionContainer.tsx Outdated
Comment thread apps/timo-web/app/[locale]/(main)/focus/_utils/duration.ts Outdated
Comment thread apps/timo-web/components/timer/durationLabel.ts Outdated
- 여러 파일에 중복 정의돼 있던 SECONDS_PER_MINUTE/SECONDS_PER_HOUR/MINUTES_PER_HOUR를 constants/time.ts로 통합했습니다
- convertDurationToMinutes를 공통 유틸(utils/convert-duration-to-minutes.ts)로 옮기고 JSDoc을 추가했습니다
- 순수 함수인 formatDurationLabel을 components/timer에서 utils/format-duration-label.ts로 옮기고, 다른 유틸 파일과 동일한 kebab-case 네이밍으로 맞췄습니다
- 다른 공통 유틸과 동일한 형식으로 설명·@param·@returns·@example을 추가했습니다
- 인라인 placeholder SVG(TimerEndIcon/TimerStopIcon)를 제거하고 timo-timer.svg 로고 에셋을 사용하도록 했습니다

@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

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/messages/ko.json (1)

170-211: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

번역 키 구성이 컴포넌트 사용 패턴과 일치합니다

Focus 네임스페이스의 모든 키(controls, endModal, stopModal, completeModal, extendModal, duration)가 컴포넌트에서 사용하는 useTranslations 호출과 정확히 매칭됩니다. 이전 리뷰에서 지적된 "태스크" 오탈자도 수정되었습니다. 👍

한 가지 사소한 제안: stopModal.description의 "지금까지 수행한 {minutes}이 타임박스에 기록됩니다."에서 "수행한 30분"이라는 표현이 다소 어색할 수 있습니다. "지금까지 {minutes}이(가) 타임박스에 기록됩니다." 또는 "지금까지 수행한 시간 {minutes}이 타임박스에 기록됩니다."가 더 자연스러울 수 있습니다.

🤖 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 170 - 211,
Focus.stopModal.description의 한국어 문구를 수정해 “수행한 30분”처럼 어색하게 읽히지 않도록 하세요. {minutes}
변수와 <blue> 마크업은 유지하고, 경과 시간이 타임박스에 기록된다는 의미가 자연스럽게 전달되도록 표현을 다듬으세요.
♻️ Duplicate comments (1)
apps/timo-web/app/[locale]/(main)/focus/_containers/FocusSessionContainer.tsx (1)

118-125: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

actualMinutes에 여전히 plannedMinutes를 전달하고 있습니다

이전 리뷰에서 지적된 문제가 현재 코드에도 그대로 남아 있습니다. actualMinutes={plannedMinutes}로 전달하면 TimerCompleteModalPanel의 "계획"과 "실제"가 항상 동일한 값을 표시합니다. 실제 경과 시간 추적이 구현될 때까지 actualMinutes={0} 임시값 사용이나 TODO 주석 추가를 권장합니다.

🤖 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)/focus/_containers/FocusSessionContainer.tsx
around lines 118 - 125, Update the TimerSessionControls invocation in
FocusSessionContainer so actualMinutes no longer receives plannedMinutes; pass
the temporary value 0 instead, optionally documenting with a TODO that actual
elapsed-time tracking should replace it later.
🤖 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/utils/convert-duration-to-time-text.ts`:
- Around line 1-20: Review the existing convertDurationToTimeText implementation
in todo-time.ts and replace it with the shared utility from this diff if the
padded "HH:MM" format is acceptable there. Remove the duplicate implementation
and update its imports or call sites as needed; if the unpadded format is
required, distinguish the APIs or add an explicit formatting option instead of
keeping identical function names with different output.

---

Outside diff comments:
In `@apps/timo-web/messages/ko.json`:
- Around line 170-211: Focus.stopModal.description의 한국어 문구를 수정해 “수행한 30분”처럼 어색하게
읽히지 않도록 하세요. {minutes} 변수와 <blue> 마크업은 유지하고, 경과 시간이 타임박스에 기록된다는 의미가 자연스럽게 전달되도록
표현을 다듬으세요.

---

Duplicate comments:
In
`@apps/timo-web/app/`[locale]/(main)/focus/_containers/FocusSessionContainer.tsx:
- Around line 118-125: Update the TimerSessionControls invocation in
FocusSessionContainer so actualMinutes no longer receives plannedMinutes; pass
the temporary value 0 instead, optionally documenting with a TODO that actual
elapsed-time tracking should replace it later.
🪄 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: e3e98085-dd37-4cdb-b68d-fcd2a2ddcc1b

📥 Commits

Reviewing files that changed from the base of the PR and between e1571a4 and 220182d.

📒 Files selected for processing (11)
  • apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_utils/todo-time.ts
  • apps/timo-web/app/[locale]/(main)/focus/_containers/FocusSessionContainer.tsx
  • apps/timo-web/app/[locale]/(main)/focus/_utils/duration.ts
  • apps/timo-web/components/timer/TimerCompleteModalPanel.tsx
  • apps/timo-web/components/timer/TimerStopModalPanel.tsx
  • apps/timo-web/constants/time.ts
  • apps/timo-web/messages/en.json
  • apps/timo-web/messages/ko.json
  • apps/timo-web/utils/convert-duration-to-minutes.ts
  • apps/timo-web/utils/convert-duration-to-time-text.ts
  • apps/timo-web/utils/format-duration-label.ts
💤 Files with no reviewable changes (1)
  • apps/timo-web/app/[locale]/(main)/focus/_utils/duration.ts

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

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

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/messages/ko.json (1)

170-211: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

번역 키 구성이 컴포넌트 사용 패턴과 일치합니다

Focus 네임스페이스의 모든 키(controls, endModal, stopModal, completeModal, extendModal, duration)가 컴포넌트에서 사용하는 useTranslations 호출과 정확히 매칭됩니다. 이전 리뷰에서 지적된 "태스크" 오탈자도 수정되었습니다. 👍

한 가지 사소한 제안: stopModal.description의 "지금까지 수행한 {minutes}이 타임박스에 기록됩니다."에서 "수행한 30분"이라는 표현이 다소 어색할 수 있습니다. "지금까지 {minutes}이(가) 타임박스에 기록됩니다." 또는 "지금까지 수행한 시간 {minutes}이 타임박스에 기록됩니다."가 더 자연스러울 수 있습니다.

🤖 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 170 - 211,
Focus.stopModal.description의 한국어 문구를 수정해 “수행한 30분”처럼 어색하게 읽히지 않도록 하세요. {minutes}
변수와 <blue> 마크업은 유지하고, 경과 시간이 타임박스에 기록된다는 의미가 자연스럽게 전달되도록 표현을 다듬으세요.
♻️ Duplicate comments (1)
apps/timo-web/app/[locale]/(main)/focus/_containers/FocusSessionContainer.tsx (1)

118-125: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

actualMinutes에 여전히 plannedMinutes를 전달하고 있습니다

이전 리뷰에서 지적된 문제가 현재 코드에도 그대로 남아 있습니다. actualMinutes={plannedMinutes}로 전달하면 TimerCompleteModalPanel의 "계획"과 "실제"가 항상 동일한 값을 표시합니다. 실제 경과 시간 추적이 구현될 때까지 actualMinutes={0} 임시값 사용이나 TODO 주석 추가를 권장합니다.

🤖 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)/focus/_containers/FocusSessionContainer.tsx
around lines 118 - 125, Update the TimerSessionControls invocation in
FocusSessionContainer so actualMinutes no longer receives plannedMinutes; pass
the temporary value 0 instead, optionally documenting with a TODO that actual
elapsed-time tracking should replace it later.
🤖 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/utils/convert-duration-to-time-text.ts`:
- Around line 1-20: Review the existing convertDurationToTimeText implementation
in todo-time.ts and replace it with the shared utility from this diff if the
padded "HH:MM" format is acceptable there. Remove the duplicate implementation
and update its imports or call sites as needed; if the unpadded format is
required, distinguish the APIs or add an explicit formatting option instead of
keeping identical function names with different output.

---

Outside diff comments:
In `@apps/timo-web/messages/ko.json`:
- Around line 170-211: Focus.stopModal.description의 한국어 문구를 수정해 “수행한 30분”처럼 어색하게
읽히지 않도록 하세요. {minutes} 변수와 <blue> 마크업은 유지하고, 경과 시간이 타임박스에 기록된다는 의미가 자연스럽게 전달되도록
표현을 다듬으세요.

---

Duplicate comments:
In
`@apps/timo-web/app/`[locale]/(main)/focus/_containers/FocusSessionContainer.tsx:
- Around line 118-125: Update the TimerSessionControls invocation in
FocusSessionContainer so actualMinutes no longer receives plannedMinutes; pass
the temporary value 0 instead, optionally documenting with a TODO that actual
elapsed-time tracking should replace it later.
🪄 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: e3e98085-dd37-4cdb-b68d-fcd2a2ddcc1b

📥 Commits

Reviewing files that changed from the base of the PR and between e1571a4 and 220182d.

📒 Files selected for processing (11)
  • apps/timo-web/app/[locale]/(main)/(with-time-sidebar)/home/_utils/todo-time.ts
  • apps/timo-web/app/[locale]/(main)/focus/_containers/FocusSessionContainer.tsx
  • apps/timo-web/app/[locale]/(main)/focus/_utils/duration.ts
  • apps/timo-web/components/timer/TimerCompleteModalPanel.tsx
  • apps/timo-web/components/timer/TimerStopModalPanel.tsx
  • apps/timo-web/constants/time.ts
  • apps/timo-web/messages/en.json
  • apps/timo-web/messages/ko.json
  • apps/timo-web/utils/convert-duration-to-minutes.ts
  • apps/timo-web/utils/convert-duration-to-time-text.ts
  • apps/timo-web/utils/format-duration-label.ts
💤 Files with no reviewable changes (1)
  • apps/timo-web/app/[locale]/(main)/focus/_utils/duration.ts
🛑 Comments failed to post (1)
apps/timo-web/utils/convert-duration-to-time-text.ts (1)

1-20: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

todo-time.tsconvertDurationToTimeText와 중복 및 포맷 불일치

새로 추가된 이 함수는 시간을 2자리 패딩(01:30)하지만, todo-time.ts 8-14줄에 이미 동일 이름의 함수가 존재하며 시간 패딩 없이(1:30) 반환합니다. 두 함수가 다른 컨텍스트에서 의도적으로 다른 포맷을 사용하는 것이 아니라면, 중복을 제거하고 하나의 구현으로 통일하는 것이 좋습니다.

todo-time.ts의 기존 함수를 이 새 유틸리티로 교체할 수 있는지 확인해 보시겠어요?

♻️ 중복 제거 제안
// todo-time.ts에서 기존 convertDurationToTimeText 제거 후 import로 대체
- export const convertDurationToTimeText = (durationSeconds: number): string => {
-   const hours = Math.floor(durationSeconds / SECONDS_PER_HOUR);
-   const minutes = Math.floor(
-     (durationSeconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE,
-   );
-   return `${hours}:${minutes.toString().padStart(2, "0")}`;
- };
+ export { convertDurationToTimeText } from "`@/utils/convert-duration-to-time-text`";

만약 패딩 없는 포맷이 의도된 것이라면, 함수명을 구분하거나 옵션 파라미터를 추가하는 방법도 고려할 수 있습니다.

🤖 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/utils/convert-duration-to-time-text.ts` around lines 1 - 20,
Review the existing convertDurationToTimeText implementation in todo-time.ts and
replace it with the shared utility from this diff if the padded "HH:MM" format
is acceptable there. Remove the duplicate implementation and update its imports
or call sites as needed; if the unpadded format is required, distinguish the
APIs or add an explicit formatting option instead of keeping identical function
names with different output.

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

고생 많으셨서요! 모달 흐름과 i18n까지 같이 정리되어 있어서 이후 실제 타이머 API 연결할 때 기반이 잘 잡힌 PR이라고 느껴졌어요.👍👍 최공

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.

TimerSessionControls에 버튼 제어와 모달 렌더링 로직이 함께 모여 있어 살짝 커 보였습니다. TimerSessionModal처럼 모달 영역만 분리하면 역할이 더 명확해질 것 같은데, 어떻게 생각하시나용!

@jjangminii
jjangminii merged commit 75e1db8 into develop Jul 12, 2026
19 checks passed
@kimminna kimminna mentioned this pull request Jul 14, 2026
@kimminna
kimminna deleted the feat/web/136-connect-modal branch July 14, 2026 18:11
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 웹 서비스 ♠️ 정민 정민양

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 설정 회원탈퇴 및 포커스 세션 종료에 Modal 컴포넌트 연결

4 participants