marmar-context / web / context / src / clinician / patient / Overview.tsx
Overview.tsx
Raw
import { clinicianApi } from "../../api/client";
import type { CheckRun, PatientDetail } from "../../api/types";
import { firstName, listNames, whenLabel } from "../../logic/format";
import { checkInPill, urgentPill } from "../../logic/pills";
import { FindingsMix } from "../charts";
import { buttonVariants, Card, Icon, Notice, SectionHeader } from "../kit";
import { Pill } from "../Pill";
import { Link } from "../router";
import { Spinner, useLoad } from "../ui";
import { tabPath } from "./links";

const linkClass = "inline-flex items-center gap-1 self-start text-[13px] font-medium text-ink underline decoration-line underline-offset-4 hover:decoration-ink";

/** CHK-8: new information since the last check, with Run the check again. */
export function NewInformation({ patient, action = true }: { patient: PatientDetail; action?: boolean }) {
  if (!patient.newInformation && !patient.attention.newSinceLastCheck) return null;
  return (
    <Notice
      role="status"
      icon="sparkling-line"
      title={patient.lastCheckId ? "New information since your last check" : "New information to check"}
      actions={
        action ? (
          <Link className={buttonVariants({ variant: "primary", size: "sm", className: "no-underline" })} to={tabPath(patient.id, "check")}>
            {patient.lastCheckId ? "Run the check again" : "Start a check"}
          </Link>
        ) : undefined
      }
    >
      {patient.newInformation && (
        <p className="m-0">
          {listNames(patient.newInformation.items)} · {whenLabel(patient.newInformation.since)}
        </p>
      )}
      {!action && <p className="m-0 text-muted">Read the records again to include it.</p>}
    </Notice>
  );
}

const OpenCheck = ({ patientId }: { patientId: string }) => (
  <Link className={linkClass} to={tabPath(patientId, "check")}>
    Open the check <Icon name="arrow-right-line" size={14} />
  </Link>
);

/** What changed, the last check in one line, and the latest check-ins. The rail holds the sharing details. */
export function Overview({ patient, lastCheck, lastCheckLoading }: { patient: PatientDetail; lastCheck: CheckRun | null; lastCheckLoading: boolean }) {
  const checkIns = useLoad(() => clinicianApi.checkIns(patient.id), [patient.id]);
  const first = firstName(patient.name);
  const last = lastCheck;
  const recent = (checkIns.data?.checkIns ?? []).slice(0, 3);
  const findings = last?.assessment.contextual.findings ?? [];
  return (
    <div className="flex flex-col gap-4">
      <NewInformation patient={patient} />
      <div className="grid gap-4 md:grid-cols-2">
        <section aria-label="Last check">
          <Card as="div" className="flex h-full flex-col gap-4">
            <SectionHeader title="Last check" />
            {last ? (
              <>
                {findings.length ? (
                  <p className="m-0 flex flex-wrap items-baseline gap-x-2">
                    <span className="text-[38px] leading-[42px] font-semibold tracking-[-0.03em] text-ink tabular-nums">{findings.length}</span>
                    <span className="text-[15px] font-medium text-subtle">{findings.length === 1 ? "finding" : "findings"} for clinician review</span>
                  </p>
                ) : (
                  <p className="m-0 text-[15px] leading-[22px] font-medium text-ink">No findings. This does not mean the prescription is safe.</p>
                )}
                <FindingsMix findings={findings} layout="inline" />
                <p className="m-0 text-[12.5px] leading-[18px] text-muted">
                  Ran {whenLabel(last.ranAt)} by {last.ranBy} · rules <span className="font-mono">{last.versions.rules}</span>
                  {last.versions.rulesReviewed ? "" : " (not yet reviewed)"}
                </p>
                <OpenCheck patientId={patient.id} />
              </>
            ) : patient.lastCheckId ? (
              lastCheckLoading ? (
                <Spinner label="Opening the last check" />
              ) : (
                <OpenCheck patientId={patient.id} />
              )
            ) : (
              <>
                <p className="m-0 text-[13.5px] leading-5 text-body">No check yet. Add {first}'s records, review each fact, then run the check.</p>
                <Link className={buttonVariants({ variant: "quiet", size: "sm", className: "self-start no-underline" })} to={tabPath(patient.id, "check")}>
                  Start a check
                </Link>
              </>
            )}
          </Card>
        </section>
        <section aria-label="Check-ins you asked for">
          <Card as="div" className="flex h-full flex-col gap-3">
            <SectionHeader title="Check-ins you asked for" />
            {recent.length > 0 && (
              <ul className="m-0 -mx-2 flex list-none flex-col p-0">
                {recent.map((c) => (
                  <li key={c.id}>
                    <Link className="flex items-center justify-between gap-3 rounded-lg px-2 py-2.5 text-ink no-underline hover:bg-tile" to={`/app/patients/${patient.id}/check-ins/${c.id}`}>
                      <span className="flex min-w-0 items-center gap-2.5 text-[13.5px]">
                        <Icon name="phone-line" className="text-muted" />
                        <span className="min-w-0">
                          <b className="font-medium">Yasmar call</b> <small className="text-[12.5px] text-muted">· {whenLabel(c.requestedAt)}</small>
                        </span>
                      </span>
                      <span className="flex shrink-0 flex-wrap items-center justify-end gap-1.5">
                        <Pill pill={checkInPill(c.status)} />
                        {c.urgent && <Pill pill={urgentPill} />}
                      </span>
                    </Link>
                  </li>
                ))}
              </ul>
            )}
            {checkIns.data && !recent.length && <p className="m-0 text-[13px] text-muted">None yet.</p>}
            {recent.length > 0 && (
              <Link className={linkClass} to={tabPath(patient.id, "check_ins")}>
                All check-ins <Icon name="arrow-right-line" size={14} />
              </Link>
            )}
          </Card>
        </section>
      </div>
    </div>
  );
}