proposal-system/web/src/App.tsx
Adam Moussa 42eedc1c49
feat(web): adopt SHOC design system and shell layout (ADR 0003)
Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:

- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
  DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
  shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
  adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
  tuple, component overrides; MUI v9 slot renames expressed as class
  selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
  scrolling main); sidebar 244px/76px collapse with brand header row,
  grouped nav, SHOC active treatment (white card + 3px accent bar);
  topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
  sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
  remaining hardcoded hexes replaced with tokens; lucide-react for
  shell/nav icons per SHOC convention

Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).
2026-07-13 16:47:17 -04:00

89 lines
4.6 KiB
TypeScript

import { Routes, Route, Navigate } from 'react-router-dom';
import { Box, Button, Card, CardContent, Typography } from '@mui/material';
import PeopleIcon from '@mui/icons-material/People';
import ProtectedRoute, { RoleGuard } from './components/ProtectedRoute';
import Topbar from './components/Topbar';
import Sidebar from './components/Sidebar';
import LoginPage from './pages/auth/LoginPage';
import AuthCallback from './pages/auth/AuthCallback';
import Dashboard from './pages/dashboard/Dashboard';
import ProposalFormPage from './pages/proposals/form/ProposalFormPage';
import ProposalDetailPage from './pages/proposals/detail/ProposalDetailPage';
import ProposalListPage from './pages/proposals/list/ProposalListPage';
import AdminDashboard from './pages/admin/dashboard/AdminDashboard';
import AdminWorkspace from './pages/admin/workspace/AdminWorkspace';
import CustomerManagementPage from './pages/admin/customers/CustomerManagementPage';
import PricingLibraryPage from './pages/admin/pricing-library/PricingLibraryPage';
export default function App() {
return (
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route path="/callback" element={<AuthCallback />} />
<Route
path="/*"
element={
<ProtectedRoute>
{/* SHOC shell composition (ADR 0003): sidebar column + [topbar / scrolling main] */}
<Box sx={{ display: 'flex', height: '100vh', width: '100%', overflow: 'hidden', backgroundColor: 'var(--background)' }}>
<Sidebar />
<Box sx={{ display: 'flex', flexDirection: 'column', flex: 1, minWidth: 0, height: '100vh', overflow: 'hidden' }}>
<Topbar />
<Box
component="main"
sx={{
flex: 1,
overflow: 'auto',
p: 1.25,
backgroundColor: 'var(--color-bg-page)',
}}
>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/proposals" element={<ProposalListPage />} />
<Route path="/proposals/new" element={<ProposalFormPage />} />
<Route path="/proposals/:id" element={<ProposalDetailPage />} />
{/* Admin Routes */}
<Route path="/admin" element={<RoleGuard roles={['Admin', 'SysAdmin']}><AdminDashboard defaultStatus="InReview" /></RoleGuard>} />
<Route path="/admin/proposals" element={<RoleGuard roles={['Admin', 'SysAdmin']}><AdminDashboard /></RoleGuard>} />
<Route path="/admin/proposals/:id" element={<RoleGuard roles={['Admin', 'SysAdmin']}><AdminWorkspace /></RoleGuard>} />
<Route path="/admin/customers" element={<RoleGuard roles={['Admin', 'SysAdmin']}><CustomerManagementPage /></RoleGuard>} />
<Route path="/admin/pricing-library" element={<RoleGuard roles={['Admin', 'SysAdmin']}><PricingLibraryPage /></RoleGuard>} />
<Route path="/admin/users" element={
<RoleGuard roles={['SysAdmin']}>
<Box sx={{ display: 'flex', justifyContent: 'center', pt: 6 }}>
<Card sx={{ maxWidth: 520, p: 4, textAlign: 'center' }}>
<CardContent>
<PeopleIcon sx={{ fontSize: 48, color: 'var(--color-text-muted)', mb: 2 }} />
<Typography variant="h5" sx={{ mb: 1 }}>User Management</Typography>
<Typography variant="body1" color="text.secondary" sx={{ mb: 3 }}>
Users and roles are currently managed in AWS Cognito. Contact the system administrator to update access.
</Typography>
<Button
variant="outlined"
size="large"
href="https://us-east-1.console.aws.amazon.com/cognito/v2/idp/user-pools?region=us-east-1"
target="_blank"
rel="noopener noreferrer"
>
Manage in Cognito
</Button>
</CardContent>
</Card>
</Box>
</RoleGuard>
} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</Box>
</Box>
</Box>
</ProtectedRoute>
}
/>
</Routes>
);
}