1- import { BrowserRouter , Routes , Route } from 'react-router-dom' ;
1+ import { BrowserRouter , Routes , Route , Navigate } from 'react-router-dom' ;
2+ import { AuthProvider , useAuth } from './context/AuthContext' ;
23import { Layout } from './components/Layout' ;
4+ import { ProtectedRoute } from './components/ProtectedRoute' ;
35import { ToastContainer } from './components/Toast' ;
46import { TeamsListPage } from './pages/TeamsListPage' ;
57import { TeamBuilderPage } from './pages/TeamBuilderPage' ;
@@ -14,28 +16,99 @@ import { WebhookDetailPage } from './pages/WebhookDetailPage';
1416import { PostActionsListPage } from './pages/PostActionsListPage' ;
1517import { PostActionBuilderPage } from './pages/PostActionBuilderPage' ;
1618import { PostActionDetailPage } from './pages/PostActionDetailPage' ;
19+ import { LoginPage } from './pages/LoginPage' ;
20+ import { RegisterPage } from './pages/RegisterPage' ;
21+ import { InvitePage } from './pages/InvitePage' ;
22+ import { UserProfilePage } from './pages/UserProfilePage' ;
23+ import { OrgSettingsPage } from './pages/OrgSettingsPage' ;
24+
25+ function GuardedRoute ( { children } : { children : React . ReactNode } ) {
26+ const { mustChangePassword } = useAuth ( ) ;
27+ if ( mustChangePassword ) return < Navigate to = "/settings/profile" replace /> ;
28+ return < > { children } </ > ;
29+ }
30+
31+ function AppRoutes ( ) {
32+ const { authConfig, isAuthenticated, isLoading, refreshUser } = useAuth ( ) ;
33+
34+ if ( isLoading ) {
35+ return (
36+ < div className = "flex min-h-screen items-center justify-center bg-slate-950" >
37+ < div className = "flex flex-col items-center gap-3" >
38+ < div className = "h-8 w-8 animate-spin rounded-full border-2 border-slate-600 border-t-blue-500" />
39+ < p className = "text-sm text-slate-400" > Loading...</ p >
40+ </ div >
41+ </ div >
42+ ) ;
43+ }
44+
45+ const showAuthPages = authConfig ?. provider !== 'noop' ;
46+
47+ return (
48+ < Routes >
49+ { /* Public auth routes — only when auth is active */ }
50+ { showAuthPages && (
51+ < >
52+ < Route
53+ path = "/login"
54+ element = {
55+ isAuthenticated
56+ ? < Navigate to = "/" replace />
57+ : < LoginPage authConfig = { authConfig ! } onLoginSuccess = { refreshUser } />
58+ }
59+ />
60+ < Route
61+ path = "/register"
62+ element = {
63+ isAuthenticated
64+ ? < Navigate to = "/" replace />
65+ : authConfig ! . registration_enabled
66+ ? < RegisterPage onRegisterSuccess = { refreshUser } />
67+ : < Navigate to = "/login" replace />
68+ }
69+ />
70+ < Route path = "/invite/:token" element = { < InvitePage /> } />
71+ </ >
72+ ) }
73+
74+ { /* Protected routes */ }
75+ < Route
76+ element = {
77+ < ProtectedRoute >
78+ < Layout />
79+ </ ProtectedRoute >
80+ }
81+ >
82+ < Route path = "/" element = { < GuardedRoute > < TeamsListPage /> </ GuardedRoute > } />
83+ < Route path = "/teams/new" element = { < GuardedRoute > < TeamBuilderPage /> </ GuardedRoute > } />
84+ < Route path = "/teams/:id" element = { < GuardedRoute > < TeamMonitorPage /> </ GuardedRoute > } />
85+ < Route path = "/schedules" element = { < GuardedRoute > < SchedulesListPage /> </ GuardedRoute > } />
86+ < Route path = "/schedules/new" element = { < GuardedRoute > < ScheduleBuilderPage /> </ GuardedRoute > } />
87+ < Route path = "/schedules/:id" element = { < GuardedRoute > < ScheduleDetailPage /> </ GuardedRoute > } />
88+ < Route path = "/webhooks" element = { < GuardedRoute > < WebhooksListPage /> </ GuardedRoute > } />
89+ < Route path = "/webhooks/new" element = { < GuardedRoute > < WebhookBuilderPage /> </ GuardedRoute > } />
90+ < Route path = "/webhooks/:id" element = { < GuardedRoute > < WebhookDetailPage /> </ GuardedRoute > } />
91+ < Route path = "/post-actions" element = { < GuardedRoute > < PostActionsListPage /> </ GuardedRoute > } />
92+ < Route path = "/post-actions/new" element = { < GuardedRoute > < PostActionBuilderPage /> </ GuardedRoute > } />
93+ < Route path = "/post-actions/:id" element = { < GuardedRoute > < PostActionDetailPage /> </ GuardedRoute > } />
94+ < Route path = "/settings" element = { < GuardedRoute > < SettingsPage /> </ GuardedRoute > } />
95+ < Route path = "/settings/profile" element = { < UserProfilePage /> } />
96+ < Route path = "/settings/organization" element = { < GuardedRoute > < OrgSettingsPage /> </ GuardedRoute > } />
97+ </ Route >
98+
99+ { /* Catch-all */ }
100+ < Route path = "*" element = { < Navigate to = "/" replace /> } />
101+ </ Routes >
102+ ) ;
103+ }
17104
18105export default function App ( ) {
19106 return (
20107 < BrowserRouter >
21- < Routes >
22- < Route element = { < Layout /> } >
23- < Route path = "/" element = { < TeamsListPage /> } />
24- < Route path = "/teams/new" element = { < TeamBuilderPage /> } />
25- < Route path = "/teams/:id" element = { < TeamMonitorPage /> } />
26- < Route path = "/schedules" element = { < SchedulesListPage /> } />
27- < Route path = "/schedules/new" element = { < ScheduleBuilderPage /> } />
28- < Route path = "/schedules/:id" element = { < ScheduleDetailPage /> } />
29- < Route path = "/webhooks" element = { < WebhooksListPage /> } />
30- < Route path = "/webhooks/new" element = { < WebhookBuilderPage /> } />
31- < Route path = "/webhooks/:id" element = { < WebhookDetailPage /> } />
32- < Route path = "/post-actions" element = { < PostActionsListPage /> } />
33- < Route path = "/post-actions/new" element = { < PostActionBuilderPage /> } />
34- < Route path = "/post-actions/:id" element = { < PostActionDetailPage /> } />
35- < Route path = "/settings" element = { < SettingsPage /> } />
36- </ Route >
37- </ Routes >
38- < ToastContainer />
108+ < AuthProvider >
109+ < AppRoutes />
110+ < ToastContainer />
111+ </ AuthProvider >
39112 </ BrowserRouter >
40113 ) ;
41114}
0 commit comments