import type { CheckInStatus, ContextRecord, PatientSummary } from "../api/types"; /** Tinted pills: each state has its own colour and icon, and always its words (never colour alone). */ export type PillTone = "grey" | "indigo" | "green" | "amber" | "purple" | "blue" | "pink" | "red" | "red-outline"; export type PillIcon = | "sent" | "ringing" | "live" | "completed" | "missed" | "later" | "not_reached" | "expired" | "declined" | "identity" | "ended_early" | "cancelled" | "urgent" | "queued" | "reading" | "read" | "failed" | "held_back" | "connected" | "paused" | "stopped" | "clinic" | "draft"; export type Pill = { label: string; tone: PillTone; icon: PillIcon; meaning: string }; /** YCI-28: every check-in state the backend sends (docs/api-contract.md), in the order a call moves. */ export const checkInPills: Record = { sent: { label: "Sent", tone: "grey", icon: "sent", meaning: "Asked. It waits in MARMAR Health until it may ring." }, ringing: { label: "Ringing", tone: "indigo", icon: "ringing", meaning: "Yasmar is ringing the patient's phone." }, in_progress: { label: "Live", tone: "green", icon: "live", meaning: "On the call now. Notes arrive as they are made." }, completed: { label: "Completed", tone: "green", icon: "completed", meaning: "The call finished, with notes and a summary." }, missed: { label: "Missed", tone: "amber", icon: "missed", meaning: "Nobody answered. It can ring again inside the window." }, later: { label: "Later", tone: "blue", icon: "later", meaning: "The patient chose a later time inside the window." }, not_reached: { label: "Not reached", tone: "amber", icon: "not_reached", meaning: "The window closed without a call." }, declined: { label: "Declined", tone: "purple", icon: "declined", meaning: "The patient said no. Nothing was asked." }, identity_not_confirmed: { label: "Identity not confirmed", tone: "pink", icon: "identity", meaning: "Whoever answered could not confirm who they were, so no questions were asked.", }, ended_early: { label: "Ended early", tone: "amber", icon: "ended_early", meaning: "The call stopped before the end. It can carry on while the window is open." }, cancelled: { label: "Cancelled", tone: "red-outline", icon: "cancelled", meaning: "Cancelled by you, or because sharing or calls were turned off." }, }; /** Urgent is a flag beside the state, never a state of its own. */ export const urgentPill: Pill = { label: "Urgent", tone: "red", icon: "urgent", meaning: "A red-flag note came up on the call. Shown beside the state." }; /** CHK-5: a finding's clinician wording the clinical team has not signed off (wording "derived" or "engine"). Quiet, beside the tier. */ export const draftWordingPill: Pill = { label: "Not yet signed off for clinicians", tone: "grey", icon: "draft", meaning: "MARMAR's clinical team has not signed off this wording for clinicians yet. The rule itself is in Why this finding.", }; // The backend's own type also names `expired`; the contract says it sends not_reached instead. const extra: Record = { expired: { label: "Expired", tone: "amber", icon: "expired", meaning: "The window closed without a call." }, }; /** The pill for a state, or a grey one in plain words for a state this screen does not know yet. */ export function checkInPill(status: string): Pill { const known = (checkInPills as Record)[status] ?? extra[status]; if (known) return known; const words = status.replace(/_/g, " "); return { label: words.charAt(0).toUpperCase() + words.slice(1), tone: "grey", icon: "sent", meaning: "" }; } /** The dot tone the older status chips use (green, amber, red or grey), from a pill's colour. */ export function dotTone(tone: PillTone): string { if (tone === "green" || tone === "amber") return tone; if (tone === "red" || tone === "red-outline") return "red"; return ""; } /** REC-4, REC-7: a record's reading state. Held back comes first: it is not used until the clinician decides. */ export function recordPill(r: Pick): Pill { if (r.heldBack) return { label: "Held back", tone: "pink", icon: "held_back", meaning: "It may name another patient. It is not used until you decide." }; switch (r.reading) { case "read": return { label: `Read ยท ${r.lineCount} ${r.lineCount === 1 ? "line" : "lines"}`, tone: "green", icon: "read", meaning: "Read. Its lines can be reviewed on the Check tab." }; case "failed": return { label: "Not read", tone: "red-outline", icon: "failed", meaning: "It could not be read." }; case "reading": return { label: "Reading", tone: "indigo", icon: "reading", meaning: "Being read now." }; default: return { label: "Waiting to be read", tone: "grey", icon: "queued", meaning: "In line to be read." }; } } /** The patient's state on the right of the header: how the clinician has them. */ export function patientStatePill(p: Pick): Pill { const s = p.sharing; if (!s) return { label: "Clinic-added", tone: "grey", icon: "clinic", meaning: "You added this patient and the records." }; if (s.status === "paused") return { label: "Paused", tone: "amber", icon: "paused", meaning: "New data is hidden until sharing resumes." }; if (s.status === "stopped") return { label: "Sharing stopped", tone: "grey", icon: "stopped", meaning: "Live access has ended." }; return { label: "Connected", tone: "green", icon: "connected", meaning: "Shared from MARMAR Health." }; }