Repository Public
1// Routes. Public pages (share links, deposit portals, sign-in) never load the signed-in application.2import { lazy, Suspense, useEffect } from 'react';3import { Redirect, Route, Switch, useLocation } from 'wouter';4import { useAuth, useRefreshAuth } from './session.ts';5import { ErrorState, Loading } from './ui.tsx';67const Shell = lazy(() => import('./shell/Shell.tsx').then((m) => ({ default: m.Shell })));8const Explorer = lazy(() => import('./explorer/Explorer.tsx').then((m) => ({ default: m.Explorer })));9const Shares = lazy(() => import('./screens/Shares.tsx').then((m) => ({ default: m.Shares })));10const Requests = lazy(() => import('./screens/Requests.tsx').then((m) => ({ default: m.Requests })));11const RequestDetail = lazy(() => import('./screens/RequestDetail.tsx').then((m) => ({ default: m.RequestDetail })));12const Settings = lazy(() => import('./screens/Settings.tsx').then((m) => ({ default: m.Settings })));13const Admin = lazy(() => import('./screens/Admin.tsx').then((m) => ({ default: m.Admin })));14const Login = lazy(() => import('./screens/Login.tsx').then((m) => ({ default: m.Login })));15const Invite = lazy(() => import('./screens/Invite.tsx').then((m) => ({ default: m.Invite })));16const Recovery = lazy(() => import('./screens/Recovery.tsx').then((m) => ({ default: m.Recovery })));17const SharePage = lazy(() => import('./public-pages/SharePage.tsx').then((m) => ({ default: m.SharePage })));18const RequestPage = lazy(() => import('./public-pages/RequestPage.tsx').then((m) => ({ default: m.RequestPage })));1920function Private() {21 const { state, loading, error, refetch } = useAuth();22 const refresh = useRefreshAuth();23 const [loc, navigate] = useLocation();24 useEffect(() => { const h = () => { void refresh(); }; window.addEventListener('spd:unauthenticated', h); return () => window.removeEventListener('spd:unauthenticated', h); }, [refresh]);25 if (loading) return <Loading />;26 if (error || !state) return <ErrorState error={error} onRetry={() => void refetch()} />;27 if (!state.authenticated) return <Redirect to={loc === '/' ? '/login' : `/login?next=${encodeURIComponent(loc)}`} />;28 if (state.recovery) return <Redirect to="/recovery" />; // a recovery session can only enrol a passkey29 return (30 <Shell>31 <Switch>32 <Route path="/"><Explorer view="folder" folderId="root" /></Route>33 <Route path="/folder/:id">{(p) => <Explorer view="folder" folderId={p.id} />}</Route>34 <Route path="/recent"><Explorer view="recent" /></Route>35 <Route path="/starred"><Explorer view="starred" /></Route>36 <Route path="/trash"><Explorer view="trash" /></Route>37 <Route path="/search"><Explorer view="search" /></Route>38 <Route path="/duplicates"><Explorer view="duplicates" /></Route>39 <Route path="/shares"><Shares /></Route>40 <Route path="/requests"><Requests /></Route>41 <Route path="/requests/:id">{(p) => <RequestDetail id={p.id} />}</Route>42 <Route path="/settings/:tab?">{(p) => <Settings tab={p.tab} />}</Route>43 <Route path="/admin">{state.user?.role === 'admin' ? <Admin /> : <Redirect to="/" />}</Route>44 <Route><ErrorState error={{ code: 'not_found' }} onRetry={() => navigate('/')} /></Route>45 </Switch>46 </Shell>47 );48}4950export function App() {51 return (52 <Suspense fallback={<Loading />}>53 <Switch>54 <Route path="/s/:token">{(p) => <SharePage token={p.token} />}</Route>55 <Route path="/request/:token">{(p) => <RequestPage token={p.token} />}</Route>56 <Route path="/invite/:token">{(p) => <Invite token={p.token} />}</Route>57 <Route path="/login"><Login /></Route>58 <Route path="/recovery"><Recovery /></Route>59 <Route><Private /></Route>60 </Switch>61 </Suspense>62 );63}64