/* eslint-disable */ const { useState, useEffect, useMemo, useCallback } = React; const Recharts = window.Recharts || {}; const { LineChart, Line, BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, CartesianGrid, Legend } = Recharts; const ChartsAvailable = !!(LineChart && BarChart); const API = ""; // same origin // ---------- helpers ---------- const fmt$ = (n) => { if (n == null || isNaN(n)) return "—"; if (n === 0) return "$0"; return "$" + Math.round(n).toLocaleString(); }; const fmt$Compact = (n) => { if (n == null || isNaN(n)) return "—"; if (Math.abs(n) >= 1_000_000) return "$" + (n / 1_000_000).toFixed(1) + "M"; if (Math.abs(n) >= 1_000) return "$" + (n / 1_000).toFixed(1) + "k"; return "$" + n; }; const fmtDate = (s) => s ? new Date(s + "T00:00:00").toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }) : "—"; const fmtDateShort = (s) => s ? new Date(s + "T00:00:00").toLocaleDateString("en-US", { month: "short", day: "numeric" }) : "—"; const todayISO = () => new Date().toISOString().split("T")[0]; const daysFromToday = (iso) => { if (!iso) return null; const d = new Date(iso + "T00:00:00"); const t = new Date(); t.setHours(0,0,0,0); return Math.round((d - t) / (1000 * 60 * 60 * 24)); }; const apiGet = async (path) => { const r = await fetch(API + path); if (!r.ok) throw new Error(`${r.status} ${r.statusText}`); return r.json(); }; const apiSend = async (path, method, body) => { const r = await fetch(API + path, { method, headers: { "Content-Type": "application/json" }, body: body ? JSON.stringify(body) : undefined, }); if (!r.ok) throw new Error(`${r.status} ${r.statusText}`); return r.json(); }; // ---------- root app ---------- function App() { const [page, setPage] = useState("dashboard"); const [dashboard, setDashboard] = useState(null); const [stages, setStages] = useState([]); const [coordinators, setCoordinators] = useState([]); const [toast, setToast] = useState(null); const [activePatientId, setActivePatientId] = useState(null); const [showAddPatient, setShowAddPatient] = useState(false); const loadDashboard = useCallback(() => apiGet("/api/dashboard").then(setDashboard).catch(() => {}), []); useEffect(() => { loadDashboard(); apiGet("/api/stages").then(setStages).catch(() => {}); apiGet("/api/lookups/coordinators").then(setCoordinators).catch(() => {}); }, [loadDashboard]); const showToast = (msg) => { setToast(msg); setTimeout(() => setToast(null), 2400); }; const refreshAll = useCallback(() => { loadDashboard(); apiGet("/api/lookups/coordinators").then(setCoordinators).catch(() => {}); }, [loadDashboard]); return (
{page === "dashboard" && ( setShowAddPatient(true)} refresh={refreshAll} /> )} {page === "follow-ups" && ( )} {page === "patients" && ( setShowAddPatient(true)} /> )} {page === "kpis" && } {page === "settings" && apiGet("/api/stages").then(setStages)} showToast={showToast} />}
{activePatientId && ( setActivePatientId(null)} onUpdate={() => { refreshAll(); }} showToast={showToast} /> )} {showAddPatient && ( setShowAddPatient(false)} onSaved={() => { setShowAddPatient(false); refreshAll(); showToast("Patient added"); }} /> )} {toast &&
{toast}
}
); } // ---------- sidebar ---------- function Sidebar({ page, setPage, overdueCount, dueTodayCount }) { const items = [ { id: "dashboard", label: "Dashboard", section: "Today" }, { id: "follow-ups", label: "Follow-ups", badge: overdueCount + dueTodayCount, section: "Today" }, { id: "patients", label: "All Consultations", section: "Pipeline" }, { id: "kpis", label: "Performance", section: "Pipeline" }, { id: "settings", label: "Settings", section: "Configure" }, ]; let lastSection = null; return ( ); } // ---------- Dashboard ---------- function Dashboard({ dashboard, stages, onPatientClick, onAddPatient, refresh }) { const [period, setPeriod] = useState("month"); const [kpi, setKpi] = useState(null); useEffect(() => { apiGet("/api/kpis?period=" + period).then(setKpi).catch(() => {}); }, [period]); if (!dashboard) return
Loading dashboard…
; return ( <>
Today, {fmtDate(dashboard.today)}

Today's work

{/* Period selector + KPIs */}
Performance — {period}
{["day", "week", "month", "quarter", "year"].map((p) => ( ))}
{/* Follow-up panels */}
Coming Up
Next 7 days
{dashboard.upcoming_7_days.length} patients
Pipeline
Stage breakdown
); } function KPICards({ kpi }) { if (!kpi) return null; return (
Consultations
{kpi.consults}
{kpi.accepted_count} accepted
Treatment Presented
${Math.round(kpi.presented).toLocaleString()}
avg case {fmt$Compact(kpi.average_case_size_presented)}
Treatment Accepted
${Math.round(kpi.accepted_dollars).toLocaleString()}
avg accepted {fmt$Compact(kpi.average_case_size_accepted)}
Case Acceptance
{kpi.case_acceptance_rate.toFixed(0)}%
${(kpi.dollar_acceptance_rate).toFixed(0)}% by dollars
Collected Today
${Math.round(kpi.paid_collected).toLocaleString()}
deposits + payments
); } function FollowUpPanel({ title, subtitle, patients, chip, empty, onPatientClick }) { return (
{subtitle}
{title}
{patients.length === 0 ? (
{empty}
) : (
{patients.slice(0, 12).map((p) => (
onPatientClick(p.id)} style={{ padding: "12px 0", borderBottom: "1px solid var(--line-soft)", cursor: "pointer", display: "flex", justifyContent: "space-between", alignItems: "center", }} >
{p.name}
{p.stage || "—"}· {fmt$Compact(p.treatment_presented)} presented {p.treatment_coordinator && <>·{p.treatment_coordinator}}
{chip === "overdue" ? `${Math.abs(daysFromToday(p.next_follow_up_date))}d late` : "today"}
))}
)}
); } function StageBreakdown({ breakdown, stages }) { const stageMap = Object.fromEntries(stages.map(s => [s.stage_name, s])); const sorted = [...breakdown].sort((a, b) => b.count - a.count); const total = sorted.reduce((sum, s) => sum + s.count, 0); return (
{sorted.map((s) => { const cfg = stageMap[s.stage]; const pct = total ? (s.count / total) * 100 : 0; return (
{s.stage} {cfg?.is_terminal && terminal}
{s.count} · {fmt$Compact(s.presented)}
); })}
); } // ---------- Follow-ups page ---------- function FollowUps({ stages, coordinators, onPatientClick, refresh }) { const [filter, setFilter] = useState("due"); const [patients, setPatients] = useState([]); const [tcFilter, setTcFilter] = useState(""); const load = useCallback(() => { let url = "/api/patients?"; if (filter === "overdue") url += "overdue=true"; if (filter === "due") url += "follow_up_due=true"; if (filter === "upcoming") url += `start_date=${todayISO()}`; if (tcFilter) url += "&tc=" + encodeURIComponent(tcFilter); apiGet(url).then(setPatients).catch(() => {}); }, [filter, tcFilter]); useEffect(() => { load(); }, [load]); return ( <>
Follow-up queue

