---
estimated_steps: 37
estimated_files: 6
skills_used: []
---

# T04: Build dashboard shell, profile settings, ProtectedRoute, and nav auth state

Create the creator dashboard shell page with sidebar navigation, profile settings page, ProtectedRoute wrapper component, and update the main nav to show authenticated user state.

## Steps

1. Create `frontend/src/components/ProtectedRoute.tsx`: Wrapper component that checks `useAuth().isAuthenticated`. If not authenticated, redirects to `/login` with a `returnTo` search param preserving the intended destination. If authenticated, renders children.
2. Create `frontend/src/pages/CreatorDashboard.tsx` (CSS module: `CreatorDashboard.module.css`):
   - Two-column layout: left sidebar (240px) + main content area
   - Sidebar nav items: Dashboard (active), Content (placeholder, disabled), Settings (links to /creator/settings). Use NavLink for active state.
   - Main content: Welcome message with user's display_name from `useAuth().user`, placeholder cards for future analytics ("Content stats coming in M020")
   - Uses `useDocumentTitle('Creator Dashboard')`
   - Mobile: sidebar collapses to top horizontal nav or hamburger
3. Create `frontend/src/pages/CreatorSettings.tsx` (CSS module: `CreatorSettings.module.css`):
   - Same dashboard layout (sidebar + content) for navigation consistency
   - Profile section: display_name input (pre-filled), email display (read-only)
   - Password section: current password + new password + confirm new password
   - Submit calls `authUpdateProfile()` via AuthContext, shows success/error feedback
   - Uses `useDocumentTitle('Settings')`
4. In `frontend/src/App.tsx`, add protected routes:
   - `<Route path="/creator/dashboard" element={<ProtectedRoute><CreatorDashboard /></ProtectedRoute>} />`
   - `<Route path="/creator/settings" element={<ProtectedRoute><CreatorSettings /></ProtectedRoute>} />`
5. Update the header/nav in `frontend/src/App.tsx`:
   - When `useAuth().isAuthenticated`: show user display_name, link to /creator/dashboard, and Logout button
   - When not authenticated: show Login link (subtle, in nav area)
   - The existing AdminDropdown remains unchanged — it's a separate concern
6. Ensure all new CSS uses CSS modules. Follow the existing dark theme (use CSS custom properties from App.css where applicable). Dashboard sidebar should use `var(--color-surface-*) / var(--color-text-*)` tokens.

## Must-Haves

- [ ] ProtectedRoute redirects unauthenticated users to /login with returnTo param
- [ ] Dashboard shell with sidebar nav (Dashboard, Content placeholder, Settings)
- [ ] Profile settings page with display_name edit and password change
- [ ] Protected routes wired in App.tsx
- [ ] Nav shows auth state (logged in: name + dashboard + logout; logged out: login link)
- [ ] All CSS in CSS modules, using existing custom properties for dark theme consistency
- [ ] `npm run build` passes with zero errors

## Verification

- `cd frontend && npm run build` — zero TypeScript errors
- `test -f frontend/src/components/ProtectedRoute.tsx` — component exists
- `test -f frontend/src/pages/CreatorDashboard.tsx && test -f frontend/src/pages/CreatorSettings.tsx` — both pages exist
- `grep -q 'ProtectedRoute' frontend/src/App.tsx` — protected routes wired
- `grep -q 'useAuth' frontend/src/App.tsx` — nav auth state wired

## Inputs

- `frontend/src/App.tsx`
- `frontend/src/context/AuthContext.tsx`
- `frontend/src/api/public-client.ts`
- `frontend/src/App.css`

## Expected Output

- `frontend/src/components/ProtectedRoute.tsx`
- `frontend/src/pages/CreatorDashboard.tsx`
- `frontend/src/pages/CreatorDashboard.module.css`
- `frontend/src/pages/CreatorSettings.tsx`
- `frontend/src/pages/CreatorSettings.module.css`
- `frontend/src/App.tsx`

## Verification

cd frontend && npm run build && test -f src/components/ProtectedRoute.tsx && test -f src/pages/CreatorDashboard.tsx && test -f src/pages/CreatorSettings.tsx && grep -q 'ProtectedRoute' src/App.tsx
