@@ -3,6 +3,8 @@ import { useEffect, useState } from "react";
33import { Outlet , useLocation , useNavigate } from "react-router-dom" ;
44import { apiBaseUrl } from "@/api/api" ;
55
6+ type GateStatus = "checking" | "ok" | "error" ;
7+
68export function AdminGate ( ) {
79 const navigate = useNavigate ( ) ;
810 const location = useLocation ( ) ;
@@ -11,10 +13,9 @@ export function AdminGate() {
1113 const devBypass =
1214 import . meta. env . DEV && import . meta. env . VITE_ADMIN_DEV_BYPASS === "true" ;
1315
14- const [ status , setStatus ] = useState < "checking" | "ok" > ( "checking" ) ;
16+ const [ status , setStatus ] = useState < GateStatus > ( "checking" ) ;
1517
1618 useEffect ( ( ) => {
17- // ✅ If dev bypass is enabled, don't gate the UI at all
1819 if ( devBypass ) {
1920 setStatus ( "ok" ) ;
2021 return ;
@@ -32,44 +33,42 @@ export function AdminGate() {
3233 headers : { Accept : "application/json" } ,
3334 } ) ;
3435
35- // 401 = not logged in -> go to admin login
36+ if ( ! alive ) return ;
37+
3638 if ( res . status === 401 ) {
3739 navigate ( loginUrl , { replace : true } ) ;
3840 return ;
3941 }
4042
41- // 403 = logged in but forbidden/allowlist/etc -> go to denied
4243 if ( res . status === 403 ) {
4344 navigate ( "/admin/denied" , { replace : true } ) ;
4445 return ;
4546 }
4647
47- // Any other non-OK -> treat as not authorized (or API misrouted/down)
4848 if ( ! res . ok ) {
49- navigate ( loginUrl , { replace : true } ) ;
49+ // Unexpected status: show error (don’t pretend it’s a login problem)
50+ setStatus ( "error" ) ;
5051 return ;
5152 }
5253
5354 const data = await res . json ( ) ;
5455
55- // accept common shapes, but prefer { user }
5656 const user =
5757 data ?. user ??
5858 data ?. me ??
5959 data ?. data ?. user ??
6060 data ?. data ?. me ??
6161 ( data ?. id ? data : null ) ;
6262
63- // If API returns 200 but user is null, treat as unauthenticated
6463 if ( ! user ) {
6564 navigate ( loginUrl , { replace : true } ) ;
6665 return ;
6766 }
6867
69- if ( alive ) setStatus ( "ok" ) ;
68+ setStatus ( "ok" ) ;
7069 } catch {
71- // Network error / CORS / API down: treat as unauthenticated
72- navigate ( loginUrl , { replace : true } ) ;
70+ if ( ! alive ) return ;
71+ setStatus ( "error" ) ;
7372 }
7473 } ) ( ) ;
7574
@@ -82,5 +81,19 @@ export function AdminGate() {
8281 return < div className = "p-6 text-zinc-300" > Checking clearance…</ div > ;
8382 }
8483
84+ if ( status === "error" ) {
85+ return (
86+ < div className = "p-6 text-zinc-300" >
87+ < div className = "text-lg font-semibold text-zinc-100" >
88+ Can’t reach the Lab API
89+ </ div >
90+ < div className = "mt-2 text-sm text-zinc-400" >
91+ This usually means < code > VITE_API_BASE_URL</ code > is wrong, CORS/session
92+ settings are off, or the API is down.
93+ </ div >
94+ </ div >
95+ ) ;
96+ }
97+
8598 return < Outlet /> ;
86- }
99+ }
0 commit comments