Patients waiting to hear from you

); } // ---------- Patients list ---------- function PatientsList({ stages, coordinators, onPatientClick, onAddPatient }) { const [patients, setPatients] = useState([]); const [search, setSearch] = useState(""); const [stage, setStage] = useState(""); const [tc, setTc] = useState(""); const [accepted, setAccepted] = useState(""); const load = useCallback(() => { const params = new URLSearchParams(); if (search) params.set("search", search); if (stage) params.set("stage", stage); if (tc) params.set("tc", tc); if (accepted === "yes") params.set("accepted", "true"); if (accepted === "no") params.set("accepted", "false"); params.set("limit", "1000"); apiGet("/api/patients?" + params.toString()).then(setPatients).catch(() => {}); }, [search, stage, tc, accepted]); useEffect(() => { const t = setTimeout(load, 200); return () => clearTimeout(t); }, [load]); return ( <>
{patients.length} records

All consultations

Export CSV
setSearch(e.target.value)} style={{ minWidth: 220 }} />
); } // ---------- Reusable patient table ---------- function PatientTable({ patients, onPatientClick, showFollowUp, empty }) { if (!patients || patients.length === 0) { return
{empty || "No patients."}
; } return (
{showFollowUp && } {patients.map((p) => { const fuDays = daysFromToday(p.next_follow_up_date); let chipClass = "chip-neutral"; if (p.is_accepted) chipClass = "chip-accepted"; else if (p.closed_lost) chipClass = "chip-firm"; else if (fuDays != null && fuDays < 0) chipClass = "chip-overdue"; else if (fuDays === 0) chipClass = "chip-due"; else if (fuDays != null && fuDays > 0) chipClass = "chip-upcoming"; return ( onPatientClick(p.id)}> {showFollowUp && ( )} ); })}
Consult Patient Coordinator Stage Presented AcceptedNext Follow-up
{fmtDateShort(p.consult_date)}
{p.name}
{p.referral_source &&
{p.referral_source}
}
{p.treatment_coordinator || "—"} {p.stage ? {p.stage} : } {fmt$Compact(p.treatment_presented)} {p.is_accepted ? fmt$Compact(p.treatment_accepted) : "—"} {p.next_follow_up_date ? (
{fmtDateShort(p.next_follow_up_date)}
{fuDays != null && (
{fuDays < 0 ? `${Math.abs(fuDays)}d overdue` : fuDays === 0 ? "today" : `in ${fuDays}d`}
)}
) : }
); } // ---------- Patient detail modal ---------- function PatientDetailModal({ patientId, stages, onClose, onUpdate, showToast }) { const [patient, setPatient] = useState(null); const [editing, setEditing] = useState(false); const [logging, setLogging] = useState(false); const load = useCallback(() => { apiGet(`/api/patients/${patientId}`).then(setPatient).catch(() => {}); }, [patientId]); useEffect(() => { load(); }, [load]); if (!patient) return null; const fuDays = daysFromToday(patient.next_follow_up_date); return (
e.stopPropagation()}>
{fmtDate(patient.consult_date)} consult
{patient.name}
{patient.stage && {patient.stage}} {patient.referral_source && via {patient.referral_source}} {patient.new_patient && New patient}
{editing ? ( { setEditing(false); load(); onUpdate(); showToast("Patient updated"); }} /> ) : ( <> {patient.notes && ( <>
Consultation Notes
{patient.notes}
)}
Contact History ({patient.contacts.length})
{patient.contacts.length === 0 ? (
No contacts logged yet.
) : patient.contacts.map((c) => (
{c.contact_type} {c.outcome && · {c.outcome}}
{c.contact_date ? new Date(c.contact_date).toLocaleString("en-US", { month: "short", day: "numeric", year: "numeric", hour: "numeric", minute: "2-digit" }) : "—"}
{c.note &&
{c.note}
} {c.new_stage &&
→ Stage: {c.new_stage}
} {c.by_user &&
by {c.by_user}
}
))}
)}
Snapshot
Treatment Presented{fmt$(patient.treatment_presented)}
Treatment Accepted{patient.is_accepted ? fmt$(patient.treatment_accepted) : "—"}
Paid Today{fmt$(patient.amount_paid_today)}
Records Date{fmtDateShort(patient.records_date)}
Coordinator{patient.treatment_coordinator || "—"}
Assistant{patient.assistant || "—"}
Follow-up
Next Follow-up {patient.next_follow_up_date ? ( <> {fmtDateShort(patient.next_follow_up_date)} {fuDays != null &&
{fuDays < 0 ? `${Math.abs(fuDays)}d overdue` : fuDays === 0 ? "today" : `in ${fuDays}d`}
} ) : "—"}
Last Contact{fmtDateShort(patient.last_contact_date)}
{logging && ( setLogging(false)} onSaved={() => { setLogging(false); load(); onUpdate(); showToast("Contact logged"); }} /> )}
); } function PatientEditForm({ patient, stages, onSaved }) { const [form, setForm] = useState({ consult_date: patient.consult_date || "", name: patient.name || "", referral_source: patient.referral_source || "", treatment_coordinator: patient.treatment_coordinator || "", assistant: patient.assistant || "", treatment_presented: patient.treatment_presented || 0, records_date: patient.records_date || "", amount_paid_today: patient.amount_paid_today || 0, treatment_accepted: patient.treatment_accepted || 0, stage: patient.stage || "", next_follow_up_date: patient.next_follow_up_date || "", phone: patient.phone || "", email: patient.email || "", notes: patient.notes || "", }); const set = (k, v) => setForm({ ...form, [k]: v }); const save = async () => { const body = { ...form }; body.treatment_presented = parseFloat(body.treatment_presented) || 0; body.treatment_accepted = parseFloat(body.treatment_accepted) || 0; body.amount_paid_today = parseFloat(body.amount_paid_today) || 0; if (!body.records_date) body.records_date = null; if (!body.next_follow_up_date) body.next_follow_up_date = null; await apiSend(`/api/patients/${patient.id}`, "PATCH", body); onSaved(); }; return (
set("consult_date", e.target.value)} />
set("name", e.target.value)} />
set("referral_source", e.target.value)} />
set("treatment_coordinator", e.target.value)} />
set("assistant", e.target.value)} />
set("treatment_presented", e.target.value)} />
set("treatment_accepted", e.target.value)} />
set("records_date", e.target.value)} />
set("amount_paid_today", e.target.value)} />
set("next_follow_up_date", e.target.value)} />
set("phone", e.target.value)} />
set("email", e.target.value)} />