import React from 'react'; import { Inbox } from 'lucide-react'; import type { OwedWork, OwedWorkRow } from './owedWork'; /** * "Waiting on you" -. The practitioner's owed work, above the day. * * A CARD THAT GROWS DOWNWARD, not a band across the top. The band was drawn first and rejected: * Spencer, *"we end up with that big empty space that makes the view seem lop-sided"* - with a single row * it left a hole the width of the screen and pushed the patient panel down for everyone. One row or four, * this layout holds. * * It takes its rows as a PROP and reaches for nothing. The view toggle cannot filter what the component * never sees (design §4.2 - a nurse practitioner in "Rooming patients" must not have their own unfinished * note hidden by a view setting), and the derivation stays unit-testable without mounting anything. */ interface Props { work: OwedWork; /** Which row's list is open in the borrowed panel, so the row can say it is the one showing. */ openRowId?: OwedWorkRow['id']; onOpenRow: (id: OwedWorkRow['id']) => void; /** * §6 - ONE LINE at portrait width. **This is the only place the card changes shape.** * * At 44px rows the full card costs three patients' worth of the visible day, and the day is what a * portrait tablet has least room for. It does not vanish: hiding owed work to make room for today * inverts the thing the card exists to fix. */ compact?: boolean; } export const WaitingOnYouCard: React.FC = ({ work, openRowId, onOpenRow, compact = false }) => { // Nothing rendered until we know. NOT an all-clear: "Nothing waiting on you" over a list that has // not arrived is an assertion nobody measured, and this card's whole job is to be believed. // // A SOURCE THAT COULD NOT BE READ IS NOT "not yet", and conflating them is how this card vanished // off a practitioner's screen entirely: one of its three sources was unreachable, so it waited for // an answer that was never coming and rendered nothing at all. An unreadable source renders the // card and is NAMED on it - the reader learns their list is incomplete, which is the one thing they // can act on. const incomplete = work.unreadable.length > 0 || work.partial.length > 0; if (work.rows.length === 0 && !work.nothingOwed && !incomplete) return null; if (compact) { const total = work.rows.reduce((sum, row) => sum + row.count, 0); // The DEADLINE survives the collapse and the labels do not. Everything else on this card can be // re-read by opening it; the sentence with a destroy-by date is the one that cannot wait. const withDeadline = work.rows.find((row) => row.detail); const deadline = withDeadline?.detail; const deadlineShort = withDeadline?.detailShort; /* * - THIS RENDERS IN A 64px RAIL, AND THE PREVIOUS LAYOUT DID THE OPPOSITE OF WHAT THE * COMMENT ABOVE PROMISES. Measured at container 743: `Waiting on you` came out **49 × 40px against * a 20px line-height** - two lines, wrapping as *"Waiting" / "on you"* - while the deadline sat * behind `ml-auto truncate` in whatever was left of ~40px of content box, which was nothing. The * label was kept and the deadline was lost, exactly backwards. * * SO IT NOW MATCHES THE RAIL IT LIVES IN rather than inventing a third idiom. The collapsed * `EncounterQueue` directly beneath is a vertical stack of dot-over-count with every label carried * in `title` (EncounterQueue.tsx:125-143). This is that, plus the one thing the queue has no reason * to carry: a destroy-by date. * * Do not "restore" the visible label. 64px minus this padding is ~48px of content; the label is * ~90px at 14px, so it cannot be un-wrapped, only shrunk to something a clinician cannot read at * arm's length on a tablet. It is not lost - it is the button's accessible NAME, so a screen reader * and a hover both still get the whole sentence, deadline included. */ // AT LEAST, WHEN PART OF IT COULD NOT BE READ. The rail has room for one number and no room to // explain it, so the number has to carry its own honesty: a bare "0" here, with a source // unreachable, is the all-clear said quietly - and it is the same false zero the expanded card // refuses to print in words. const spoken = work.nothingOwed ? 'Nothing waiting on you' : work.unreadable.length > 0 ? `At least ${total} waiting on you — ${work.unreadable.join(' and ')} could not be checked` : work.partial.length > 0 ? `At least ${total} waiting on you — ${work.partial.join(' and ')} could only be partly checked` : `${total} waiting on you${deadline ? ` — ${deadline}` : ''}`; return ( ); } return (

Waiting on you

{/* NAMED, NEVER COUNTED. "One source unavailable" tells a clinician nothing they can use; the name of the list tells them exactly which part of their day they cannot see. */} {work.unreadable.length > 0 && (

{work.unreadable.join(' and ')} could not be checked just now, so this list may not be complete.

)} {work.partial.length > 0 && (

{work.partial.join(' and ')} could only be partly checked, so this list is incomplete and more may be waiting on you.

)} {work.nothingOwed ? ( // A STATED all-clear, never an absent card. Absence reads as "not built yet"; this reads // as "we looked" - design §4.1.

Nothing waiting on you.

) : work.rows.length === 0 ? null : ( )}
); }; export default WaitingOnYouCard;