# Adding a New Advisor-Only Page to SPQ v2 Five files to touch. Follow the exact pattern below. ## Step-by-step ### 1. Create the page component ``` src/pages/advisor/.tsx ``` Use `export default function PageName()` — lazy import expects a default export. Page shell pattern: ```tsx import { useCallback, useEffect, useState } from 'react'; import { pb } from '../../lib/pocketbase'; export default function PageName() { const userId = pb.authStore.model?.id as string | undefined; // ... state, effects, return JSX using the same Tailwind classes // as other advisor pages (AdvisorTeam as canonical reference) } ``` ### 2. `src/App.tsx` — lazy import + route ```tsx const PageName = lazy(() => import('./pages/advisor/PageName')); ``` Route inside `}>`: ```tsx } /> ``` `AdvisorOnly` restricts access to `advisor` role only. ### 3. `src/components/Layout.tsx` — nav item Add the icon to the lucide-react import, then add a nav item in the `navItems` array: ```tsx { to: "/route-path", label: "Page Label", icon: IconName }, ``` Also add preload import and wire handlers: ```tsx import { preloadSettingsPage, preloadTimeCards } from "../lib/routePreload"; // In the NavLink loop: onMouseEnter={item.to === "/route-path" ? preloadPageName : ...} ``` ### 4. `src/components/mobile/MobileLayout.tsx` — same nav pattern Mirror the import, nav item, and preload wiring from step 3. ### 5. `src/lib/routePreload.ts` — preload helpers ```ts export const loadPageName = () => import('../pages/advisor/PageName'); export function preloadPageName() { void loadPageName(); } ``` ## Common page components available - `ListSkeleton` / `ListError` — from `../../components/ui/` - `StatusBadge` — define inline or import from existing pages - Loading/error/empty pattern: `loading ? : error ? : actualContent` ## Verification ```bash npm run build && npm run lint && npm run test ``` ## Pitfalls - **Lazy import path**: Must point to the .tsx file directly. The `lazy(() => import(...))` wrapper uses dynamic import — Vite code-splits it. - **Don't forget MobileLayout** — every new page needs a nav entry in both layouts or mobile users can't reach it. - **Preload wiring**: Both `onMouseEnter` and `onFocus` need the preload call in both Layout.tsx and MobileLayout.tsx. Missing either means no prefetch.