import type { MouseEvent } from "react";
import { useState } from "react";
import { clinicianApi } from "../../api/client";
import type { CheckInListItem, PatientDetail } from "../../api/types";
import { firstName, whenLabel } from "../../logic/format";
import { cancellable, notesLabel, summaryLabel } from "../../logic/patient-detail";
import { checkInPill, checkInPills, urgentPill } from "../../logic/pills";
import { Button, cn, Drawer, EmptyState, Icon, Modal, SectionHeader, tbl } from "../kit";
import { SectionNote } from "../patient/bits";
import { Pill } from "../Pill";
import { Link, navigate } from "../router";
import { RowMenu } from "../RowMenu";
import { errorText, ErrorNote, Spinner, useLoad, useToast } from "../ui";
const callPath = (patientId: string, id: string) => `/app/patients/${patientId}/check-ins/${id}`;
/** YCI-28: the check-ins this clinician asked for, one row each, newest first. A row opens the call. */
export function CheckInsTab({ patient }: { patient: PatientDetail }) {
const list = useLoad(() => clinicianApi.checkIns(patient.id), [patient.id]);
const [legend, setLegend] = useState(false);
const [cancelling, setCancelling] = useState<CheckInListItem | null>(null);
const toast = useToast();
const first = firstName(patient.name);
const rows = list.data?.checkIns ?? [];
const cancel = async (c: CheckInListItem) => {
setCancelling(null);
try {
await clinicianApi.cancelCheckIn(c.id);
list.reload(true);
toast.show("Check-in cancelled. Yasmar will not ring.");
} catch (e) {
toast.show(errorText(e), true);
}
};
const open = (e: MouseEvent, c: CheckInListItem) => {
// The row is a mouse target; keyboard users have the link in the first cell.
if ((e.target as HTMLElement).closest("a, button, [role=menu]")) return;
navigate(callPath(patient.id, c.id));
};
return (
<section className="flex flex-col gap-3" aria-labelledby="checkins-title">
{toast.node}
<SectionHeader
title={<span id="checkins-title">Check-ins you asked for</span>}
count={rows.length > 0 ? rows.length : undefined}
action={
<Button variant="ghost" size="sm" className="text-muted" onClick={() => setLegend(true)}>
<Icon name="information-line" size={15} /> What each state means
</Button>
}
/>
<SectionNote>Yasmar calls {first} through MARMAR Health with your questions. Notes appear live, then a summary for you.</SectionNote>
{list.loading && !list.data && <Spinner />}
<ErrorNote error={list.error} onRetry={() => list.reload()} />
{rows.length > 0 && (
<div className="min-w-0">
<table className={tbl.table}>
<thead className={tbl.head}>
<tr>
<th scope="col" className={tbl.th}>Requested</th>
<th scope="col" className={tbl.th}>Status</th>
<th scope="col" className={tbl.th}>Last change</th>
<th scope="col" className={tbl.th}>Notes</th>
<th scope="col" className={tbl.th}>Summary</th>
<th scope="col" className={tbl.th}>
<span className="sr-only">Actions</span>
</th>
</tr>
</thead>
<tbody className={tbl.body}>
{rows.map((c) => (
<tr key={c.id} className={cn(tbl.row, tbl.clickable, c.urgent && "bg-red-fill/40 hover:bg-red-fill/60")} onClick={(e) => open(e, c)}>
<td className={tbl.lead}>
<Link className={cn(tbl.name, "tabular-nums")} to={callPath(patient.id, c.id)}>
{whenLabel(c.requestedAt)}
<span className="sr-only">: Yasmar call, {checkInPill(c.status).label}</span>
</Link>
</td>
<td data-label="Status" className={tbl.td}>
<span className="inline-flex flex-wrap items-center gap-1.5 @max-[640px]/pd:justify-end">
<Pill pill={checkInPill(c.status)} />
{c.urgent && <Pill pill={urgentPill} />}
</span>
</td>
<td data-label="Last change" className={cn(tbl.td, "whitespace-nowrap text-cell tabular-nums")}>
{whenLabel(c.statusAt)}
</td>
<td data-label="Notes" className={cn(tbl.td, "tabular-nums")}>
{c.noteCount ? (
<span className={c.unreadNotes ? "font-medium text-ink" : undefined}>
{notesLabel(c)}
{c.unreadNotes > 0 && <span aria-hidden="true" className="ml-1.5 inline-block size-1.5 rounded-full bg-blue-icon align-middle" />}
</span>
) : (
<span className="text-subtle">{notesLabel(c)}</span>
)}
</td>
<td data-label="Summary" className={tbl.td}>
{c.summaryReady ? <span className="text-ink">Ready</span> : <span className="text-subtle">{summaryLabel(c)}</span>}
</td>
<td className={tbl.menu}>
<RowMenu
label={`More for the check-in asked ${whenLabel(c.requestedAt)}`}
items={[
{ label: "Open the call", icon: "arrow-right-up-line", onSelect: () => navigate(callPath(patient.id, c.id)) },
...(cancellable(c.status) ? [{ label: "Cancel this check-in", icon: "close-circle-line" as const, danger: true, onSelect: () => setCancelling(c) }] : []),
]}
/>
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
{list.data && !rows.length && <EmptyState title="No check-ins yet." />}
<StateLegend open={legend} onClose={() => setLegend(false)} />
<Modal open={!!cancelling} title="Cancel this check-in?" onClose={() => setCancelling(null)}>
<p className="m-0 text-[13.5px] leading-5 text-body">Yasmar will not ring {first} for it. This cannot be undone; you can ask for a new check-in later.</p>
<div className="flex flex-wrap justify-end gap-2 pt-1">
<Button variant="quiet" onClick={() => setCancelling(null)}>
Keep it
</Button>
<Button variant="red" onClick={() => cancelling && void cancel(cancelling)}>
<Icon name="close-circle-line" size={15} /> Cancel check-in
</Button>
</div>
</Modal>
</section>
);
}
/** Sources in drawers: what each state means, with the pill it shows as. */
function StateLegend({ open, onClose }: { open: boolean; onClose: () => void }) {
return (
<Drawer open={open} title="What each state means" onClose={onClose}>
<dl className="m-0 flex flex-col">
{[...Object.values(checkInPills), urgentPill].map((pill) => (
<div key={pill.label} className="flex flex-col items-start gap-1.5 py-3 shadow-[inset_0_-1px_0_var(--color-hairline)]">
<dt>
<Pill pill={pill} title="" />
</dt>
<dd className="m-0 text-[13px] leading-[19px] text-cell">{pill.meaning}</dd>
</div>
))}
</dl>
<p className="m-0 text-[12.5px] leading-[18px] text-muted">Every change is kept with its time. Open a call to see them in order.</p>
</Drawer>
);
}