import { type ComponentPropsWithoutRef, type ReactNode } from 'react'; import { type VariantProps } from 'class-variance-authority'; import { type PatientFieldSection } from '../_shared/patient-fields'; declare const rootVariants: (props?: ({ surface?: "elevated" | "flat" | null | undefined; density?: "comfortable" | "compact" | null | undefined; } & import("class-variance-authority/types").ClassProp) | undefined) => string; /** Patient phone number — already formatted for display by the consumer. */ export interface PatientSummaryCardPhone { /** Display string, e.g. `"+39 055 123 4567"`. Compiled into a `tel:` link. */ prefixAndNumber: string; /** Optional label that distinguishes this number (e.g. "Mobile"). */ label?: string; /** Whether SMS is enabled for this number — shows a small "SMS" chip. */ smsEnabled?: boolean; } /** A family relation row — links one patient to another. */ export interface PatientSummaryCardFamilyRelation { /** Localised relation label, consumer-supplied (e.g. "Mother", "Child"). */ relation: string; /** The related patient — name + optional in-app profile URL. */ relatedPatient: { name: string; url?: string; }; } /** Operator the patient is assigned to. */ export interface PatientSummaryCardAssignee { name: string; avatarUrl?: string; } /** AI-consent grant metadata — structural only, never the consented content. */ export interface PatientSummaryCardAiConsent { /** ISO-8601 / display string of when consent was granted. */ grantedAt: string; /** Optional name of who recorded the grant. */ grantedBy?: string; } /** Addressable attention flags — the keys `onFlagActivate` accepts. */ export type PatientSummaryCardFlagId = 'highlightedAnamnesis' | 'unsignedDocuments' | 'unpaid'; /** Status flags rendered as glyph badges (counts / amounts only — no PHI). */ export interface PatientSummaryCardFlags { /** Number of anamnesis answers highlighted for clinical attention. */ highlightedAnamnesisCount?: number; /** Outstanding balance in the smallest currency unit (cents). */ unpaidAmountCents?: number; /** Number of documents awaiting the patient's signature. */ unsignedDocumentsCount?: number; } /** Marketing-consent tri-state. */ export type PatientSummaryCardMarketingConsent = 'no' | 'yes' | 'not_specified'; export interface PatientSummaryCardHandle { /** Structural snapshot — identifiers and counts only, never patient identity. */ getSummary: () => { id?: string; hasUnpaid: boolean; unsignedDocumentsCount: number; highlightedAnamnesisCount: number; aiConsentGranted: boolean; }; } export interface PatientSummaryCardProps extends Omit, 'aria-label' | 'children'> { /** Patient display name. Rendered as the heading. */ name: string; /** Honorific — `'mr'` / `'ms'`. Prepended to the name in the heading. */ title?: 'mr' | 'ms'; /** Patient age in whole years — rendered in the identity line. */ ageYears?: number; /** Date of birth — already formatted for display by the consumer. */ dateOfBirth?: string; /** Biological sex marker — `'m'` / `'f'`. Drives the identity-line glyph copy. */ gender?: 'm' | 'f'; /** Optional avatar / photo URL. Falls back to initials. */ avatarUrl?: string; /** * In-app patient profile URL. When safe, the heading becomes a link. * Guarded by the shared `isSafeEntityUrl` allow-list — unsafe URLs are * dropped and the heading renders as plain text. */ patientUrl?: string; /** * Patient fields in the shared model — the SAME `sections` shape * `PatientDetails` consumes (`@alfadocs/ui-kit` `PatientFieldSection`). * When provided, the card renders these (honouring `visibleFieldOrder`) * instead of the legacy contact props, so a consumer defines its patient- * field registry once and reuses it across every patient surface. * * The card renders each field's `label`, `value`, and `icon` only — it is * flat (section headings are not shown in the body) and never inline-edits; * `sensitive` / `copyable` / `mono` / `editable` are honoured by * `PatientDetails`, not the card (so the PHI lock glyph does not appear here). * * Pass `onVisibleFieldsChange` alongside `sections` to make THIS placement * self-curating (a "Customize fields" cog appears — show/hide + drag-and-drop * reorder). */ sections?: PatientFieldSection[]; /** * Ordered visible field ids for THIS placement. The order is a * per-INSTANCE, per-CONTEXT preference the kit never persists — wire it to * whatever scope the consumer wants (e.g. a global per-user setting, or a * different config in the care-plan view vs the patient folder). The same * field vocabulary can therefore display differently in different parts of * the app. Omit (`undefined`) ⇒ show every field; an explicit empty array * `[]` ⇒ show none (a card that starts collapsed to name + identity chips and * reveals fields via the cog). Also applied to the legacy contact rows (ids * `email` / `phone` / `cityProvince` / `marketingConsent` / `aiConsent` / * `assignedTo`). */ visibleFieldOrder?: string[]; /** * Make this card's field set user-customizable. When provided alongside * `sections`, a "Customize fields" cog renders in the header (show/hide + * drag-and-drop / Alt+Arrow reorder), and this fires with the next ordered * visible set. The consumer owns persistence + its scope — editing here * writes only THIS context's preference, never a shared/global one. */ onVisibleFieldsChange?: (orderedIds: string[]) => void; /** @deprecated Pass via `sections`. Patient email — `mailto:` link when `emailEnabled`. */ email?: string; /** Whether email contact is enabled — gates the `mailto:` link. */ emailEnabled?: boolean; /** Phone number block. Compiled into a `tel:` link. */ phone?: PatientSummaryCardPhone; /** City / province display string. */ cityProvince?: string; /** Marketing-consent tri-state. */ marketingConsent?: PatientSummaryCardMarketingConsent; /** AI-consent grant metadata. When present, an "AI consent" row renders. */ aiConsent?: PatientSummaryCardAiConsent; /** Counts / amounts surfaced as glyph badges. */ flags?: PatientSummaryCardFlags; /** Family relations — rendered as `` chips, optionally linked. */ familyRelations?: PatientSummaryCardFamilyRelation[]; /** Operator the patient is assigned to. */ assignedTo?: PatientSummaryCardAssignee; /** ISO-4217 currency code for the unpaid-amount chip. Defaults to `EUR`. */ currency?: string; /** BCP-47 locale override. Defaults to the active i18next language. */ locale?: string; /** Render the skeleton loading placeholder. */ loading?: boolean; /** Rendered at the inline-end of the heading row (e.g. an action menu). */ actionSlot?: ReactNode; /** * Make an attention chip actionable. A handler turns that chip into a * button — "2 unsigned documents" opens the signing flow, the unpaid * balance opens invoicing. Without a handler the chip stays a read-only * badge, which is the default: most surfaces have nowhere to send the * reader. */ onFlagActivate?: Partial void>>; /** * Explain a chip on hover / focus. The chip states WHAT ("2 unsigned * documents"); this states what the reader cannot see — how the signature * was requested, why the balance is outstanding. * * A string renders a `Tooltip`; a node renders a `HoverCard` with that node * as its content, for a host that wants the fuller card grammar (an eyebrow, * fact rows, a hint line). Either way the chip's own text stays the * accessible name and the surface only describes it. */ flagHover?: Partial>; /** * Accessible name for the open button a hover CARD shows in its top-end * corner. The button appears only where the flag has BOTH a card and an * `onFlagActivate` handler — it mirrors the chip's own click so a pointer * that has travelled into the card can still act. Name the destination * ("Open signing"), not the gesture. * * Without a label there is no button: a card that merely describes should * not sprout an affordance the chip does not have. */ flagOpenLabel?: Partial>; /** * Extra chips appended to the attention row, for signals the CARD cannot * model because they do not belong to the patient. An appointment panel * adds its own to-invoice and paid-online chips here; the card keeps its * patient-level flags and does not grow an appointment vocabulary. */ extraChips?: ReactNode; /** * Master switch — show the edit affordance on fields marked `editable` in * `sections`. The card edits through the SAME shared control as * `PatientDetails`, so a field offers the same affordance and the same * validation wherever it is shown. */ editable?: boolean; /** * The single write channel. A rejected promise keeps the row in edit mode * and shows the message inline — the card never optimistically mutates the * value it was given. */ onFieldSave?: (fieldId: string, value: unknown) => Promise; /** Return a message to block the save and keep the row in edit mode. */ validateField?: (fieldId: string, value: unknown) => string | null; /** Fires when the whole card / heading is activated. */ onActivate?: () => void; /** `'elevated'` (default) wraps in ``; `'flat'` drops the chrome. */ surface?: 'flat' | 'elevated'; /** `'comfortable'` (default) reads as a header; `'compact'` for asides. */ density?: 'comfortable' | 'compact'; /** Override the default region aria-label. */ 'aria-label'?: string; /** Agent-readiness consumer id, surfaced as `data-component-id`. */ id?: string; } export declare const PatientSummaryCard: import("react").ForwardRefExoticComponent>; /** Variant unions re-exported for downstream typing. */ export type PatientSummaryCardSurface = NonNullable['surface']>; export type PatientSummaryCardDensity = NonNullable['density']>; export {}; //# sourceMappingURL=patient-summary-card.d.ts.map