111 lines
4.9 KiB
JavaScript
111 lines
4.9 KiB
JavaScript
import { Toaster } from '@/components/ui/toaster';
|
|
import { Toaster as HotToaster } from 'react-hot-toast';
|
|
import { QueryClientProvider } from '@tanstack/react-query';
|
|
import { queryClientInstance } from '@/lib/query-client';
|
|
import { Navigate, BrowserRouter as Router, Route, Routes } from 'react-router-dom';
|
|
import { AuthProvider, useAuth } from '@/lib/AuthContext';
|
|
|
|
import PageNotFound from '@/lib/PageNotFound';
|
|
import ErrorBoundary from '@/components/ErrorBoundary';
|
|
import ScrollToTop from '@/components/ScrollToTop';
|
|
import ProtectedRoute from '@/components/ProtectedRoute';
|
|
import EmployerRoute from '@/routes/EmployerRoute';
|
|
import RoleHome from '@/routes/RoleHome';
|
|
import EmployerLayout from '@/layouts/EmployerLayout';
|
|
|
|
import Login from '@/pages/Login';
|
|
import OwliverHome from '@/pages/OwliverHome';
|
|
import Dashboard from '@/pages/hiring/Overview';
|
|
import Positions from '@/pages/hiring/Positions';
|
|
import CreatePosition from '@/pages/hiring/CreatePosition';
|
|
import PositionDetail from '@/pages/hiring/PositionDetail';
|
|
import Candidates from '@/pages/hiring/Candidates';
|
|
import CandidateProfile from '@/pages/hiring/CandidateProfile';
|
|
import HiredHistory from '@/pages/hiring/HiredHistory';
|
|
import TalentPool from '@/pages/hiring/TalentPool';
|
|
import Analytics from '@/pages/hiring/Analytics';
|
|
import Activity from '@/pages/Activity';
|
|
import Profile from '@/pages/Profile';
|
|
import Settings from '@/pages/Settings';
|
|
|
|
const AuthenticatedApp = () => {
|
|
const { isLoadingAuth, isLoadingPublicSettings } = useAuth();
|
|
|
|
if (isLoadingPublicSettings || isLoadingAuth) {
|
|
return (
|
|
<div className="fixed inset-0 flex items-center justify-center">
|
|
<div className="h-8 w-8 animate-spin rounded-full border-4 border-slate-200 border-t-slate-800" />
|
|
<span className="sr-only">Checking your session</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Routes>
|
|
{/* Sign-in sits outside the protected boundary, for the obvious reason. */}
|
|
<Route path="/login" element={<Login />} />
|
|
|
|
<Route element={<ProtectedRoute />}>
|
|
{/* Everyone who reaches here has a session — `ProtectedRoute` saw to
|
|
that — so `/` is a question about who they are, not whether they are
|
|
signed in. A role with no console in this build lands back on the
|
|
sign-in page, where it says so. */}
|
|
<Route path="/" element={<RoleHome />} />
|
|
|
|
<Route element={<EmployerRoute />}>
|
|
<Route element={<EmployerLayout />}>
|
|
{/* The Owliver AI home — the post-login landing. A separate page
|
|
from the Dashboard, which keeps its own address below. */}
|
|
<Route path="/home" element={<OwliverHome />} />
|
|
<Route path="/dashboard" element={<Dashboard />} />
|
|
<Route path="/positions" element={<Positions />} />
|
|
{/* Static before dynamic, so `positions/new` cannot be read as a
|
|
position whose id is "new". */}
|
|
<Route path="/positions/new" element={<CreatePosition />} />
|
|
<Route path="/positions/:id" element={<PositionDetail />} />
|
|
<Route path="/candidates" element={<Candidates />} />
|
|
{/* The full candidate record is a page rather than a drawer: it
|
|
carries around forty fields and fifteen screening dimensions,
|
|
which a 480px column cannot show without hiding most of it. */}
|
|
<Route path="/candidates/:id" element={<CandidateProfile />} />
|
|
<Route path="/hired" element={<HiredHistory />} />
|
|
<Route path="/talent-pool" element={<TalentPool />} />
|
|
<Route path="/analytics" element={<Analytics />} />
|
|
<Route path="/activity" element={<Activity />} />
|
|
<Route path="/profile" element={<Profile />} />
|
|
<Route path="/settings" element={<Settings />} />
|
|
</Route>
|
|
</Route>
|
|
|
|
{/* The addresses this console was lifted from. Bookmarks and links
|
|
written against the two-console build still resolve. */}
|
|
<Route path="/admin" element={<Navigate to="/dashboard" replace />} />
|
|
<Route path="/employer" element={<Navigate to="/dashboard" replace />} />
|
|
<Route path="/overview" element={<Navigate to="/dashboard" replace />} />
|
|
</Route>
|
|
|
|
<Route path="*" element={<PageNotFound />} />
|
|
</Routes>
|
|
);
|
|
};
|
|
|
|
export default function App() {
|
|
return (
|
|
<ErrorBoundary>
|
|
<AuthProvider>
|
|
<QueryClientProvider client={queryClientInstance}>
|
|
<Router>
|
|
<ScrollToTop />
|
|
<AuthenticatedApp />
|
|
</Router>
|
|
<Toaster />
|
|
{/* The design system's `toast` helper wraps react-hot-toast, which
|
|
needs its own renderer mounted. Without this every toast in the
|
|
app fires into nothing. */}
|
|
<HotToaster position="bottom-right" />
|
|
</QueryClientProvider>
|
|
</AuthProvider>
|
|
</ErrorBoundary>
|
|
);
|
|
}
|