# Frontend Structure React 18 + Material-UI, built statically and served by the backend (see [architecture.md](./architecture.md)) — there's no separate frontend deployment. ## Navigation is a state switch, not a router `react-router-dom` is a dependency and `frontend/src/index.js` wraps the tree in `` — but that's vestigial. Nothing in the codebase uses ``, `useNavigate`, or `useParams` (verified by grep). All real navigation is plain React state in `App.js`: `NAV_VIEWS` (an array of view IDs) + `VIEW_CONFIG` (icon/label/description per ID) drive the nav bar, and `currentView` (persisted to `localStorage`) picks which lazy-loaded component renders via a long `currentView === '...' ? : ...` chain. There are no URLs per view and no deep links — "adding a page" means adding an entry to `VIEW_CONFIG`/`NAV_VIEWS` and a branch in that chain, not adding a ``. ```mermaid flowchart TB Login["LoginForm\n(unauthenticated)"] -- "AuthContext.login()" --> Gate{"isAuthenticated?"} Gate -- no --> Login Gate -- yes --> AppContent["AppContent\ncurrentView state"] AppContent --> Nav["Nav bar\n(navViews = NAV_VIEWS\n+ 'users' if role==admin)"] Nav --> Switch{"currentView"} Switch -->|projects| ProjectFlow Switch -->|planning| PlanningDashboard Switch -->|mobile| MobileOrders Switch -->|materials| MaterialsList Switch -->|smart-packages| SmartPackagesRoutes Switch -->|openai-usage| AIUsageView["inline AI usage view"] Switch -->|noegletal| NoeglatalDashboard Switch -->|dashboard| AdvancedDashboard Switch -->|users, admin only| UsersManagement ``` ## Top-level components (`frontend/src/components/`, lazy-loaded ones especially) | Component | Role | |---|---| | `ProjectFlow.js` | The core quote-building wizard: project data → geometry → smart packages → final review | | `EnhancedGeometry.js` | Roof geometry input with SVG visualizations for all 7 supported roof types | | `InlineSmartPackage.js` | Smart Package step-by-step wizard embedded in the project flow | | `FinalReview.js` | Quote review + Ordrestyring offer creation | | `MaterialsList.js` | Material search/selection with cached API queries | | `PlanningDashboard.js` | Order/calendar planning view | | `MobileOrders.js` | Field/besigtigelse intake against Ordrestyring order history | | `NoeglatalDashboard.js`, `AdvancedDashboard.js` | Metrics/KPI dashboards | | `UsersManagement.js` | **New (2026-09-04).** Admin-only user CRUD page ("Brugere" nav item), only rendered when `AuthContext.user.role === 'admin'` | | `LoginForm.js` | Credential form, calls `AuthContext.login` | ## Smart Packages subsystem (`components/smartPackages/`, 19 files) `SmartPackages.js` is the management shell; supporting pieces: `SmartPackageWizard.js` / `SmartPackageForm.js` (creation flow), `PackageDetailsDialog.js`, `TaskManagement.js`, `StatisticsView.js`, `SmartPackageReviewQueue.js`, `HaandvaerkPriserImportPanel.js` (haandvaerkpriser.dk import), `BackupImport.js`, `ComponentsLibrary.js`, `smartPackageCategories.js` / `smartPackageManagementQuery.js` (data/query helpers). Routed into the main app via `frontend/src/routes/SmartPackagesRoutes.js` (lazy-loaded as the `smart-packages` view). ## Auth (`frontend/src/contexts/AuthContext.js`) - Login posts to `/api/auth/login`; on success stores `accessToken` in `localStorage` and sets it as the axios default `Authorization` header for every subsequent request. - `user` is now `{ username, role }` — **`role` was added 2026-09-04** to gate the `users` nav view/component; it comes straight from the login response (`response.data.user.role`), matching the backend's `auth_accounts.role` column (see [data.md](./data.md), [backend.md](./backend.md)). - A refresh-token flow (`/api/auth/refresh`, HttpOnly cookie) is scaffolded in the axios response interceptor but the backend endpoint doesn't exist yet — this is explicitly flagged in the file's own `TODO`/`WARNING` comments as incomplete, not a bug to silently "fix" without checking backend readiness first. - `logout()` clears `localStorage` and the axios header; there's no server-side session invalidation (JWTs just expire, 24h access / 7d refresh).