import { useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { useEscapeKey } from "../../hooks/useEscapeKey"; import type { IntakeJournalEntry } from "../../hooks/useIntakeJournal"; import { useScrollLock } from "../../hooks/useScrollLock"; import { formatDateTime, getNumericLocale } from "../../utils/formatters"; import { MedicationAvatar } from "../MedicationAvatar"; interface IntakeJournalModalProps { isOpen: boolean; entry: IntakeJournalEntry | null; isLoading: boolean; isSaving: boolean; isDeleting: boolean; error: string | null; onClose: () => void; onSave: (note: string) => Promise | boolean; onDelete: () => Promise | void; allowDelete?: boolean; } function formatDisplayDateTime(value: string | null): string | null { if (!value) { return null; } return formatDateTime(value, getNumericLocale()); } function getJournalSourceLabel(entry: IntakeJournalEntry, t: ReturnType["t"]): string { if (entry.takenSource === "automatic") { return t("journal.context.sourceAutomaticReminder"); } return entry.markedBy ? t("journal.context.sourceSharedLink") : t("journal.context.sourceOwnerApp"); } export function IntakeJournalModal({ isOpen, entry, isLoading, isSaving, isDeleting, error, onClose, onSave, onDelete, allowDelete = true, }: IntakeJournalModalProps) { const { t } = useTranslation(); const [note, setNote] = useState(""); const [showSavedState, setShowSavedState] = useState(false); const activeDoseTrackingIdRef = useRef(null); const wasSavingRef = useRef(false); useScrollLock(isOpen); useEscapeKey(isOpen, onClose); useEffect(() => { if (!isOpen) { setNote(""); setShowSavedState(false); activeDoseTrackingIdRef.current = null; wasSavingRef.current = false; return; } if (!entry) { return; } setNote(entry.note ?? ""); if (activeDoseTrackingIdRef.current !== entry.doseTrackingId) { activeDoseTrackingIdRef.current = entry.doseTrackingId; setShowSavedState(false); } }, [entry, isOpen]); useEffect(() => { if (!isOpen) { wasSavingRef.current = false; return; } if (isSaving) { setShowSavedState(false); wasSavingRef.current = true; return; } if (wasSavingRef.current) { wasSavingRef.current = false; if (entry && !error && note === (entry.note ?? "")) { setShowSavedState(true); } } }, [entry, error, isOpen, isSaving, note]); if (!isOpen) { return null; } const handleSave = async () => { const saved = await onSave(note); if (saved) { onClose(); } }; const scheduledForLabel = formatDisplayDateTime(entry?.scheduledFor ?? null); const takenAtLabel = formatDisplayDateTime(entry?.takenAt ?? null); const title = entry?.note ? t("journal.editor.editTitle") : t("journal.editor.addTitle"); const saveLabel = showSavedState ? t("common.saved") : t("common.save"); let bodyContent: React.ReactNode; if (isLoading) { bodyContent =
{t("journal.editor.loading")}
; } else if (entry) { bodyContent = ( <>
{entry.medicationName}

{entry.dismissed ? t("journal.context.statusSkipped") : t("journal.context.statusTaken")}

{t("journal.context.scheduledFor")} {scheduledForLabel ?? t("common.notAvailable")}
{t("journal.context.takenAt")} {takenAtLabel ?? t("journal.context.notRecorded")}
{t("journal.context.markedBy")} {entry.markedBy ?? t("journal.context.self")}
{t("journal.context.source")} {getJournalSourceLabel(entry, t)}