import { useMemo } from "react"; import { useNavigate } from "react-router-dom"; import { ChevronRight } from "lucide-react"; import { usePatientNav } from "../patientNav.tsx"; import { usePatientUnpaidInvoices } from "./usePatientUnpaidInvoices.tsx"; import { exactOwedCents } from "./exactOwedCents"; import { formatMoney } from "./patientAccountSummary.ts"; import { resolvePatientHomeDoors, type ResolvedDoor } from "./patientHomeDoors.ts"; import { doorQuantity } from "./patientHomeDoorCounts.ts"; import { usePatientHomeDoorCounts } from "./usePatientHomeDoorCounts.ts"; import { usePracticeSwitcher } from "../../../components/PracticeSwitcher/PracticeSwitcherProvider"; /** * "Everything else" - the named doors at the bottom of the patient home., design spec ยง7. * * This replaced a forty-row dump of the navigation tree, and the reason is not tidiness: a list * that long at the bottom of a phone screen reproduces the "the bottom does not get read" mechanism * the ranked queue above it was designed around. See `patientHomeDoors.ts` for the two properties of * the flat list that had to survive the change - drift and the adolescent filter - and how they do. * * TWO KINDS OF BADGE, and collapsing them would break the amber. ATTENTION (`2 unread`) means * something is outstanding. QUANTITY (how many practices) means nothing is wrong. Painting both amber * makes every row look like a problem and the hue then means nothing anywhere - the same wallpaper * failure as a count that never reaches zero. * Quantities are read from the lists their destination pages load, never counted a second way here. */ const Door = ({ door, value, quantity }: { door: ResolvedDoor; value?: string; quantity?: string }) => { const navigate = useNavigate(); return ( ); }; export const EverythingElse = () => { const navItems = usePatientNav(); const doors = useMemo(() => resolvePatientHomeDoors(navItems), [navItems]); // READ FROM THE SHARED PROVIDER, never counted here. It is the same list the summary band and the // ranked queue read, so the money on this row cannot disagree with the money above it - which is // the whole reason the provider exists. const unpaid = usePatientUnpaidInvoices(); const owed = exactOwedCents(unpaid); // Answered without an exact total - a bill unread, cut short or of unknown balance - says so rather than nothing. const billingValue = owed ? formatMoney(owed) : unpaid && owed === undefined ? "Amount not confirmed" : undefined; const counts = usePatientHomeDoorCounts(); const { practicesFreshness, checkPractices } = usePracticeSwitcher(); // Nothing published (outside the dashboard shell, or a staff workspace) - render nothing rather // than an empty box asserting the patient has nowhere to go. if (doors.length === 0) return null; // Spencer, 2026-08-21: "EVERYTHING ELSE goes." On the first screen a patient ever // sees, it reads as a leftovers bin - and the rows under it are the main destinations of the // whole portal. // // The heading was REMOVED, not hidden, and the section still needs an accessible name: these // rows ARE the patient portal's navigation, and without a name a screen-reader user gets an // unlabelled region instead of a landmark they can jump to. a nav with a label, which is the // element that was always correct for a list of destinations, doing the job the heading did. // // AND IT IS BACK, AS A CAPTION. The approved overview deck of 2026-08-28 draws it again at every // width - small, uppercase, quiet - which is the form that answers the 08-21 objection: it names // the group without competing with the rows under it for the eye. The nav label stays regardless. return ( ); }; export default EverythingElse;