/* Side-effect import: initialises i18next and subscribes it to the language store, before any component calls t(). Imported here rather than in main so that every entry point into the app gets it. */ import '@/lib/i18n'; 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, useParams } from 'react-router-dom'; import PageNotFound from './lib/PageNotFound'; import { AuthProvider, useAuth } from '@/lib/AuthContext'; import ScrollToTop from './components/ScrollToTop'; import ProtectedRoute from '@/components/ProtectedRoute'; import Layout from '@/layouts/Layout'; import Overview from '@/pages/Overview'; import Positions from '@/pages/Positions'; import PositionDetail from '@/pages/PositionDetail'; import Candidates from '@/pages/Candidates'; import HiredHistory from '@/pages/HiredHistory'; import TalentPool from '@/pages/TalentPool'; import Apply from '@/pages/Apply'; import UserTracking from '@/pages/UserTracking'; import Analytics from '@/pages/Analytics'; import CreatePosition from '@/pages/CreatePosition'; import Profile from '@/pages/Profile'; import University from '@/pages/University'; import CourseDetail from '@/pages/CourseDetail'; import WorkerProfile from '@/pages/WorkerProfile'; import KrowIdentity from '@/pages/KrowIdentity'; import Owliver from '@/pages/Owliver'; import EmployeeDashboard from '@/pages/EmployeeDashboard'; import OpportunityDetail from '@/pages/OpportunityDetail'; import DesignSystem from '@/pages/DesignSystem'; /* Admin product — its own layout and route tree, so the Admin redesign can diverge without touching the Employer or Talent experiences. */ import AdminLayout from '@/layouts/AdminLayout'; import ControlCenter from '@/pages/admin/ControlCenter'; import AdminPositions from '@/pages/admin/Positions'; import AdminCandidates from '@/pages/admin/Candidates'; import AdminCandidateProfile from '@/pages/admin/CandidateProfile'; import AdminCandidatesAnalysis from '@/pages/admin/CandidatesAnalysis'; import AdminHiredHistory from '@/pages/admin/HiredHistory'; import AdminTalentPool from '@/pages/admin/TalentPool'; import AdminTalentProfile from '@/pages/admin/TalentProfile'; import AdminAnalytics from '@/pages/admin/Analytics'; import AdminActivity from '@/pages/admin/Activity'; import AdminProfile from '@/pages/admin/Profile'; import AdminSettings from '@/pages/admin/Settings'; import AdminWorkspace from '@/pages/admin/Workspace'; import AdminWorkspaceSkills from '@/pages/admin/WorkspaceSkills'; import AdminWorkspaceAgents from '@/pages/admin/WorkspaceAgents'; import AdminAgentDetail from '@/pages/admin/AgentDetail'; import AdminSkillEditor from '@/pages/admin/SkillEditor'; import AdminOwliverSkillEditor from '@/pages/admin/OwliverSkillEditor'; import AdminSkillDevelopment from '@/pages/admin/SkillDevelopment'; import AdminLogin from '@/pages/admin/Login'; import AdminRoute from '@/pages/admin/AdminRoute'; /** `/university/:id` → the same challenge inside the Admin shell, id preserved. */ const LegacyCourseRedirect = () => { const { id } = useParams(); return ; }; /** `/positions/:id` → the same position inside the Admin shell, id preserved. */ const LegacyPositionRedirect = () => { const { id } = useParams(); return ; }; const AuthenticatedApp = () => { const { isLoadingAuth, isLoadingPublicSettings } = useAuth(); if (isLoadingPublicSettings || isLoadingAuth) { return (
); } return ( {/* Admin sign-in — outside the protected boundary. */} } /> }> {/* The application opens on the Admin console, which is entered through its own sign-in. Employer keeps every one of its routes, including Overview at an explicit path — nothing of that product is removed, only the address the app happens to start at. */} } /> }> }> } /> } /> } /> } /> } /> {/* The full Candidate Intelligence profile. A page rather than a drawer: the record carries around forty fields and fifteen screening dimensions, which a 480px column cannot show without hiding most of it. */} } /> {/* Candidate Analysis. A sibling segment, not `candidates/:id`: the analysis reads the whole pool, so it is not addressed by a candidate id and must not be matched as one. The route is the one the `candidates-analysis` surface declares, so the skill table, the assistant placement table and this agree. */} } /> } /> } /> {/* The person, keyed by worker profile — distinct from `candidates/:id`, which is one person FOR ONE POSITION. Two routes because they answer different questions; one screen would push the product back towards a candidate record per vacancy, which is the thing `worker_profiles` exists to stop. */} } /> } /> } /> } /> } /> } /> {/* Two centres, deliberately separate. Settings configures the account and the system; Workspace & Skills configures the workforce — Owliver's capabilities, training and progression — each with its own pages underneath rather than one page holding both subjects. */} } /> } /> } /> {/* Static before dynamic, so `agents/new` cannot be read as an agent whose id is "new". */} } /> } /> } /> {/* Two editors, because a UI skill and an Owliver skill configure different things. Static segments rank above the dynamic `:id`, so `skills/owliver/...` cannot be read as a skill called "owliver" — and the two original addresses are untouched. */} } /> } /> } /> } /> } /> {/* Redirect top-level legacy aliases to the unified global shell */} {/* Employee (talent) opportunity flow — full-page routes, no drawer. Standalone (outside AdminLayout/AdminRoute, which are the employer shell and gate); authenticated via ProtectedRoute. */}
} />
} />
} /> } /> } /> {/* `/positions` only matches the exact path, so the sub-routes need their own aliases or an inbound link lands on the 404 page. */} } /> } /> } /> } /> } /> } /> {/* Same treatment as every other legacy alias: the challenge opens inside the application shell rather than on a bare page, so Forge → challenge keeps its navigation, header and page frame. Existing links to /university/:id are unchanged and still resolve here. */} } /> } /> } /> } /> } />
); }; function App() { return ( {/* The design system's `toast` helper wraps react-hot-toast, which needs its own renderer mounted. Without this every toast in the app fired into nothing — confirmations, errors and the "not in the demo" notices all silently did nothing. */} ) } export default App