5ad67a512f
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
271 lines
21 KiB
Plaintext
271 lines
21 KiB
Plaintext
# Progress Log
|
||
|
||
## Codebase Patterns
|
||
|
||
### Project Structure
|
||
- Components in `src/components/`, tiles in `src/components/tiles/`
|
||
- Old views still in `src/components/views/` (to be removed in Task 21)
|
||
- Data files in `src/data/` — consultations.ts, medications.ts, problems.ts, investigations.ts, documents.ts, patient.ts + new files: profile.ts, tags.ts, alerts.ts, kpis.ts, skills.ts
|
||
- Types in `src/types/pmr.ts` (PMR interfaces) and `src/types/index.ts` (Phase type)
|
||
- Hooks in `src/hooks/` — useScrollCondensation.ts, useBreakpoint.ts
|
||
- Contexts in `src/contexts/` — AccessibilityContext.tsx (has 1 pre-existing ESLint warning — expected)
|
||
- Lib in `src/lib/` — search.ts (fuse.js integration)
|
||
- Path alias: `@/` maps to `./src/`
|
||
|
||
### Phase Management
|
||
- App.tsx controls phase: 'boot' -> 'ecg' -> 'login' -> 'pmr'
|
||
- Phase type defined in `src/types/index.ts` as `'boot' | 'ecg' | 'login' | 'pmr'`
|
||
- BootSequence.tsx handles terminal animation — LOCKED
|
||
- ECGAnimation.tsx handles heartbeat + letter tracing + flatline exit — LOCKED
|
||
- LoginScreen.tsx bridges to dashboard (was PMRInterface, now DashboardLayout)
|
||
|
||
### Data Architecture (CORRECT — do not modify existing files)
|
||
- All data files are populated with accurate CV content from References/CV_v4.md
|
||
- 5 consultation entries (roles), 18 medications (skills with prescribingHistory), 11 problems (achievements), 6 investigations (projects), 5 documents (education)
|
||
- Types are properly defined in pmr.ts — Consultation, Medication, Problem, Investigation, Document, Patient, ViewId
|
||
- New types needed: Tag, Alert, KPI, SkillMedication (Task 2)
|
||
|
||
### Known Dependencies
|
||
- React 18.3.1, TypeScript, Vite
|
||
- Tailwind CSS for utility classes
|
||
- Framer Motion 11.15.0 for animations
|
||
- Lucide React 0.468.0 for icons
|
||
- fuse.js 7.0.0 (already installed) for fuzzy search
|
||
|
||
### Typography
|
||
- Elvaro Grotesque (`font-ui`) — primary UI font, 7 weights (300-900), loaded from Fonts/ directory
|
||
- Blumir (`font-ui-alt`) — alternative, variable font (100-700)
|
||
- Geist Mono (`font-geist`) — timestamps, data values, coded entries
|
||
- Fira Code (`font-mono`) — boot/ECG terminal only
|
||
- Do NOT use Inter, Roboto, DM Sans, or system defaults
|
||
- DM Sans in the concept HTML is a PLACEHOLDER — use Elvaro Grotesque
|
||
- Font mapping was corrected in Task 1: Elvaro = font-ui (primary), Blumir = font-ui-alt (alternative)
|
||
|
||
### Design Tokens
|
||
- Dashboard background: use `--bg-dashboard` (#F0F5F4), NOT `--bg` (#FFFFFF which is for boot/ECG)
|
||
- Three-tier shadows: `--shadow-sm` (resting), `--shadow-md` (hover/interactive), `--shadow-lg` (overlays)
|
||
- Border tiers: `--border` (#D4E0DE, structural), `--border-light` (#E4EDEB, cards)
|
||
- Accent: `--accent` (#0D6E6E teal), `--accent-hover` (#0A8080), `--accent-light` (rgba 0.08), `--accent-border` (rgba 0.18)
|
||
- Status colors each have base + light + border variants (success, amber, alert, purple)
|
||
- Tailwind: `pmr-*` prefix for all dashboard colors (e.g., `bg-pmr-bg`, `text-pmr-accent`, `border-pmr-border-light`)
|
||
- Tailwind shadows: `shadow-pmr-sm`, `shadow-pmr-md`, `shadow-pmr-lg`
|
||
- Tailwind radius: `rounded-card` (8px), `rounded-card-sm` (6px), `rounded-login` (12px)
|
||
|
||
### Dashboard Layout
|
||
- DashboardLayout.tsx is the main container for the pmr phase — replaces PMRInterface
|
||
- Three-zone: TopBar (fixed, z-100, 48px) + Sidebar (fixed left, 272px) + Main (scrollable card grid)
|
||
- Card grid: CSS Grid `repeat(2, 1fr)` gap 16px, responsive 1fr at ≤900px via `.dashboard-grid` class
|
||
- Entrance: three separate Framer Motion variants (topbar → sidebar → content), staggered with delays
|
||
- Sidebar: default export (`import Sidebar from './Sidebar'`), TopBar: named export (`import { TopBar } from './TopBar'`)
|
||
- Background color transition: DashboardLayout covers App.tsx's `bg-black` with `var(--bg-dashboard)` + `minHeight: 100vh`
|
||
|
||
### Visual Review
|
||
- Dev server runs on `http://localhost:5173` throughout the loop
|
||
- App has boot→ECG→login→dashboard sequence (~15s on first load)
|
||
- If browser tools fail, skip visual review and note in iteration log — don't block progress
|
||
|
||
## Manual Intervention — 2026-02-13
|
||
### Reason: Complete redesign — replacing CareerRecord PMR with GP System Dashboard
|
||
### Changes made:
|
||
- **IMPLEMENTATION_PLAN.md**: Completely rewritten with 21 new tasks for GP System dashboard overhaul
|
||
- **guardrails.md**: Completely rewritten for new design direction (teal palette, tile-based layout, 8px radius, new shadow system)
|
||
- **progress.txt**: This intervention entry added
|
||
- **CLAUDE.md**: Will be updated by Task 3 in the new plan (architecture, colors, components, styling)
|
||
|
||
### Previous plan status: 15/15 tasks completed (all checked off)
|
||
### New plan: 21 tasks across 4 phases (Foundation → Core Layout → Dashboard Tiles → Interactions → Polish)
|
||
|
||
### What's being replaced:
|
||
- `PatientBanner.tsx` → `TopBar.tsx` (white top bar with search and session info)
|
||
- `ClinicalSidebar.tsx` → `Sidebar.tsx` (light background #F7FAFA, person header, tags, alerts only)
|
||
- `PMRInterface.tsx` → `DashboardLayout.tsx` (topbar + sidebar + scrollable card grid)
|
||
- All 7 `views/*.tsx` files → Dashboard tile components in `src/components/tiles/`
|
||
- Color palette: dark sidebar (#1E293B) + NHS Blue (#005EB8) → light sidebar (#F7FAFA) + teal (#0D6E6E)
|
||
- Navigation: sidebar-nav view-switching → single scrollable dashboard with expandable tiles
|
||
- Patient banner scroll condensation → removed (no banner, just topbar)
|
||
|
||
### What's preserved:
|
||
- Boot sequence (BootSequence.tsx) — LOCKED
|
||
- ECG animation (ECGAnimation.tsx) — LOCKED
|
||
- Login screen (LoginScreen.tsx) — unchanged
|
||
- Font setup: Elvaro Grotesque (primary UI), Blumir (alt), Geist Mono (data), Fira Code (terminal only)
|
||
- All data files in src/data/ — content unchanged, new data files added
|
||
- fuse.js dependency — reused for command palette search
|
||
- App.tsx phase management (boot → ecg → login → pmr) — pmr phase now renders DashboardLayout
|
||
|
||
### Context for next iteration:
|
||
- The reference design is `References/GPSystemconcept.html` — READ THIS before starting any visual task
|
||
- The old PMR components STILL EXIST in the codebase. Don't delete them yet — some expand/collapse patterns and data rendering can be reused inside tile expansion (Task 16). Cleanup happens in Task 21.
|
||
- Login screen still transitions to `#1E293B` background. The new dashboard has `#F0F5F4` background. The LoginScreen.tsx may need a background color update, or the transition can be handled in DashboardLayout's entrance animation.
|
||
- The concept HTML uses DM Sans font — this is a PLACEHOLDER. Production uses Elvaro Grotesque (font-ui). Do not switch to DM Sans.
|
||
- The concept's command palette has a comprehensive data model — use it as reference for building the palette in Task 18.
|
||
- Tile interactions (expansion, KPI flip) are in Phase 3. Tiles in Phase 2 should be built as static/display-only first, with data attributes or props that Phase 3 can hook into.
|
||
|
||
### New guardrails added:
|
||
- Accent color: teal #0D6E6E (replacing NHS Blue #005EB8 as primary interactive color)
|
||
- Border radius: 8px for cards (was 4px)
|
||
- Shadow system: three-tier (sm/md/lg) replacing single pmr shadow
|
||
- Sidebar: light background, PersonHeader + Tags + Alerts ONLY (projects, skills, education moved to tiles)
|
||
- Layout: TopBar + Sidebar + Card Grid (replacing PatientBanner + ClinicalSidebar + view switching)
|
||
- Tile ordering: Patient Summary → Latest Results + Core Skills → Last Consultation → Career Activity → Education → Projects
|
||
- Skills frequency: user-specified values (Data Analysis=twice daily, etc.)
|
||
|
||
## Iteration Log
|
||
|
||
### Iteration 1 — Task 1: Update design tokens and Tailwind config
|
||
**Status:** Complete
|
||
**Changes:**
|
||
- Updated `src/index.css`: Added full GP System Dashboard token set (colors, shadows, layout vars, status colors with light/border variants). Kept legacy `--pmr-*` aliases for backward compat. Updated values of legacy tokens to match new palette (e.g., `--pmr-content` → `#F0F5F4`, `--pmr-sidebar` → `#F7FAFA`, `--pmr-radius` → `8px`).
|
||
- Updated `tailwind.config.js`: New pmr color tokens (bg, surface, sidebar, accent, text-primary/secondary/tertiary, border/border-light, success, amber, alert, purple). Three-tier shadow system (pmr-sm/md/lg). Border-radius updated (card=8px, card-sm=6px, login=12px).
|
||
- **Fixed font-ui/font-ui-alt swap**: Previous iterations had Blumir as `font-ui` and Elvaro as `font-ui-alt` — this was backwards. Now corrected: Elvaro Grotesque = `font-ui` (primary), Blumir = `font-ui-alt` (alternative). No components were using these classes directly, so no breakage.
|
||
- Used `--bg-dashboard` for the dashboard background (not `--bg`) to avoid conflicting with the existing `--bg: #FFFFFF` used by boot/ECG phases.
|
||
**Learnings:**
|
||
- The `--bg` CSS var is used for boot/ECG phases (#FFFFFF). Dashboard background uses `--bg-dashboard` (#F0F5F4) to avoid collision.
|
||
- No existing components reference `font-ui` or `font-ui-alt` Tailwind classes, so the font swap was safe.
|
||
- The old shadow tokens (`pmr-hover`, `pmr-banner`) were not referenced in any component code.
|
||
**Quality checks:** typecheck ✓, lint ✓ (1 pre-existing warning), build ✓
|
||
**Visual review:** Not applicable (token-only changes, no visual components yet)
|
||
|
||
### Iteration 2 — Task 2: Create new data files and update types
|
||
**Status:** Complete
|
||
**Changes:**
|
||
- Created `src/data/profile.ts` — personal statement extracted from CV_v4.md (exact match)
|
||
- Created `src/data/tags.ts` — 5 sidebar tags with color variants (teal, amber, green)
|
||
- Created `src/data/alerts.ts` — 2 sidebar alert flags (£14.6M savings, £220M budget) with severity and lucide-react icon names
|
||
- Created `src/data/kpis.ts` — 4 KPI metrics (Budget, Savings, Years, Team Size) with values, labels, subs, color variants, and explanation text for flip cards
|
||
- Created `src/data/skills.ts` — 5 technical skills as "SkillMedication" entries with user-specified frequencies (Data Analysis="Twice daily", Python="Daily", SQL="Daily", Power BI="Once weekly", JS/TS="When required"), plus years, proficiency, category, status, and lucide-react icon names
|
||
- Updated `src/types/pmr.ts` — added 4 new interfaces: Tag, Alert, KPI, SkillMedication
|
||
**Learnings:**
|
||
- All new data files follow the established pattern: import types, export const array
|
||
- Icon names are stored as strings (lucide-react icon names) — components will dynamically import them
|
||
- Skills frequency strings are user-specified values (not standardized enum like old Medication type)
|
||
- KPI explanations are substantial text blocks for flip card backs — these will be displayed in full when users flip the cards
|
||
- All CV numbers/dates verified against CV_v4.md — £220M, £14.6M, 9+ years, team of 12, start years for skills
|
||
**Quality checks:** typecheck ✓, lint ✓ (1 pre-existing warning), build ✓
|
||
**Visual review:** Not applicable (data-only changes, no visual components yet)
|
||
|
||
### Iteration 3 — Task 4: Build TopBar component
|
||
**Status:** Complete
|
||
**Changes:**
|
||
- Created `src/components/TopBar.tsx` — fixed 48px header with three zones:
|
||
- Left: Home icon (lucide-react, 18px, accent) + "Headhunt Medical Center" (13px, 600 weight) + "Remote" version badge (11px, tertiary)
|
||
- Center: Search bar button (max-width 560px, min-width 400px, 42px height) with Search icon, placeholder text, Ctrl+K kbd badge. On click triggers `onSearchClick` prop (for command palette in Task 18). Hidden on mobile (<768px). Hover/focus border transitions to accent color with focus ring.
|
||
- Right: "Dr. A.CHARLWOOD" text (hidden on <640px) + "Active Session · [time]" pill badge (Geist Mono, accent-light bg, accent-border)
|
||
- Component uses CSS custom properties from Task 1 tokens (--surface, --border, --accent, --text-primary, --text-secondary, --text-tertiary, --bg-dashboard, --accent-light, --accent-border)
|
||
- Live time updates every 60 seconds using setInterval
|
||
- Search bar is a `<button>` element (not input) — it doesn't do inline search, only triggers the command palette
|
||
- Responsive: search bar hidden on <768px (md breakpoint), user name hidden on <640px (sm breakpoint)
|
||
**Learnings:**
|
||
- Search bar should be a button, not an input — it triggers the command palette overlay (Task 18). No inline filtering.
|
||
- Using `var(--radius-card)` for 8px border radius on the search bar container
|
||
- Time format: 24-hour (en-GB locale), no seconds — matches clinical system convention
|
||
- TopBar is not yet wired into DashboardLayout (that's Task 7) — component is created and ready
|
||
**Quality checks:** typecheck ✓, lint ✓ (1 pre-existing warning), build ✓
|
||
**Visual review:** Not applicable (component not yet wired into App — will be visible after Task 7)
|
||
|
||
### Iteration 4 — Tasks 5-6: Build Sidebar with PersonHeader, Tags, and Alerts
|
||
**Status:** Complete
|
||
**Changes:**
|
||
- Created `src/components/Sidebar.tsx` — complete sidebar component with three main sections:
|
||
- **PersonHeader**: 52px teal gradient avatar with "AC" initials, name "CHARLWOOD, Andrew" (15px, 700 weight), title "Pharmacy Data Technologist" (11.5px, Geist Mono), status badge "Open to Opportunities" with animated pulse dot (6px, success color, 2s pulse animation). Details grid with 6 rows: GPhC No. (monospace, letter-spaced), Education, Location, Phone (accent link), Email (accent link), Registered. 2px teal border-bottom separator.
|
||
- **Tags**: Section title with divider line. 5 colored pill badges (10.5px, 3px/8px padding, 4px radius) in three color variants (teal/amber/green). Data from tags.ts.
|
||
- **Alerts/Highlights**: 2 flag items with lucide-react icons (AlertTriangle for alert, AlertCircle for amber). 11px, 700 weight, 7px/10px padding, 6px radius. Severity-based colors.
|
||
- Added animations to `src/index.css`:
|
||
- `@keyframes pulse` for status badge dot (opacity 1→0.4→1, 2s infinite)
|
||
- `.pmr-scrollbar` custom scrollbar styles (4px width, transparent track, border-colored thumb, hover darkens)
|
||
- Sidebar container: 272px width, light background (#F7FAFA), right border, auto overflow with custom scrollbar, 20px/16px padding, flex column
|
||
- Sub-components: `SectionTitle` (10px uppercase with divider line), `TagPill` (color variant mapping), `AlertFlag` (dynamic icon selection, severity styling)
|
||
**Learnings:**
|
||
- Combined Tasks 5 and 6 into a single component file — they're interdependent parts of the same sidebar
|
||
- Used inline styles instead of Tailwind for most styling to match the ref spec precisely and avoid conflicts with CSS custom properties
|
||
- Dynamic icon selection: icons stored as strings in data (lucide-react icon names), components conditionally render the correct icon component
|
||
- Phone number formatting: `07795553088` → `07795 553 088` using replace with regex capture groups
|
||
- The sidebar is not yet wired into the dashboard layout — that's Task 7
|
||
- Hover effects on links: inline onMouseEnter/onMouseLeave handlers toggle textDecoration (underline on hover)
|
||
**Quality checks:** typecheck ✓, lint ✓ (1 pre-existing warning), build ✓
|
||
**Visual review:** Not applicable (component not yet wired into App — will be visible after Task 7)
|
||
|
||
### Iteration 5 — Task 7: Build DashboardLayout and wire up App.tsx
|
||
**Status:** Complete
|
||
**Changes:**
|
||
- Created `src/components/DashboardLayout.tsx` — main layout container with three-zone structure:
|
||
- TopBar (fixed via TopBar component, animated slide-down from -48px)
|
||
- Sidebar (fixed left via Sidebar component, animated slide from -272px)
|
||
- Main content area (flex: 1, scrollable, 24px 28px 40px padding) with card grid placeholder
|
||
- Card grid uses CSS Grid: `repeat(2, 1fr)` with 16px gap, responsive to 1 column at ≤900px
|
||
- Three Framer Motion entrance variants: topbar (200ms), sidebar (250ms, 50ms delay), content (300ms, 150ms delay)
|
||
- All animations respect `prefers-reduced-motion` via module-scope matchMedia check (established pattern)
|
||
- Added `dashboard-grid` responsive CSS class in `src/index.css` for the 900px breakpoint
|
||
- Updated `src/App.tsx`: replaced `PMRInterface` import/render with `DashboardLayout` in 'pmr' phase
|
||
- Background transition handled by option 1 from ref: DashboardLayout sets `background: var(--bg-dashboard)` with `minHeight: 100vh`, covering the dark login background as the entrance animation plays
|
||
- Command palette state placeholder added (useState for open/close) — will be wired in Task 18
|
||
- TopBar `onSearchClick` prop connected to command palette open handler
|
||
- Main content area uses `pmr-scrollbar` class for styled scrollbar (thin, border-colored thumb)
|
||
**Learnings:**
|
||
- DashboardLayout uses separate `initial`/`animate` on each motion.div rather than a parent orchestrator — cleaner for three independently animated zones
|
||
- The `bg-black` on App.tsx's outer div provides the dark background during boot/ecg/login; DashboardLayout's own background covers it during pmr phase
|
||
- Card grid is empty (tiles come in Tasks 8-15) but the grid structure is in place with comments marking each tile position
|
||
- Sidebar is default-exported, TopBar is named-exported — imports adjusted accordingly
|
||
- The responsive breakpoint (900px) is in CSS not Tailwind because it's a custom value not matching standard Tailwind breakpoints
|
||
**Quality checks:** typecheck ✓, lint ✓ (1 pre-existing warning), build ✓
|
||
**Visual review:** Skipped — browser tools unavailable. Dashboard layout structure verified via quality checks. Visual review will happen when tiles are added.
|
||
|
||
### Iteration 6 — Task 8: Build reusable Card component
|
||
**Status:** Complete
|
||
**Changes:**
|
||
- Created `src/components/Card.tsx` with two exports:
|
||
- `Card` component: Reusable base card with white background, 8px border-radius, shadow-sm
|
||
- `CardHeader` component: Colored dot (8px circle) + uppercase title + optional mono right text
|
||
- Card styling: Uses CSS custom properties (--surface, --border-light, --border, --radius, --shadow-sm/md)
|
||
- Hover interaction: Shadow deepens to shadow-md, border strengthens to --border (via useState + onMouseEnter/onMouseLeave)
|
||
- Full-width variant: `full` prop sets `gridColumn: '1 / -1'` to span both grid columns
|
||
- CardHeader dot colors: teal (#0D6E6E), amber (#D97706), green (#059669), alert (#DC2626), purple (#7C3AED)
|
||
- Header typography: title is 12px, 600 weight, uppercase, 0.06em letter-spacing, text-secondary
|
||
- Right text: 10px, 400 weight, text-tertiary, Geist Mono font, margin-left auto
|
||
- All styles use inline React.CSSProperties to precisely match the ref spec
|
||
**Learnings:**
|
||
- Card uses inline styles rather than Tailwind classes — ensures precise CSS custom property mapping
|
||
- Hover state managed with React state (not CSS :hover) to coordinate shadow + border color transitions
|
||
- CardHeader accepts dotColor as string literal union type ('teal' | 'amber' | etc.) — mapped to hex colors via object
|
||
- Component is ready to be used by all tile components (Tasks 9-15)
|
||
**Quality checks:** typecheck ✓, lint ✓ (1 pre-existing warning), build ✓
|
||
**Visual review:** Not applicable — base component, will be visible once integrated into tiles
|
||
|
||
### Iteration 7 — Task 9: Build PatientSummary tile
|
||
**Status:** Complete
|
||
**Changes:**
|
||
- Created `src/components/tiles/PatientSummaryTile.tsx` — simple read-only tile displaying personal statement
|
||
- Full-width card (via `full` prop on Card component) with teal dot CardHeader
|
||
- Body text: 13px, line-height 1.6, text-primary color, font-ui (Elvaro Grotesque)
|
||
- Content sourced from `src/data/profile.ts` (personalStatement export)
|
||
- Updated `src/components/DashboardLayout.tsx` to import and render PatientSummaryTile as first tile in grid
|
||
**Learnings:**
|
||
- PatientSummaryTile is the simplest tile — no expansion, no interactivity, just display
|
||
- The `full` prop on Card correctly spans both grid columns (grid-column: 1 / -1)
|
||
- CardHeader with teal dot + "PATIENT SUMMARY" matches the spec exactly
|
||
- Personal statement text is substantial (4 sentences, ~110 words) — 13px with 1.6 line-height provides readable density
|
||
- This is the first tile actually visible in the dashboard — sets the visual tone for subsequent tiles
|
||
**Quality checks:** typecheck ✓, lint ✓ (1 pre-existing warning), build ✓
|
||
**Visual review:** Skipped — no browser tools available. Will verify visually after multiple tiles are in place.
|
||
|
||
### Iteration 8 — Task 10: Build LatestResults tile
|
||
**Status:** Complete
|
||
**Changes:**
|
||
- Created `src/components/tiles/LatestResultsTile.tsx` — half-width card with 2×2 metric grid
|
||
- CardHeader: teal dot + "LATEST RESULTS" + "Updated May 2025" right text (Geist Mono)
|
||
- 2×2 CSS grid (1fr 1fr, 12px gap) containing four MetricCard sub-components
|
||
- Each MetricCard: 14px padding, 6px radius, border-light, dashboard background (#F0F5F4)
|
||
- Value: 22px, 700 weight, -0.02em letter-spacing, line-height 1.2, colored by variant (green/amber/teal)
|
||
- Label: 11px, 500 weight, text-secondary
|
||
- Sub: 10px, text-tertiary, Geist Mono font
|
||
- Added `data-kpi-id` attribute on each metric card for Task 17 flip interaction hookup
|
||
- Updated `src/components/DashboardLayout.tsx` — imported and rendered LatestResultsTile in the half-width left column position
|
||
**Learnings:**
|
||
- MetricCard uses `var(--bg-dashboard)` for background (#F0F5F4) as specified in ref — creates subtle contrast against the white card surface
|
||
- The colorMap for KPI values maps green/amber/teal variant strings to hex colors — same approach as Card's dotColorMap
|
||
- Half-width tiles (no `full` prop) naturally fill one grid column in the 2-column dashboard grid
|
||
- The `data-kpi-id` attribute provides a hook for Task 17's flip card interaction without adding click handlers yet
|
||
**Quality checks:** typecheck ✓, lint ✓ (1 pre-existing warning), build ✓
|
||
**Visual review:** Skipped — no browser tools available.
|
||
|