App.tsx 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. // App root: auth gate + router + query client + dark mode (default).
  2. import { useEffect, useState } from 'react'
  3. import { Route, Switch, Redirect, useLocation } from 'wouter'
  4. import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
  5. import { Shell } from './components/Shell'
  6. import { LoginPage } from './pages/Login'
  7. import { OverviewPage } from './pages/Overview'
  8. import { RoutersPage } from './pages/Routers'
  9. import { EventsPage } from './pages/Events'
  10. import { CommandsPage } from './pages/Commands'
  11. import { AlertsPage } from './pages/Alerts'
  12. const queryClient = new QueryClient({
  13. defaultOptions: {
  14. queries: {
  15. staleTime: 5_000,
  16. retry: 1,
  17. refetchOnWindowFocus: false,
  18. },
  19. },
  20. })
  21. function useAuth() {
  22. const [authed, setAuthed] = useState<boolean | null>(null)
  23. useEffect(() => {
  24. setAuthed(!!localStorage.getItem('c2s_token'))
  25. const handler = () => setAuthed(false)
  26. window.addEventListener('c2s:unauthorized', handler)
  27. return () => window.removeEventListener('c2s:unauthorized', handler)
  28. }, [])
  29. return { authed, setAuthed }
  30. }
  31. function Protected({ children }: { children: React.ReactNode }) {
  32. const { authed } = useAuth()
  33. const [, navigate] = useLocation()
  34. if (authed === null) return null
  35. if (!authed) {
  36. navigate('/login')
  37. return null
  38. }
  39. return <Shell>{children}</Shell>
  40. }
  41. export default function App() {
  42. return (
  43. <QueryClientProvider client={queryClient}>
  44. <div className="dark">
  45. <Switch>
  46. <Route path="/login" component={LoginPage} />
  47. <Route path="/"><Protected><OverviewPage /></Protected></Route>
  48. <Route path="/routers"><Protected><RoutersPage /></Protected></Route>
  49. <Route path="/events"><Protected><EventsPage /></Protected></Route>
  50. <Route path="/commands"><Protected><CommandsPage /></Protected></Route>
  51. <Route path="/alerts"><Protected><AlertsPage /></Protected></Route>
  52. <Route><Redirect to="/" /></Route>
  53. </Switch>
  54. </div>
  55. </QueryClientProvider>
  56. )
  57. }