From 5860d822cfe3e228ec9ebcbb9affe45d663b5f79 Mon Sep 17 00:00:00 2001 From: Barkley Trimsworth Date: Tue, 31 Mar 2026 00:53:59 +0000 Subject: [PATCH] =?UTF-8?q?fix(portal):=20redirect=20unauthenticated=20use?= =?UTF-8?q?rs=20to=20login=20=E2=80=94=20never=20show=20portal=20chrome=20?= =?UTF-8?q?(GRO-309)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CustomerPortal.tsx: add initComplete state to track async session initialization. After init completes with no valid session, redirect: staff dev users → /admin, all others → /login - Dashboard.tsx: change !sessionId fallback from dead-end UI to (defense-in-depth) - All 85 web unit tests pass Co-Authored-By: Paperclip --- apps/web/src/portal/CustomerPortal.tsx | 22 +++++++++++++++++++--- apps/web/src/portal/sections/Dashboard.tsx | 9 ++------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/apps/web/src/portal/CustomerPortal.tsx b/apps/web/src/portal/CustomerPortal.tsx index 80d4e5b..aa877f2 100644 --- a/apps/web/src/portal/CustomerPortal.tsx +++ b/apps/web/src/portal/CustomerPortal.tsx @@ -1,5 +1,5 @@ import { useState, useCallback, useEffect, useRef } from "react"; -import { useSearchParams } from "react-router-dom"; +import { useSearchParams, Navigate } from "react-router-dom"; import { Home, Calendar, PawPrint, FileText, CreditCard, MessageSquare, Settings, LogOut, Shield, @@ -38,6 +38,7 @@ export function CustomerPortal() { const [session, setSession] = useState(null); const [sessionExtended, setSessionExtended] = useState(false); const [clientName, setClientName] = useState(""); + const [initComplete, setInitComplete] = useState(false); const { branding } = useBranding(); const [searchParams, setSearchParams] = useSearchParams(); @@ -68,7 +69,8 @@ export function CustomerPortal() { }) .catch(() => { setSearchParams({}, { replace: true }); - }); + }) + .finally(() => setInitComplete(true)); return; } @@ -90,7 +92,11 @@ export function CustomerPortal() { setClientName(devUser.name); } }) - .catch(() => {}); + .catch(() => {}) + .finally(() => setInitComplete(true)); + } else { + // No valid session: staff dev users and unauthenticated users fall through here + setInitComplete(true); } }, []); @@ -168,6 +174,16 @@ export function CustomerPortal() { const avatarInitials = (clientName.split(" ")[0] || "G").charAt(0).toUpperCase(); + // After init completes, redirect unauthenticated users to /login and staff to /admin + // The portal chrome must NEVER be visible to users without a valid client session + if (initComplete && !session) { + const devUser = getDevUser(); + if (devUser && devUser.type === "staff") { + return ; + } + return ; + } + return (
-
-

Please sign in to view your dashboard.

-
-
- ); + return ; } const upcomingAppointments = getUpcomingAppointments();