gigafibre-fsm/apps/website/src/components/ProtectedAdminRoute.tsx
louispaulb 6620652900 merge: import site-web-targo into apps/website/ (4 commits preserved)
Integrates www.gigafibre.ca (React/Vite) into the monorepo.
Full git history accessible via `git log -- apps/website/`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 08:09:15 -04:00

63 lines
1.9 KiB
TypeScript

import React, { useState, useEffect, useRef } from "react";
import { Navigate } from "react-router-dom";
import { supabase } from "@/integrations/supabase/client";
import { Loader2 } from "lucide-react";
export function ProtectedAdminRoute({ children }: { children: React.ReactNode }) {
const [loading, setLoading] = useState(true);
const [authorized, setAuthorized] = useState(false);
const initialCheckDone = useRef(false);
useEffect(() => {
const checkAdmin = async (userId: string) => {
const { data: roleRow } = await supabase
.from("user_roles")
.select("role")
.eq("user_id", userId)
.eq("role", "admin")
.maybeSingle();
setAuthorized(!!roleRow);
setLoading(false);
};
// Listen to auth state changes — but ignore null session until initial check is done
const { data: { subscription } } = supabase.auth.onAuthStateChange((_event, session) => {
if (session?.user) {
initialCheckDone.current = true;
checkAdmin(session.user.id);
} else if (initialCheckDone.current) {
// Only redirect if we already confirmed the initial state
setAuthorized(false);
setLoading(false);
}
});
// Initial session check — this is the source of truth
supabase.auth.getSession().then(({ data: { session } }) => {
initialCheckDone.current = true;
if (session?.user) {
checkAdmin(session.user.id);
} else {
setAuthorized(false);
setLoading(false);
}
});
return () => subscription.unsubscribe();
}, []);
if (loading) {
return (
<div className="min-h-screen flex items-center justify-center">
<Loader2 className="w-8 h-8 animate-spin text-muted-foreground" />
</div>
);
}
if (!authorized) {
return <Navigate to="/admin/login" replace />;
}
return <>{children}</>;
}