4272ca4dfe
- Create ConsultationsView with 5 expandable consultation entries - Each entry has color-coded left border by employer (NHS blue vs Teal) - Collapsed state shows date, org, role, key coded entry - Expanded state shows Duration, HISTORY, EXAMINATION, PLAN, CODED ENTRIES - Accordion behavior: only one entry expanded at a time - Expand animation 200ms ease-out, respects reduced motion - Section headers in uppercase with letter-spacing - Coded entries in [XXX000] format with Geist Mono font
247 lines
14 KiB
Plaintext
247 lines
14 KiB
Plaintext
# Progress Log — Clinical Record PMR Phase
|
|
|
|
## Phase Transition
|
|
|
|
**Previous phase completed:** React conversion of ECG Heartbeat CV (all 12 tasks done)
|
|
**New phase started:** Clinical Record PMR System — Design 7 implementation
|
|
**Date:** 2026-02-11
|
|
|
|
This is a complete redesign of the CV presentation, moving from the ECG animation concept to a Patient Medical Record system interface. All previous components (Hero, Skills, Experience, etc.) will be replaced with PMR-specific views and components.
|
|
|
|
## Codebase Patterns
|
|
|
|
### PMR Design System
|
|
- **Source of truth**: `designs/07-the-clinical-record.md` — Complete specification for the PMR interface
|
|
- **Color palette (light-mode only)**:
|
|
- Main content: `#F5F7FA` (cool light gray)
|
|
- Cards: `#FFFFFF` (white)
|
|
- Sidebar: `#1E293B` (dark blue-gray)
|
|
- Patient banner: `#334155` (lighter blue-gray)
|
|
- NHS blue: `#005EB8` (primary interactive)
|
|
- Green: `#22C55E` (active/resolved)
|
|
- Amber: `#F59E0B` (alerts/in-progress)
|
|
- Red: `#EF4444` (urgent)
|
|
- Borders: `#E5E7EB` (gray-200)
|
|
- **Typography**: Inter for general text, Geist Mono for coded entries/data values
|
|
- **Spacing**: 4px base unit, tighter than previous design (clinical system density)
|
|
- **Borders**: 1px solid gray-200, 4px radius (clinical systems use minimal rounding)
|
|
- **Table rows**: 40px height, alternating colors
|
|
|
|
### Data Architecture
|
|
- All PMR content lives in `src/data/` as typed arrays
|
|
- Separation of data from components enables easy CV updates
|
|
- Types defined in `src/types/pmr.ts`
|
|
|
|
### Animation Approach
|
|
- **Login typing**: `setInterval` with character-by-character reveal (30ms/char username, 20ms/dot password)
|
|
- **View switching**: Instant (no animation) — matches clinical system behavior
|
|
- **Consultation expand**: Height 0→auto, 200ms, ease-out
|
|
- **Alert entrance**: Slide down with spring, 250ms
|
|
- **Alert dismiss**: Icon → checkmark (200ms) → collapse (200ms)
|
|
- **Patient banner condensation**: Smooth height transition, 200ms
|
|
- **Reduced motion**: Typing instant, slides become fades, expand instant
|
|
|
|
### Clinical System Authenticity
|
|
- Navigation is instant — no crossfade
|
|
- Tables use explicit borders on all cells
|
|
- Traffic lights are 8px circles with text labels (never sole indicator)
|
|
- Consultation format: History / Examination / Plan (clinical SOAP note structure)
|
|
- Medications table mimics actual prescribing lists
|
|
- Coded entries use [XXX000] format (SNOMED-style)
|
|
|
|
### Responsive Breakpoints
|
|
- Desktop (>1024px): 220px sidebar, full tables
|
|
- Tablet (768-1024px): 56px icon-only sidebar, scrollable tables
|
|
- Mobile (<768px): Bottom nav bar, card layouts instead of tables
|
|
|
|
### Accessibility Requirements
|
|
- Tables must be proper `<table>` markup with `scope="col"`
|
|
- Clinical alert uses `role="alert"` and `aria-live="assertive"`
|
|
- Keyboard shortcuts: Alt+1-7 for navigation
|
|
- Focus management after view changes and expansions
|
|
- Screen reader announces views and table structure
|
|
|
|
## Iteration Log
|
|
|
|
### Iteration 1 — Task 1: Create PMR data layer and TypeScript types
|
|
- **Completed**: Task 1 - Created PMR data layer with TypeScript interfaces and data files
|
|
- **Files created**:
|
|
- `src/types/pmr.ts` - All PMR TypeScript interfaces (Patient, Consultation, Medication, Problem, Investigation, Document, etc.)
|
|
- `src/data/consultations.ts` - 5 roles mapped to consultation format with History/Examination/Plan structure
|
|
- `src/data/medications.ts` - 18 skills mapped to medication format across 3 categories (Active, Clinical, PRN)
|
|
- `src/data/problems.ts` - 11 problems with traffic light status (3 Active, 2 In Progress, 6 Resolved)
|
|
- `src/data/investigations.ts` - 5 projects as investigations with methodology/results
|
|
- `src/data/documents.ts` - 5 education/certification documents
|
|
- `src/data/patient.ts` - Patient demographic data
|
|
- **Design decisions**:
|
|
- Used SNOMED-style codes for coded entries (EFF001, ALG001, AUT001, etc.)
|
|
- Mapped employer colors: NHS blue (#005EB8) for ICB, Teal (#00897B) for Tesco
|
|
- Proficiency percentages estimated from CV skill descriptions
|
|
- Prescribing history for each skill shows progression over time
|
|
- **Quality checks**: `npm run typecheck` ✓, `npm run lint` ✓, `npm run build` ✓
|
|
- **Learnings**:
|
|
- CV has 5 roles but only 4 explicitly listed dates - inferred Duty Pharmacy Manager from GPhC registration date (Aug 2016)
|
|
- Key numbers verified: £14.6M efficiency, 14,000 patients, £2.6M savings, 70% reduction, 200 hours, £1M revenue, £220M budget
|
|
- Skills categorized into Active (technical), Clinical (healthcare domain), PRN (strategic/leadership)
|
|
|
|
### Iteration 2 — Task 2: Modify ECGAnimation for PMR flatline transition
|
|
- **Completed**: Task 2 - Modified ECGAnimation exit phase for clinical flatline → login transition
|
|
- **Files modified**:
|
|
- `src/components/ECGAnimation.tsx` - Changed exit from fade-to-white to flatline → black → login background
|
|
- **Changes made**:
|
|
- Replaced HOLD_TIME (0.75s) and EXIT_TIME (0.8s) with precise phase timings:
|
|
- FLATLINE_HOLD: 300ms (hold after name trace)
|
|
- FLATLINE_DRAW: 300ms (horizontal line extending rightward)
|
|
- FADE_TO_BLACK: 200ms (canvas opacity fade)
|
|
- BG_TRANSITION: 200ms (background to #1E293B login color)
|
|
- New timing phases: isFlatlinePhase, isFadePhase, isBgTransitionPhase
|
|
- Background now transitions to login screen color (#1E293B) instead of white
|
|
- Flatline drawn from final name position to right edge of viewport
|
|
- Scanline head dot hidden during fade/bg phases
|
|
- **Design decisions**:
|
|
- Flatline visually reads as patient monitor flatline (deliberate metaphor)
|
|
- Total ECG phase still ~5-6 seconds, exit adds ~1 second
|
|
- Background transition uses CSS transition for smooth handoff to LoginScreen
|
|
- **Quality checks**: `npm run typecheck` ✓, `npm run lint` ✓, `npm run build` ✓
|
|
- **Learnings**:
|
|
- Canvas fade must complete before background transition for clean visual
|
|
- The flatline extension needs to go slightly past viewport edge (+50px) for smooth visual
|
|
|
|
### Iteration 3 — Task 3: Build LoginScreen component with typing animation
|
|
- **Completed**: Task 3 - Created LoginScreen component with authentic clinical login typing animation
|
|
- **Files created/modified**:
|
|
- `src/components/LoginScreen.tsx` - New component with typing animation
|
|
- `src/App.tsx` - Added 'login' phase between 'ecg' and 'content'
|
|
- `src/types/index.ts` - Added 'login' to Phase type
|
|
- `index.html` - Added Inter font family
|
|
- `tailwind.config.js` - Added PMR colors (sidebar, banner, nhsblue, etc.) and fonts (inter, geist)
|
|
- **Design decisions**:
|
|
- Username types at 30ms per character (A.CHARLWOOD = 11 chars + space = ~350ms)
|
|
- Password fills 8 dots at 20ms per dot (~160ms)
|
|
- Button shows pressed state (darker, scale) before onComplete callback
|
|
- Blinking cursor at 530ms interval during typing
|
|
- Uses Fira Code as monospace font (Geist Mono not available via Google Fonts)
|
|
- NHS blue shield icon for clinical system branding
|
|
- White login card: 320px wide, 12px radius, subtle shadow
|
|
- **Accessibility**:
|
|
- Respects prefers-reduced-motion: instant text appearance, ~500ms total
|
|
- **Quality checks**: `npm run typecheck` ✓, `npm run lint` ✓, `npm run build` ✓
|
|
- **Learnings**:
|
|
- Geist Mono not available via Google Fonts, using Fira Code as fallback
|
|
- Total login animation timing: ~1.2s (350ms username + 150ms pause + 160ms password + 150ms pause + 100ms button + 200ms hold)
|
|
|
|
### Iteration 4 — Task 4: Build PatientBanner component with full and condensed modes
|
|
- **Completed**: Task 4 - Created PatientBanner component with scroll-based condensation
|
|
- **Files created**:
|
|
- `src/hooks/useScrollCondensation.ts` - IntersectionObserver hook for scroll detection
|
|
- `src/components/PatientBanner.tsx` - Full (80px) and condensed (48px) banner modes
|
|
- **Design decisions**:
|
|
- IntersectionObserver with rootMargin -100px to detect scroll past threshold
|
|
- Smooth height transition using CSS `transition-all duration-200 ease-out`
|
|
- Sticky positioning with z-40 for persistent visibility
|
|
- Status dot: 8px circle, green for Active
|
|
- Badge: NHS blue background, white text, small pill shape
|
|
- Action buttons: outlined with NHS blue, fill on hover
|
|
- GPhC number formatted with spaces like NHS number (221 181 0)
|
|
- Tooltip on NHS No field explaining it's GPhC Registration Number
|
|
- **Accessibility**:
|
|
- `role="banner"` on header element
|
|
- `aria-label` on status dot
|
|
- Proper link semantics for phone and email
|
|
- **Quality checks**: `npm run typecheck` ✓, `npm run lint` ✓, `npm run build` ✓
|
|
- **Learnings**:
|
|
- IntersectionObserver with rootMargin provides cleaner scroll detection than scroll event listeners
|
|
- Sentinel element at top of viewport triggers condensation when it leaves view
|
|
- Sticky positioning requires no JavaScript for the sticky behavior itself
|
|
|
|
### Iteration 5 — Task 5: Build ClinicalSidebar component with navigation and search
|
|
- **Completed**: Task 5 - Created ClinicalSidebar with navigation and search functionality
|
|
- **Files created**:
|
|
- `src/components/ClinicalSidebar.tsx` - Sidebar navigation with 7 items
|
|
- `src/components/PMRInterface.tsx` - Main PMR layout container
|
|
- **Files modified**:
|
|
- `src/App.tsx` - Changed from 'content' to 'pmr' phase, uses PMRInterface
|
|
- `src/types/index.ts` - Updated Phase type: 'content' → 'pmr'
|
|
- **Design decisions**:
|
|
- 220px fixed width sidebar with dark blue-gray background (#1E293B)
|
|
- Header: "CareerRecord PMR v1.0.0" in 50% opacity white
|
|
- 7 navigation items with Lucide icons (ClipboardList, FileText, Pill, AlertTriangle, FlaskConical, FolderOpen, Send)
|
|
- Separator line between Summary and Consultations
|
|
- Active state: 3px NHS blue left border, white text, background rgba(255,255,255,0.12)
|
|
- Hover state: white text at 100%, background rgba(255,255,255,0.08)
|
|
- Search input in header with basic filtering (fuse.js not installed yet)
|
|
- Footer with "Session: A.CHARLWOOD" and current time (updates every minute)
|
|
- URL hash routing (#summary, #consultations, etc.)
|
|
- Keyboard shortcuts: Alt+1-7 for navigation, / to focus search, Escape to clear search
|
|
- **Navigation behavior**:
|
|
- Instant view switching (no animation) — matches clinical system authenticity
|
|
- Click updates URL hash and activeView state simultaneously
|
|
- On page load, hash is read to set initial view
|
|
- **Accessibility**:
|
|
- `role="navigation"` and `aria-label` on sidebar
|
|
- `aria-current="page"` on active nav item
|
|
- Keyboard navigation with Alt+1-7 shortcuts
|
|
- Search has escape key to clear and blur
|
|
- **Quality checks**: `npm run typecheck` ✓, `npm run lint` ✓, `npm run build` ✓
|
|
- **Learnings**:
|
|
- Lucide React already installed, provides all required icons
|
|
- fuse.js not installed — basic search filtering implemented, can enhance later
|
|
- Sticky positioning with `h-screen sticky top-0` keeps sidebar fixed while content scrolls
|
|
- PMRInterface wraps PatientBanner + sidebar + main content layout
|
|
|
|
### Iteration 6 — Task 6: Build SummaryView component with clinical alert
|
|
- **Completed**: Task 6 - Created SummaryView with Clinical Alert and summary cards
|
|
- **Files created**:
|
|
- `src/components/views/SummaryView.tsx` - Full Summary view with Clinical Alert and 4 cards
|
|
- **Files modified**:
|
|
- `src/components/PMRInterface.tsx` - Updated to render SummaryView when activeView is 'summary'
|
|
- **Design decisions**:
|
|
- Clinical Alert: amber background (#FEF3C7), 4px amber left border, AlertTriangle icon
|
|
- Alert animates in with max-height transition (300ms delay after view loads)
|
|
- Acknowledge button: on click, icon cross-fades to green Check (200ms), then alert collapses (200ms)
|
|
- Patient Demographics card: full width, two-column key-value layout with right-aligned labels
|
|
- Active Problems card: shows 3 active/in-progress problems with traffic light dots and dates
|
|
- Current Medications Quick View: 4-column table (Drug, Dose, Freq, Status), top 5 Active meds
|
|
- Last Consultation card: shows most recent role with truncated history text
|
|
- Traffic lights: 8px circles, green for Active/Resolved, amber for In Progress
|
|
- All tables use proper semantic `<table>` markup with `scope="col"`
|
|
- "View Full List" / "View Full Record" links navigate to corresponding views
|
|
- **Accessibility**:
|
|
- `role="alert"` and `aria-live="assertive"` on Clinical Alert
|
|
- `aria-label` on main content area with current view name
|
|
- Proper table semantics for medications table
|
|
- Traffic lights always accompanied by text labels (never sole indicator)
|
|
- Respects `prefers-reduced-motion`: alert appears instantly, no animations
|
|
- **Quality checks**: `npm run typecheck` ✓, `npm run lint` ✓, `npm run build` ✓
|
|
- **Learnings**:
|
|
- Alert animation uses max-height transition for smooth expand/collapse
|
|
- Clinical Alert text uses amber-800 (#92400E) for contrast against amber-100 background
|
|
- Grid layout: demographics full width, problems/medications side-by-side, last consultation full width
|
|
- `line-clamp-2` and `line-clamp-3` utilities work well for truncating text in cards
|
|
|
|
### Iteration 7 — Task 7: Build ConsultationsView with History/Examination/Plan structure
|
|
- **Completed**: Task 7 - Created ConsultationsView with expandable consultation entries
|
|
- **Files created**:
|
|
- `src/components/views/ConsultationsView.tsx` - Full Consultations view with 5 expandable entries
|
|
- **Files modified**:
|
|
- `src/components/PMRInterface.tsx` - Added ConsultationsView to renderView switch
|
|
- **Design decisions**:
|
|
- Each entry has 3px left border color-coded by employer: NHS blue (#005EB8) for ICB, Teal (#00897B) for Tesco
|
|
- Collapsed state shows: status dot, date, organization (colored), role title, key coded entry summary
|
|
- Status dot: green for current roles, gray for historical
|
|
- Expanded state shows: Duration, HISTORY (paragraph), EXAMINATION (bullets), PLAN (bullets), CODED ENTRIES
|
|
- Section headers styled in Inter 600, 12px, uppercase, tracking-wider, gray-400
|
|
- Coded entries use [XXX000] format in Geist Mono, gray-400
|
|
- Only one entry expanded at a time (accordion behavior)
|
|
- Expand animation: height 0→auto (200ms, ease-out)
|
|
- Chevron icon rotates 180° when expanded
|
|
- **Accessibility**:
|
|
- `aria-expanded` on toggle buttons
|
|
- Status dots have `aria-label` describing current vs historical
|
|
- Respects `prefers-reduced-motion`: expand is instant
|
|
- **Quality checks**: `npm run typecheck` ✓, `npm run lint` ✓, `npm run build` ✓
|
|
- **Learnings**:
|
|
- Height animation uses `height: auto` which requires setting height to undefined after animation
|
|
- Content inside expanded area uses separate opacity transition for smooth appearance
|
|
- Border-left styling with explicit width/color in style prop for dynamic org colors
|