import { useEffect, useRef, useState } from "react"; import { habitRequest, type TodayHabit } from "../lib/dashboard"; import { Button, Checkbox } from "./design-system/primitives"; import { Field } from "./design-system/Field"; export function CheckInEditor({ habitId, date, disabled, onSaved, onExpired }: { habitId: string; date: string; disabled?: boolean; onSaved: () => void; onExpired?: () => void; }) { const [day, setDay] = useState(null); const [count, setCount] = useState(""); const [error, setError] = useState(""); const [notice, setNotice] = useState(""); const [busy, setBusy] = useState(false); const [attempt, setAttempt] = useState(0); const saving = useRef(false); const expired = useRef(onExpired); expired.current = onExpired; useEffect(() => { const controller = new AbortController(); setDay(null); setError(""); habitRequest(`/habits/${habitId}/days/${date}`, { signal: controller.signal }) .then(value => { if (!controller.signal.aborted) { setDay(value); setCount(String(value.value)); } }) .catch(error => { if (!controller.signal.aborted) { if (error.message.includes("session has expired")) expired.current?.(); setError(error.message); } }); return () => controller.abort(); }, [habitId, date, attempt]); async function save(body: { count: number } | { done: boolean }, taskId?: string) { if (saving.current || disabled) return; saving.current = true; setBusy(true); setError(""); setNotice(""); try { const result = await habitRequest(`/habits/${habitId}/days/${date}/${taskId ? `tasks/${taskId}` : "progress"}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); setDay(result); setCount(String(result.value)); setNotice(`Saved check-in for ${date}.`); onSaved(); } catch (error) { const message = error instanceof Error ? error.message : "Could not save. Try again."; setError(message); if (message.includes("session has expired")) expired.current?.(); } finally { saving.current = false; setBusy(false); } } return

Check-in · {date}

{error &&

{error}

} {!day ? error ? :

Loading check-in…

: day.future ?

Future check-ins cannot be edited.

: !day.due ?

Nothing was scheduled for this date.

: <>

{day.name} · {day.timezone}. Changes use the requirements saved for this date.

{day.method === "count" ?
{ event.preventDefault(); void save({ count: Number(count) }); }}> {id => setCount(event.target.value)} />} {day.carriedFrom &&

Includes carryover from {day.carriedFrom}. Saving sets this day's total.

}
: day.method === "manual" ? void save({ done: event.target.checked })} /> : day.tasks.map(task => void save({ done: event.target.checked }, task.taskId)} />)} }

{notice}

; }