"use client"; import { Database, Download, Import, Smartphone } from "lucide-react"; import { useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { SettingsCard, SettingsSection, } from "@/components/settings/settings-parts"; import { downloadJson, exportRecords, importRecords, type RecordsExport, } from "@/lib/records"; import { notify } from "@/lib/toast"; // A single titled row inside a records card: icon + title/description on the // left, a status badge or action on the right. function RecordRow({ icon, title, description, right, }: { icon: React.ReactNode; title: string; description: string; right: React.ReactNode; }) { return (
{icon}

{title}

{description}

{right}
); } export function RecordsPanel() { const { t } = useTranslation(); const comingSoon = ( {t("settings.records.comingSoon")} ); const fileRef = useRef(null); const [exporting, setExporting] = useState(false); const [importing, setImporting] = useState(false); // A parsed archive staged for import (preview before applying). const [staged, setStaged] = useState<{ name: string; count: number; patients: unknown[] } | null>( null, ); const runExport = async () => { setExporting(true); try { const data = await exportRecords(); const stamp = new Date().toISOString().slice(0, 10); downloadJson(data, `temetro-records-${stamp}.json`); notify.success( t("settings.records.exportDoneTitle"), t("settings.records.exportDoneBody", { count: data.patientCount }), ); } catch { notify.error( t("settings.records.exportFailedTitle"), t("settings.records.exportFailedBody"), ); } finally { setExporting(false); } }; const onFile = async (file: File) => { try { const parsed = JSON.parse(await file.text()) as RecordsExport; const patients = Array.isArray(parsed?.patients) ? parsed.patients : null; if (!patients) throw new Error("bad"); setStaged({ name: file.name, count: patients.length, patients }); } catch { setStaged(null); notify.error( t("settings.records.importInvalidTitle"), t("settings.records.importInvalidBody"), ); } finally { if (fileRef.current) fileRef.current.value = ""; } }; const runImport = async () => { if (!staged) return; setImporting(true); try { const result = await importRecords(staged.patients); notify.success( t("settings.records.importDoneTitle"), t("settings.records.importDoneBody", { created: result.created, skipped: result.skipped, }), ); setStaged(null); } catch { notify.error( t("settings.records.importFailedTitle"), t("settings.records.importFailedBody"), ); } finally { setImporting(false); } }; return ( <> } right={ {t("settings.records.connected")} } title={t("settings.records.clinicDb")} /> } right={comingSoon} title={t("settings.records.patientStorage")} /> } right={ } title={t("settings.records.export")} /> } right={ <> { const f = e.target.files?.[0]; if (f) onFile(f); }} ref={fileRef} type="file" /> } title={t("settings.records.importTemetro")} /> {staged ? (

{staged.name}

{t("settings.records.importPreview", { count: staged.count })}

) : null}

{t("settings.records.retentionBody")}

); }