-
Notifications
You must be signed in to change notification settings - Fork 0
[FEAT] 타이머 종료·완료·연장·중단 모달 연결 및 다국어 지원 #140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
cad030f
b2a2414
e1571a4
8434073
af6e208
8ad63d2
422c453
abda0f2
220182d
b0fa9b6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,17 +4,19 @@ import { TimerOnIcon } from "@repo/timo-design-system/icons"; | |
| import { useState } from "react"; | ||
|
|
||
| import { Timer } from "@/components/timer/Timer"; | ||
| import { TimerControls } from "@/components/timer/TimerControls"; | ||
| import { TimerSessionControls } from "@/components/timer/TimerSessionControls"; | ||
|
|
||
| type TimerStatus = "RUNNING" | "PAUSED"; | ||
|
|
||
| const PLANNED_MINUTES = 12; | ||
|
|
||
| export const TimerPanel = () => { | ||
| const [status, setStatus] = useState<TimerStatus>("PAUSED"); | ||
|
|
||
| const handleTogglePlay = () => | ||
| setStatus((prev) => (prev === "RUNNING" ? "PAUSED" : "RUNNING")); | ||
| const handleEnd = () => setStatus("PAUSED"); | ||
| const handleAddTime = () => {}; | ||
| const handleExtendTimer = () => {}; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
✏️ proposed fix: TODO 주석 추가- const handleExtendTimer = () => {};
+ // TODO: 사이드바 타이머 시간 연장 로직 구현 필요
+ const handleExtendTimer = () => {};🤖 Prompt for AI Agents |
||
| const handleCompleteTimer = () => setStatus("PAUSED"); | ||
|
|
||
| return ( | ||
| <div className="flex flex-col items-center gap-11.25"> | ||
|
|
@@ -26,11 +28,13 @@ export const TimerPanel = () => { | |
| size="sm" | ||
| /> | ||
|
|
||
| <TimerControls | ||
| <TimerSessionControls | ||
| isRunning={status === "RUNNING"} | ||
| onTogglePlay={handleTogglePlay} | ||
| onEnd={handleEnd} | ||
| onAddTime={handleAddTime} | ||
| plannedMinutes={PLANNED_MINUTES} | ||
| actualMinutes={PLANNED_MINUTES} | ||
|
Comment on lines
+34
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🛡️ 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 |
||
| onExtend={handleExtendTimer} | ||
| onComplete={handleCompleteTimer} | ||
| /> | ||
| </div> | ||
| ); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| import { Modal } from "@repo/timo-design-system/ui"; | ||
| import { useTranslations } from "next-intl"; | ||
|
|
||
| import { formatDurationLabel } from "@/utils/format-duration-label"; | ||
|
|
||
| export interface TimerCompleteModalPanelProps { | ||
| plannedMinutes: number; | ||
| actualMinutes: number; | ||
| feedbackText?: string; | ||
| onComplete: () => void; | ||
| } | ||
|
|
||
| export const TimerCompleteModalPanel = ({ | ||
| plannedMinutes, | ||
| actualMinutes, | ||
| feedbackText, | ||
| onComplete, | ||
| }: TimerCompleteModalPanelProps) => { | ||
| const t = useTranslations("Focus.completeModal"); | ||
| const tDuration = useTranslations("Focus.duration"); | ||
| const hourUnit = tDuration("hourUnit"); | ||
| const minuteUnit = tDuration("minuteUnit"); | ||
|
|
||
| return ( | ||
| <> | ||
| <Modal.Title>{t("title")}</Modal.Title> | ||
| <p className="typo-headline-r-14 text-timo-black mt-3"> | ||
| {feedbackText ?? t("defaultFeedback")} | ||
| </p> | ||
|
|
||
| <div className="bg-timo-gray-500 mt-4.5 h-px w-full" /> | ||
|
|
||
| <div className="mt-4 flex gap-6.5"> | ||
| <div className="flex flex-col gap-1"> | ||
| <span className="typo-body-m-12 text-timo-gray-900"> | ||
| {t("plannedLabel")} | ||
| </span> | ||
| <span className="typo-headline-b-20 text-timo-gray-900"> | ||
| {formatDurationLabel(plannedMinutes, hourUnit, minuteUnit)} | ||
| </span> | ||
| </div> | ||
| <div className="flex flex-col gap-1"> | ||
| <span className="typo-body-m-12 text-timo-blue-300"> | ||
| {t("actualLabel")} | ||
| </span> | ||
| <span className="typo-headline-m-20 text-timo-blue-300"> | ||
| {formatDurationLabel(actualMinutes, hourUnit, minuteUnit)} | ||
| </span> | ||
| </div> | ||
| </div> | ||
|
|
||
| <Modal.Footer> | ||
| <Modal.FillButton className="flex-1 px-0" onClick={onComplete}> | ||
| {t("completeButton")} | ||
| </Modal.FillButton> | ||
| </Modal.Footer> | ||
| </> | ||
| ); | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| import timoTimerLogo from "@repo/timo-design-system/assets/images/logo/timo-timer.svg"; | ||
| import { Modal, ModalButton } from "@repo/timo-design-system/ui"; | ||
| import Image from "next/image"; | ||
| import { useTranslations } from "next-intl"; | ||
|
|
||
| export interface TimerEndModalPanelProps { | ||
| onContinue: () => void; | ||
| onComplete: () => void; | ||
| } | ||
|
|
||
| export const TimerEndModalPanel = ({ | ||
| onContinue, | ||
| onComplete, | ||
| }: TimerEndModalPanelProps) => { | ||
| const t = useTranslations("Focus.endModal"); | ||
|
|
||
| return ( | ||
| <> | ||
| <Modal.Icon> | ||
| <Image src={timoTimerLogo} alt="" width={40} height={40} /> | ||
| </Modal.Icon> | ||
| <Modal.Title>{t("title")}</Modal.Title> | ||
| <Modal.Description>{t("description")}</Modal.Description> | ||
| <Modal.Footer> | ||
| <ModalButton | ||
| variant="border" | ||
| className="flex-1 px-0" | ||
| onClick={onContinue} | ||
| > | ||
| {t("continueButton")} | ||
| </ModalButton> | ||
| <ModalButton | ||
| variant="fill" | ||
| className="flex-1 px-0" | ||
| onClick={onComplete} | ||
| > | ||
| {t("completeButton")} | ||
| </ModalButton> | ||
| </Modal.Footer> | ||
| </> | ||
| ); | ||
| }; | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
There was a problem hiding this comment.
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
actualMinutes에plannedMinutes를 그대로 전달하여 "계획"과 "실제"가 항상 동일하게 표시됩니다FocusTask인터페이스에 경과 시간 필드(elapsedSeconds등)가 없어 현재 데이터 모델로는 실제 시간 추적이 불가능합니다. 하지만actualMinutes={plannedMinutes}로 전달하면:TimerCompleteModalPanel의 "계획"과 "실제"가 항상 같은 값을 보여줌 (예: 둘 다 "2h")TimerStopModalPanel의 "지금까지 수행한 {minutes}"에 계획 시간이 표시됨경과 시간 추적이 구현될 때까지 TODO 주석 추가 또는
actualMinutes={0}임시값 사용을 고려하세요.TimerPanel.tsx의PLANNED_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