import React, { useId, useState } from 'react'; import { Search } from 'lucide-react'; import { shortList } from '../../../utils/recordActions'; import { KINDS_WITHOUT_A_FORM } from '../../../utils/recordFieldCatalogue.generated'; import { seedForThing, splitOnPrefix, type RecordThing } from '../../../utils/recordThingSearch'; import type { ProposalKind } from '../../../utils/recordProposals'; import { useRecordThingSearch } from './useRecordThingSearch'; import { useIsPhoneWidth } from '../../../hooks/useIsPhoneWidth'; /** * The fallback for whatever the visit did not cover. * * Drawn in `mockups/practitioner/encounter.html` as two groups under one search box: * * What you add most * Metformin 500 mg tablet prescription * Type 2 diabetes mellitus diagnosis * Or by kind * Prescription - Diagnosis - Referral - Test or lab order * * THE LIST HOLDS THINGS, NOT KINDS, and the deck says why: *"A clinician does not search for * 'Prescription', they search for metformin - the kind is decided by what they pick, which is Epic's * whole answer to a chart too large to menu."* The kind is an OUTCOME of the pick, shown on the row, * never a question asked first. * * CORRECTED 2026-09-04. This surface previously searched the four KIND LABELS and showed nothing * else - which is a menu of four with a filter on it, and *"Epic's answer to too many things is never a * better menu"* is the one rule the whole surface exists to obey. The kinds are still here, under * *"Or by kind"*, for the thing that is on nobody's list yet. * * IT IS ALSO THE ONLY WAY TWO KINDS ARE REACHABLE AT ALL. A referral and a lab order have no resource * form, so nothing the note describes can ever propose one. */ interface Props { /** What this clinician has added most. Empty until there is a history, which is expected on day one. */ mostAdded?: readonly RecordThing[]; /** Kinds this clinician reached for recently. Orders the "Or by kind" group as it builds up. */ recents?: readonly ProposalKind[]; /** The kinds this specialty reaches for. Seeds that order before there are any recents. */ specialty?: readonly ProposalKind[]; /** A kind, and whatever the picked thing prefills - empty when the kind itself was chosen. */ onChoose: (kind: ProposalKind, prefilled: Record) => void; } const KIND_LABEL: Partial> = { medication: 'prescription', condition: 'diagnosis', labOrder: 'lab order', }; const ThingRow: React.FC<{ thing: RecordThing; term: string; onChoose: Props['onChoose'] }> = ({ thing, term, onChoose, }) => { const split = splitOnPrefix(thing.label, term); return (
  • ); }; export const AddSomethingElse: React.FC = ({ mostAdded, recents, specialty, onChoose }) => { const [query, setQuery] = useState(''); const { searching, things, unavailable } = useRecordThingSearch(query); // At 390 the field is about 170px, and the drawn hint was cut at "...or type". A phone gets the field's // own name, which fits whole. const isPhone = useIsPhoneWidth(); const searchId = useId(); const typed = query.trim() !== ''; const kinds = shortList(recents, specialty); return (
    {/* A visible label, as the deck draws it; a placeholder alone disappears as soon as someone types. */}
    {typed ? (
    Matches
    {searching &&

    Searching…

    } {/* A SEARCH THAT FINDS NOTHING SAYS SO, rather than falling back to the kinds. Silently showing them reads as "these are your matches" and sends somebody hunting for what they typed among four rows with nothing to do with it. */} {!searching && things.length === 0 && (

    Nothing matches “{query.trim()}”. Try a different word.

    )}
      {things.map((thing) => ( ))}
    {/* "WE COULD NOT LOOK" IS NOT "THERE IS NOTHING". A clinician told nothing matched, when the drug lookup was simply down, concludes the drug is not orderable here and goes elsewhere - which is worse than being told to try again. */} {unavailable.length > 0 && (

    Could not search {unavailable.join(' or ')} just now, so any of those are missing from this list.

    )}
    ) : ( <> {/* EMPTY ON DAY ONE, AND THAT IS THE ACCEPTED TRADE - the same one already ruled on the kind list: recents beat specialty as they accumulate, and a group with no history behind it is drawn as absent rather than as a heading over nothing. */} {mostAdded && mostAdded.length > 0 && (
    What you add most
      {mostAdded.map((thing) => ( ))}
    )}
    Or by kind
      {kinds.map((action) => (
    • ))}
    )}
    ); }; export default AddSomethingElse;