"use client"; import { useState, useEffect, useRef } from "react"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { EVENT_CONFIG, EventType, formatTimeAgo, formatDuration } from "@/lib/event-config"; import { EventModal } from "@/components/event-modal"; import { EventIcon } from "@/components/event-icon"; import { useBaby } from "@/contexts/baby-context"; import { checkFeedAlert, getThresholds } from "@/lib/notifications"; import { format, isToday } from "date-fns"; import { fr } from "date-fns/locale"; import { AlertTriangle, Clock, CheckCircle2, Pin, PinOff, Pencil, Check, X, Plus, FileText, ImageIcon } from "lucide-react"; import { useSession } from "next-auth/react"; function buildQuickLogGroups(isBreastfed: boolean, hasPump: boolean): { label: string; types: EventType[] }[] { const feedTypes: EventType[] = [ ...(isBreastfed ? (["BREASTFEED"] as EventType[]) : []), "BOTTLE", ...(hasPump ? (["PUMP"] as EventType[]) : []), "DIAPER_WET", "DIAPER_STOOL", ]; return [ { label: "Alimentation & Soins", types: feedTypes }, { label: "Sommeil & Activités", types: ["NAP", "NIGHT_SLEEP", "BATH", "WALK", "TUMMY_TIME"] }, { label: "Santé", types: ["TEMPERATURE", "MEDICATION", "SYMPTOM"] }, { label: "Autre", types: ["OTHER"] }, ]; } interface Event { id: string; type: EventType; startedAt: string; endedAt?: string; notes?: string; metadata?: Record; user: { id: string; name: string }; } function getBabyAge(birthDate: string): string { const birth = new Date(birthDate); const now = new Date(); const days = Math.floor((now.getTime() - birth.getTime()) / 86400000); if (days < 7) return `${days} jour${days !== 1 ? "s" : ""}`; const weeks = Math.floor(days / 7); if (weeks < 8) return `${weeks} semaine${weeks !== 1 ? "s" : ""}`; const months = Math.floor(days / 30); return `${months} mois`; } function getEventSummary(event: Event): string { const meta = event.metadata ?? {}; if (event.type === "BREASTFEED") { const side = meta.breastSide === "left" ? "gauche" : meta.breastSide === "right" ? "droite" : "les deux"; if (event.endedAt) return `${formatDuration(new Date(event.startedAt), new Date(event.endedAt))} · ${side}`; return side; } if (event.type === "BOTTLE") { return [meta.volume ? `${meta.volume} mL` : "", meta.bottleType === "maternal" ? "maternel" : "artificiel"].filter(Boolean).join(" · "); } if (event.type === "DIAPER_STOOL") return [String(meta.color ?? ""), meta.leaked ? "débordement" : ""].filter(Boolean).join(" · "); if (event.type === "DIAPER_WET") return meta.leaked ? "débordement" : ""; if (event.type === "TEMPERATURE") return meta.value ? `${meta.value}°${meta.unit ?? "C"}` : ""; if (event.type === "MEDICATION") return String(meta.name ?? ""); if (event.type === "SYMPTOM") { const tags = (meta.tags as string[] | undefined) ?? []; return tags.join(", "); } if ((event.type === "NAP" || event.type === "NIGHT_SLEEP") && event.endedAt) { return formatDuration(new Date(event.startedAt), new Date(event.endedAt)); } if (event.type === "OTHER") return event.notes ? event.notes.slice(0, 50) : ""; return ""; } function formatElapsed(startedAt: string, now: Date): string { const ms = Math.max(0, now.getTime() - new Date(startedAt).getTime()); const h = Math.floor(ms / 3600000); const m = Math.floor((ms % 3600000) / 60000); const s = Math.floor((ms % 60000) / 1000); if (h > 0) return `${h}:${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`; return `${m}:${s.toString().padStart(2, "0")}`; } function ActiveTimers({ events, onStop, babyName }: { events: Event[]; onStop: () => void; babyName?: string }) { const [now, setNow] = useState(() => new Date()); const active = events.filter((e) => !e.endedAt && EVENT_CONFIG[e.type]?.hasTimer); useEffect(() => { if (active.length === 0) return; const id = setInterval(() => setNow(new Date()), 1000); return () => clearInterval(id); }, [active.length]); if (active.length === 0) return null; return (

En cours

{active.map((ev) => { const cfg = EVENT_CONFIG[ev.type]; return (

{cfg.label}

{babyName && {babyName}}

Depuis {format(new Date(ev.startedAt), "HH:mm")}

{formatElapsed(ev.startedAt, now)}
); })}
); } function QuickNoteWidget({ babyId }: { babyId: string }) { const qc = useQueryClient(); const todayStr = format(new Date(), "yyyy-MM-dd"); const [editing, setEditing] = useState(false); const [draft, setDraft] = useState(""); const [saving, setSaving] = useState(false); const textareaRef = useRef(null); const { data: notes = [] } = useQuery>({ queryKey: ["journal-today", babyId, todayStr], queryFn: () => fetch(`/api/journal?babyId=${babyId}&date=${todayStr}`).then((r) => r.json()), }); const todayNote = notes[0] ?? null; function startEdit() { setDraft(todayNote?.content ?? ""); setEditing(true); setTimeout(() => textareaRef.current?.focus(), 50); } async function save() { if (!draft.trim()) return; setSaving(true); if (todayNote) { await fetch(`/api/journal/${todayNote.id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ content: draft }), }); } else { await fetch("/api/journal", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ babyId, date: todayStr, content: draft }), }); } qc.invalidateQueries({ queryKey: ["journal-today", babyId] }); setEditing(false); setSaving(false); } return (
Note du jour
{!editing && ( )}
{editing ? (