"use client"; import { useState, useEffect } from "react"; import { Button, Modal, Select, Input } from "@/components/ui"; import { addToOfflineQueue } from "@/lib/offline-queue"; import { trackLogCreated } from "@/lib/analytics"; import type { LogType } from "@/types"; export type { LogType }; export interface SmartDefault { subType: string; amountMl?: number; /** UTC ISO string of the original log time — when set, pre-fills the time picker for editing. */ editTime?: string; } interface Props { type: LogType | null; childId: string; onClose: () => void; onSaved?: () => void; smartDefault?: SmartDefault | null; } type TimePreset = "now" | "5" | "15" | "30" | "custom"; const TIME_PRESETS: { value: TimePreset; label: string }[] = [ { value: "now", label: "Just now" }, { value: "5", label: "5 min ago" }, { value: "15", label: "15 min ago" }, { value: "30", label: "30 min ago" }, { value: "custom", label: "Custom" }, ]; function localDatetimeNow() { const now = new Date(); const offset = now.getTimezoneOffset() * 60000; return new Date(now.getTime() - offset).toISOString().slice(0, 16); } /** * Convert a UTC ISO string to a datetime-local value in the device's local timezone. * This is the inverse of what new Date(datetimeLocalValue).toISOString() does. * Used to pre-fill the time picker when editing an existing log. */ function isoToLocalDatetimeLocal(utcIso: string): string { const date = new Date(utcIso); const offset = date.getTimezoneOffset() * 60000; // negative for UTC+tz (e.g. IST = -330*60000) return new Date(date.getTime() - offset).toISOString().slice(0, 16); } function resolveLoggedAt(preset: TimePreset, customValue: string): string { const now = new Date(); if (preset === "5") return new Date(now.getTime() - 5 * 60_000).toISOString(); if (preset === "15") return new Date(now.getTime() - 15 * 60_000).toISOString(); if (preset === "30") return new Date(now.getTime() - 30 * 60_000).toISOString(); if (preset === "custom" && customValue) return new Date(customValue).toISOString(); return now.toISOString(); } const DEFAULT_SUBTYPE: Record = { feed: "breast_milk", diaper: "wet", sleep: "nap", }; export function LogModal({ type, childId, onClose, onSaved, smartDefault }: Props) { const [loading, setLoading] = useState(false); const [subType, setSubType] = useState("breast_milk"); const [amountMl, setAmountMl] = useState(""); const [notes, setNotes] = useState(""); const [timePreset, setTimePreset] = useState("now"); const [customTime, setCustomTime] = useState(localDatetimeNow); // Reset fields and apply smart defaults whenever the modal opens (type changes to non-null) useEffect(() => { if (!type) return; setSubType(smartDefault?.subType ?? DEFAULT_SUBTYPE[type]); setAmountMl(type === "feed" && smartDefault?.amountMl ? String(smartDefault.amountMl) : ""); setNotes(""); if (smartDefault?.editTime) { // Editing an existing log — pre-fill the picker with its original time setTimePreset("custom"); setCustomTime(isoToLocalDatetimeLocal(smartDefault.editTime)); } else { setTimePreset("now"); setCustomTime(localDatetimeNow()); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [type]); if (!type) return null; const handleSubmit = async () => { setLoading(true); const loggedAt = resolveLoggedAt(timePreset, customTime); const data = { type, childId, subType, amountMl: amountMl ? Number(amountMl) : undefined, notes: notes || undefined, loggedAt, }; try { const res = await fetch("/api/logs", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), }); if (!res.ok && !navigator.onLine) { addToOfflineQueue({ type, data }); } trackLogCreated(type as "feed" | "sleep" | "diaper"); onSaved?.(); onClose(); } catch { if (!navigator.onLine) addToOfflineQueue({ type, data }); onClose(); } setLoading(false); }; const titles: Record = { feed: "Log Feed", diaper: "Log Diaper", sleep: "Log Sleep" }; return (
{/* Time presets */}

When?

{TIME_PRESETS.map(p => ( ))}
{timePreset === "custom" && ( setCustomTime(e.target.value)} className="mt-2" /> )}
{/* Type-specific fields */} {type === "feed" && ( <> setAmountMl(e.target.value)} /> )} {type === "diaper" && ( )} {type === "sleep" && ( )} setNotes(e.target.value)} />
); }