"use client"; import { CalendarDays, Trash2 } from "lucide-react"; import { type ReactNode, useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { AiBadge } from "@/components/ai-badge"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { Button } from "@/components/ui/button"; import { Calendar } from "@/components/ui/calendar"; import { Combobox, type ComboboxOption } from "@/components/ui/combobox"; import { Input } from "@/components/ui/input"; import { Popover, PopoverPopup, PopoverTrigger } from "@/components/ui/popover"; import { Sheet, SheetFooter, SheetHeader, SheetPanel, SheetPopup, SheetTitle, } from "@/components/ui/sheet"; import { type Appointment, type AppointmentStatus, deleteAppointment, updateAppointment, } from "@/lib/appointments"; import { listProviders, type Provider } from "@/lib/staff"; import { notify } from "@/lib/toast"; const TYPES = [ "Follow-up", "New patient", "Consultation", "Lab review", "Vaccination", ]; const STATUSES: AppointmentStatus[] = [ "confirmed", "checked-in", "completed", "cancelled", ]; const controlClass = "h-9 w-full rounded-3xl border border-transparent bg-input/50 px-3 text-sm text-foreground outline-none transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/30"; // Local-date ISO key (avoids UTC drift from toISOString). const keyOf = (d: Date) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String( d.getDate(), ).padStart(2, "0")}`; function Field({ label, children }: { label: string; children: ReactNode }) { return ( ); } // Right-side Sheet for reviewing and editing a single appointment — opened by // clicking a row in the schedule. Editing here is intentional (AI-drafted rows // often need their placeholders filled in). Persists via the appointments API. export function AppointmentDetailSheet({ appt, open, onOpenChange, onSaved, onDeleted, }: { appt: Appointment | null; open: boolean; onOpenChange: (open: boolean) => void; onSaved: (updated: Appointment) => void; onDeleted: (id: string) => void; }) { const { t } = useTranslation(); const [providers, setProviders] = useState([]); const [date, setDate] = useState(() => new Date()); const [dateOpen, setDateOpen] = useState(false); const [time, setTime] = useState("09:00"); const [type, setType] = useState(TYPES[0]); const [provider, setProvider] = useState(""); const [status, setStatus] = useState("confirmed"); const [busy, setBusy] = useState(false); // Seed the form from the selected appointment whenever it changes. useEffect(() => { if (!appt) return; setDate(new Date(`${appt.date}T00:00:00`)); setTime(appt.time); setType(appt.type); setProvider(appt.provider); setStatus(appt.status); }, [appt]); useEffect(() => { if (!open) return; let active = true; listProviders() .then((data) => active && setProviders(data)) .catch(() => { /* provider combobox just stays empty; free-text is preserved */ }); return () => { active = false; }; }, [open]); const providerOptions = useMemo( () => providers.map((pr) => ({ value: pr.name, label: pr.name, keywords: pr.role, })), [providers], ); const save = async () => { if (!appt) return; setBusy(true); try { const updated = await updateAppointment(appt.id, { fileNumber: appt.fileNumber, name: appt.name, initials: appt.initials, date: keyOf(date), time, type, provider, status, }); onSaved(updated); notify.success( t("appointments.sheet.savedTitle"), t("appointments.sheet.savedBody"), ); onOpenChange(false); } catch { notify.error( t("appointments.sheet.saveFailedTitle"), t("appointments.sheet.saveFailedBody"), ); } finally { setBusy(false); } }; const remove = async () => { if (!appt) return; setBusy(true); try { await deleteAppointment(appt.id); onDeleted(appt.id); notify.success(t("appointments.sheet.deletedTitle"), appt.name); onOpenChange(false); } catch { notify.error( t("appointments.sheet.deleteFailedTitle"), t("appointments.sheet.deleteFailedBody"), ); } finally { setBusy(false); } }; return ( {appt?.name ?? t("appointments.sheet.title")}

{t("appointments.sheet.editHint")}

{appt && (
{appt.initials}
{appt.name} {t("appointments.dialog.fileNumber", { number: appt.fileNumber || "—", })}
{t("appointments.sheet.date")} {date.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric", })} } /> { if (d) { setDate(d); setDateOpen(false); } }} selected={date} />
setTime(event.target.value)} type="time" value={time} />
)}
); }