Patients page, clinical Settings re-theme, Polar-style user footer

- Patients: new /patients directory table (name, MRN, age·sex, status,
  last seen, allergies) with search + Add patient; clicking a row opens
  the record in the chat via /?patient=<#>. chat-panel reads that search
  param (Suspense-wrapped) and runs the lookup once on arrival. Sidebar
  "Patients" now links to /patients; lib/patients gains listPatients().
- Settings: re-themed to clinical tabs (Profile · Records · Signing ·
  Care team · Developers) — clinician profile, patient notifications,
  patient-owned-storage/signed-records features, and a Signing key panel.
  Same layout/components, only content changed.
- Sidebar footer: Polar-style NavUser (avatar + name + chevron) opening a
  menu upward — Settings · Docs & GitHub · Theme · Log out. Collapsed
  ("locked"): avatar only, name on hover (tooltip), menu opens to the
  right. Placeholder identity (no auth yet).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Khalid Abdi
2026-06-01 21:55:33 +03:00
parent a2654a87e1
commit dec150c77d
10 changed files with 379 additions and 124 deletions
+14 -1
View File
@@ -2,7 +2,8 @@
import { nanoid } from "nanoid";
import type { ChatStatus } from "ai";
import { useCallback, useState } from "react";
import { useSearchParams } from "next/navigation";
import { useCallback, useEffect, useRef, useState } from "react";
import {
Conversation,
@@ -106,6 +107,18 @@ export function ChatPanel() {
const handleStop = useCallback(() => setStatus("ready"), []);
// Opening a patient from the Patients page lands here as `/?patient=<file#>`;
// run the lookup once on arrival.
const searchParams = useSearchParams();
const requestedPatient = searchParams.get("patient");
const handledPatientRef = useRef<string | null>(null);
useEffect(() => {
if (requestedPatient && handledPatientRef.current !== requestedPatient) {
handledPatientRef.current = requestedPatient;
send(`/patient ${requestedPatient}`);
}
}, [requestedPatient, send]);
const promptInput = (
<ChatInput onStop={handleStop} onSubmit={send} status={status} />
);