This commit is contained in:
2026-04-18 23:11:35 +02:00
commit f7cfd2a86e
196 changed files with 35538 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
import { Navigate, Outlet, useLocation } from 'react-router-dom';
import { useAuth } from '../context/AuthContext';
import { SpinnerIcon } from './icons';
function FullScreenSpinner({ label }: { label?: string }) {
return (
<main className="flex min-h-screen items-center justify-center bg-ink-950 p-6">
<div className="flex items-center gap-3 text-neutral-400">
<SpinnerIcon className="h-5 w-5 text-brand-400" />
{label && <span className="text-sm font-medium">{label}</span>}
</div>
</main>
);
}
// Forces a session. Sends to /auth otherwise.
export function RequireAuth() {
const { session, ready } = useAuth();
const loc = useLocation();
if (!ready) return <FullScreenSpinner />;
if (!session) return <Navigate to="/auth" replace state={{ from: loc.pathname }} />;
return <Outlet />;
}
// Forces a registered device on this install. Sends to /device otherwise.
export function RequireDevice() {
const { device, deviceLookupDone } = useAuth();
if (!deviceLookupDone) return <FullScreenSpinner />;
if (!device) return <Navigate to="/device" replace />;
return <Outlet />;
}
// Admin-only route gate. Non-admins bounce to /chats — RLS still enforces
// server-side, this is purely a UX shortcut.
export function RequireAdmin() {
const { profile } = useAuth();
if (profile && !profile.isAdmin) return <Navigate to="/chats" replace />;
return <Outlet />;
}