import { FormEvent, useEffect, useState } from "react"; import { api, PomodoroHistoryItem, PomodoroStatus } from "../api/client"; import { phaseLabel } from "../utils/pomodoro"; import { formatTime } from "../utils/time"; import "./Pomodoro.css"; export default function Pomodoro() { const [status, setStatus] = useState(null); const [history, setHistory] = useState([]); const [duration, setDuration] = useState(25); const [taskNote, setTaskNote] = useState(""); const [result, setResult] = useState(""); const [completed, setCompleted] = useState(false); const [error, setError] = useState(""); const refresh = async () => { const [current, past] = await Promise.all([api.pomodoroStatus(), api.pomodoroHistory()]); setStatus(current); setHistory(past); if (current.cycle?.work_duration_min) { setDuration(current.cycle.work_duration_min); } if (current.cycle?.task_note) { setTaskNote(current.cycle.task_note); } }; useEffect(() => { refresh().catch(console.error); const timer = setInterval(() => { api.pomodoroStatus().then(setStatus).catch(console.error); }, 1000); return () => clearInterval(timer); }, []); const handleStartWork = async (e: FormEvent) => { e.preventDefault(); setError(""); try { const data = await api.pomodoroStart(duration, taskNote); setStatus(data); setResult(""); setCompleted(false); } catch (err) { setError(err instanceof Error ? err.message : "Ошибка запуска"); } }; const handlePause = async () => { setError(""); try { setStatus(await api.pomodoroPause()); } catch (err) { setError(err instanceof Error ? err.message : "Ошибка"); } }; const handleResume = async () => { setError(""); try { setStatus(await api.pomodoroResume()); } catch (err) { setError(err instanceof Error ? err.message : "Ошибка"); } }; const handleStop = async () => { setError(""); try { await api.pomodoroStop(result, completed); await refresh(); setResult(""); setCompleted(false); } catch (err) { setError(err instanceof Error ? err.message : "Ошибка"); } }; const handleSkip = async () => { setError(""); try { await api.pomodoroSkip(); await refresh(); } catch (err) { setError(err instanceof Error ? err.message : "Ошибка"); } }; const handleReset = async () => { setError(""); try { await api.pomodoroResetCycle(false); await refresh(); } catch (err) { setError(err instanceof Error ? err.message : "Ошибка"); } }; const isActive = status?.status === "running" || status?.status === "paused"; const displaySeconds = isActive ? (status?.remaining_seconds ?? 0) : duration * 60; const progress = status && isActive ? ((status.duration_min * 60 - status.remaining_seconds) / (status.duration_min * 60)) * 100 : 0; const cycle = status?.cycle; const ringColor = status?.phase === "work" ? "#4f7cff" : "#3dbf8f"; return (
{cycle && (
Цикл {cycle.completed_work_sessions}/{cycle.sessions_until_long_break} {cycle.auto_advance && " · авто"}
)}
{formatTime(displaySeconds)}
{isActive ? phaseLabel(status?.phase ?? "work") : status?.status ?? "idle"}
{status?.task_note &&

Задача: {status.task_note}

} {!isActive ? (
) : (
{status?.status === "running" ? ( ) : ( )}
setResult(e.target.value)} placeholder="Что успели сделать?" />
)} {error &&

{error}

}

История

    {history.map((item) => (
  • {phaseLabel(item.phase)}: {item.task_note || "Без описания"} — {item.status}
    {item.duration_min} мин ·{" "} {item.finished_at ? new Date(item.finished_at).toLocaleString("ru-RU") : ""}
    {item.result &&
    {item.result}
    }
  • ))}
); }