portal: public Patient Portal kiosk (self-service booking + results)

New chrome-less (portal) route group with /portal/[clinic], a card-style choice
of "Book an appointment" vs "View my results", and step flows wired to a new
public backend router (src/routes/portal.ts):
- GET  /api/portal/:clinic            -> clinic name
- POST /api/portal/:clinic/appointments  (verifies name+file#, books a confirmed
  appointment that appears on the doctor's Appointments page)
- GET  /api/portal/:clinic/results    (minimal, safe status — no clinical values)

Excluded /portal from the auth proxy redirect so the kiosk loads without a
session. PHI exposure is intentionally minimal (see docs).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Khalid Abdi
2026-06-20 18:49:39 +03:00
parent e656eae362
commit 516de6ad60
8 changed files with 676 additions and 1 deletions
+9
View File
@@ -0,0 +1,9 @@
// The Patient Portal kiosk runs with no app chrome — no sidebar, no auth guard.
// It's a standalone full-screen surface for a clinic iPad / self-service device.
export default function PortalLayout({
children,
}: {
children: React.ReactNode;
}) {
return <main className="min-h-dvh w-full overflow-y-auto bg-background">{children}</main>;
}
@@ -0,0 +1,11 @@
"use client";
import { useParams } from "next/navigation";
import { PortalKiosk } from "@/components/portal/portal-kiosk";
export default function PatientPortalPage() {
const params = useParams<{ clinic: string }>();
const clinic = Array.isArray(params.clinic) ? params.clinic[0] : params.clinic;
return <PortalKiosk clinic={clinic ?? ""} />;
}