portal/src/App.tsx
jtricerolph fa32ea84ee Add self-registration, role management, and department mapping UI
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-02 00:24:05 +00:00

63 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
import { AuthGate } from './components/AuthGate'
import { Login } from './pages/Login'
import { Register } from './pages/Register'
import { Dashboard } from './pages/Dashboard'
import { AppFrame } from './pages/AppFrame'
import { AdminUsers } from './pages/AdminUsers'
import { AdminRoles } from './pages/AdminRoles'
import { AdminDepartments } from './pages/AdminDepartments'
import { AdminMonitor } from './pages/AdminMonitor'
import { AdminSettings } from './pages/AdminSettings'
// The portal is only ever the top-level frame. If it finds itself loaded inside
// an iframe, it means an app's path fell back to the portal (that app isn't
// deployed or routed in NPM yet) — so render a placeholder instead of recursing
// the whole shell endlessly inside itself.
function EmbeddedFallback() {
return (
<div style={{
height: '100dvh', display: 'flex', alignItems: 'center', justifyContent: 'center',
textAlign: 'center', padding: '2rem', background: 'var(--navy-dark)', color: 'var(--text-muted)',
}}>
<div>
<div style={{ fontSize: '2.5rem', marginBottom: '0.75rem' }}>🚧</div>
<p style={{ fontSize: '1rem', color: 'var(--text)', marginBottom: '0.35rem' }}>
This app isnt available yet
</p>
<p style={{ fontSize: '0.85rem' }}>
It hasnt been deployed or routed on this site.
</p>
</div>
</div>
)
}
export default function App() {
if (window.self !== window.top) return <EmbeddedFallback />
return (
<BrowserRouter>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route path="/*" element={
<AuthGate>
{user => (
<Routes>
<Route path="/" element={<Dashboard user={user} />} />
<Route path="/app/:slug" element={<AppFrame user={user} />} />
<Route path="/admin/users" element={user.is_admin ? <AdminUsers user={user} /> : <Navigate to="/" />} />
<Route path="/admin/roles" element={user.is_admin ? <AdminRoles user={user} /> : <Navigate to="/" />} />
<Route path="/admin/departments" element={user.is_admin ? <AdminDepartments user={user} /> : <Navigate to="/" />} />
<Route path="/admin/monitor" element={user.is_admin ? <AdminMonitor user={user} /> : <Navigate to="/" />} />
<Route path="/admin/settings" element={user.is_admin ? <AdminSettings user={user} /> : <Navigate to="/" />} />
<Route path="*" element={<Navigate to="/" />} />
</Routes>
)}
</AuthGate>
} />
</Routes>
</BrowserRouter>
)
}