# Frontend Components — Unit 3: Layout & Navigation
## Modified Components
### `AppLayout.tsx` (modify)
**Path**: `frontend/src/components/layout/AppLayout.tsx`
Remove `Topbar`. Add `MobileBar` and `SidebarOverlay`. Manage `isMenuOpen` state.
```tsx
{isMenuOpen &&
setIsMenuOpen(false)} />}
setIsMenuOpen(true)} />
```
---
### `Sidebar.tsx` (modify)
**Path**: `frontend/src/components/layout/Sidebar.tsx`
Changes:
- Add `roles?: Role[]` to `NavItem` — filter visible items by `user.role`
- Add `SidebarFooter` section at the bottom with `LanguageSwitcher`, `ThemeToggle`, `UserMenu`
- Accept optional `onClose?: () => void` prop (used by mobile overlay close button)
- Retain `data-testid="app-sidebar"`
Nav items and role visibility:
| Label key | Route | Roles | Icon |
|---|---|---|---|
| `nav.dashboard` | `/dashboard` | all | `LayoutDashboard` |
| `nav.users` | `/users` | Owner, Administrator | `Users` |
| `nav.settings` | `/settings` | Owner | `Settings` |
| `nav.cms` | `/cms` | Owner | `FileText` |
| `nav.profile` | `/profile` | all | `User` |
---
## New Components
### `MobileBar.tsx`
**Path**: `frontend/src/components/layout/MobileBar.tsx`
Visible only on `< md`. Contains hamburger button and app name.
Props: `onMenuOpen: () => void`
```tsx
```
---
### `SidebarOverlay.tsx`
**Path**: `frontend/src/components/layout/SidebarOverlay.tsx`
Full-screen overlay wrapping `Sidebar` for mobile. Backdrop closes it on click.
```tsx
```
Props: `onClose: () => void`
---
### `ThemeToggle.tsx`
**Path**: `frontend/src/components/layout/ThemeToggle.tsx`
Toggles dark/light mode. Uses `useTheme()` hook.
```tsx
```
---
### `useTheme.ts`
**Path**: `frontend/src/hooks/useTheme.ts`
```ts
function useTheme(): { theme: Theme; isDark: boolean; toggleTheme: () => void }
```
Reads initial value from `localStorage['cms-theme']` or `prefers-color-scheme`. Syncs DOM class on ``.
---
## Removed Components
### `Topbar.tsx`
Deleted. `data-testid="app-topbar"` removed from the DOM.
---
## `index.html` Change
Add no-flash inline script in `` before any stylesheet:
```html
```
---
## i18n Additions
**`nl/translation.json`**:
```json
{
"nav": {
"settings": "Instellingen",
"profile": "Profiel",
"openMenu": "Navigatie openen"
},
"theme": {
"switchToLight": "Overschakelen naar licht thema",
"switchToDark": "Overschakelen naar donker thema"
}
}
```
**`en/translation.json`**:
```json
{
"nav": {
"settings": "Settings",
"profile": "Profile",
"openMenu": "Open navigation"
},
"theme": {
"switchToLight": "Switch to light theme",
"switchToDark": "Switch to dark theme"
}
}
```
---
## Test IDs Summary
| Element | `data-testid` |
|---|---|
| Sidebar | `app-sidebar` |
| Mobile bar | `app-mobile-bar` |
| Hamburger button | `mobile-menu-button` |
| Sidebar overlay container | `sidebar-overlay` |
| Sidebar backdrop | `sidebar-backdrop` |
| Theme toggle | `theme-toggle` |
| Nav: dashboard | `nav-dashboard` |
| Nav: users | `nav-users` |
| Nav: settings | `nav-settings` |
| Nav: cms | `nav-cms` |
| Nav: profile | `nav-profile` |
| Main content area | `app-main` |