DRY refactor: Extract reusable patient search logic from ZoekenBlock. New files: - lib/cortex/hooks/use-patient-search.ts (116 lines) Debounced patient search with abort controller - lib/cortex/hooks/use-patient-selection.ts (98 lines) FHIR fetch + store update flow - lib/fhir/patient-mapper.ts (109 lines) FHIR Patient to DB Patient mapping + utilities - components/cortex/shared/patient-list-item.tsx (114 lines) Reusable patient list item with loading states Refactored: - ZoekenBlock: 349 -> 127 lines (-64%) Documentation: - docs/intent/patient-search/ux-analyse-patient-selectie.md - docs/intent/patient-search/bouwplan-patient-selectie-v1.md CLAUDE.md updated with Cortex architecture documentation. Epic 0 complete: 4/4 stories (4 SP) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
7.6 KiB
7.6 KiB
UX Analyse: Patient Selectie in Cortex
Datum: 2025-01-03 Auteur: Colin Lit + Claude Status: Analyse compleet, ready for implementation planning
1. Probleemstelling
Huidige Flow
User: "Notitie medicatie Jan"
|
Cortex: "Welke patient bedoel je?"
|
[ZoekenBlock opent in artifact area]
|
User klikt op "Jan de Vries"
|
[Patient wordt actief, ZoekenBlock sluit]
|
User moet OPNIEUW "notitie medicatie" typen
|
[DagnotatieBlock opent, maar zonder prefill!]
Pain Points
| # | Pain Point | Ernst | Omschrijving |
|---|---|---|---|
| 1 | Twee-staps flow | Hoog | Chat vraagt, apart venster, klik, terug naar notitie |
| 2 | Context verlies | Hoog | activePatient uit store wordt NIET gebruikt in DagnotatieBlock |
| 3 | Dubbele zoekfunctie | Medium | ZoekenBlock en DagnotatieBlock hebben beide patient search |
| 4 | Geen inline disambiguatie | Hoog | Moet naar apart panel switchen |
| 5 | Clarification niet geimplementeerd | Hoog | resolveClarification() doet niets na selectie |
| 6 | Geen re-processing | Hoog | Na patient selectie moet user opnieuw intent typen |
2. Oplossingsrichtingen
2.1 @Mention Systeem (P1)
Type @ gevolgd door naam voor autocomplete dropdown in chat input.
+-----------------------------------------------------+
| Notitie voor @jan |
| +----------------------+ |
| | Jan de Vries (52) | |
| | Jan Bakker (34) | |
| | Jan Pieterse (67) | |
| +----------------------+ |
+-----------------------------------------------------+
Voordelen:
- Disambiguatie voor verzenden, niet erna
- Bekende UX pattern (Slack, GitHub, Discord)
- Patient ID direct beschikbaar voor AI
- Geen extra API calls na submit
2.2 Persistent Patient Sidebar (P1)
Altijd zichtbare patient lijst aan de linkerkant.
+----------+----------------------------------------+
| Zoek | |
+----------| Chat Panel |
| Recent | |
| -------- | |
| * Jan | User: Notitie medicatie |
| * Marie | Cortex: Ik maak een notitie... |
| * Piet | |
| | |
| Alle A-Z | Artifact Area |
| -------- | |
| Bakker | +- DagnotatieBlock ----------------+ |
| Berg, M | | Patient: Jan de Vries | |
| De Vrie. | | Categorie: Medicatie | |
| ... | +----------------------------------+ |
+----------+----------------------------------------+
Layout Wijziging:
- Huidig: Chat (40%) + Artifact (60%)
- Nieuw: Sidebar (15%) + Chat (35%) + Artifact (50%)
2.3 Preview-First Confirmation (P2)
Toon complete preview in chat, direct opslaan zonder artifact.
+-----------------------------------------------+
| Cortex: |
| |
| +- Notitie Preview -----------------------+ |
| | Jan de Vries (52) [wijzig] | |
| | Categorie: Medicatie [wijzig] | |
| | "Medicatie gegeven volgens schema" | |
| | | |
| | [Opslaan] [Uitgebreid] [Annuleer] | |
| +-----------------------------------------+ |
+-----------------------------------------------+
3. Implementatie Roadmap
Fase 1: Foundation (Week 1) - 10 SP
| Story | Beschrijving | SP |
|---|---|---|
| F1.S1 | Patient Sidebar layout wijziging (15/35/50 split) | 3 |
| F1.S2 | PatientSidebar component skeleton | 2 |
| F1.S3 | Patient search in sidebar (hergebruik API) | 2 |
| F1.S4 | Recent patients sectie | 2 |
| F1.S5 | Click-to-select activePatient | 1 |
Fase 2: @Mention Systeem (Week 2) - 13 SP
| Story | Beschrijving | SP |
|---|---|---|
| F2.S1 | @-detectie in CommandInput | 2 |
| F2.S2 | PatientMentionDropdown component | 3 |
| F2.S3 | Patient search API integratie (debounced) | 2 |
| F2.S4 | Mention chip rendering in input | 3 |
| F2.S5 | Mention data meesturen naar chat API | 2 |
| F2.S6 | AI prompt update voor mentions | 1 |
Fase 3: Smart Defaults (Week 3) - 10 SP
| Story | Beschrijving | SP |
|---|---|---|
| F3.S1 | DagnotatieBlock: auto-use activePatient | 2 |
| F3.S2 | Alle blocks: activePatient als default | 3 |
| F3.S3 | PendingIntent state in store | 2 |
| F3.S4 | Re-process na patient selectie | 3 |
Fase 4: Preview Cards (Week 4) - 12 SP
| Story | Beschrijving | SP |
|---|---|---|
| F4.S1 | PreviewCard component design | 3 |
| F4.S2 | Inline edit in preview card | 3 |
| F4.S3 | Direct save van preview card | 2 |
| F4.S4 | Uitgebreid - open artifact flow | 2 |
| F4.S5 | AI prompt update voor preview generation | 2 |
Totaal: 45 SP (~4 weken)
4. Technische Details
4.1 Store Uitbreiding
// stores/cortex-store.ts
interface CortexStore {
// Bestaand
activePatient: Patient | null;
// Nieuw
recentPatients: Patient[]; // Max 5
pendingIntent: PendingIntent | null; // Bewaar intent tijdens disambiguatie
patientSidebarOpen: boolean; // Collapse state
// Acties
addRecentPatient: (patient: Patient) => void;
setPendingIntent: (intent: PendingIntent | null) => void;
togglePatientSidebar: () => void;
}
interface PendingIntent {
originalMessage: string;
intent: CortexIntent;
entities: Partial<ExtractedEntities>;
awaitingPatientSelection: boolean;
}
4.2 API Wijzigingen
// app/api/cortex/chat/route.ts
const RequestSchema = z.object({
message: z.string(),
messages: z.array(ChatMessageSchema).optional(),
context: z.object({...}).optional(),
// Nieuw
mentions: z.array(z.object({
patientId: z.string().uuid(),
patientName: z.string(),
position: z.object({ start: z.number(), end: z.number() }),
})).optional(),
});
4.3 Component Structuur
components/cortex/
+-- patient-sidebar/
| +-- patient-sidebar.tsx
| +-- patient-list.tsx
| +-- patient-list-item.tsx
| +-- patient-search-input.tsx
| +-- recent-patients.tsx
+-- command-center/
+-- patient-mention-dropdown.tsx (nieuw)
+-- mention-chip.tsx (nieuw)
5. UI/UX Specificaties
5.1 Patient Sidebar
- Desktop (>1024px): 240px vast, collapsible naar 48px, Cmd+B toggle
- Tablet (768-1024px): Overlay mode, swipe gesture
- Mobile (<768px): Bottom sheet
5.2 @Mention Dropdown
- Trigger: @ karakter in input
- Minimale query: 1 karakter na @
- Debounce: 200ms
- Max resultaten: 5
- Keyboard: Up/Down, Enter, Escape
5.3 Mention Chip Styling
.mention-chip {
display: inline-flex;
padding: 2px 6px;
background: amber-100;
border: 1px solid amber-300;
border-radius: 4px;
}
6. Success Metrics
| Metric | Baseline | Target |
|---|---|---|
| Clicks voor patient selectie | 3-4 | 1-2 |
| Tijd tot notitie opgeslagen | ~15 sec | ~8 sec |
| "Welke patient?" prompts | ~40% | <10% |
7. Volgende Stappen
- Review met Colin - prioriteiten bevestigen
- Design mockups maken
- Bouwplan schrijven voor Fase 1 + 2
- Start implementatie Patient Sidebar
- Parallel: @mention dropdown prototype
Gerelateerde Documenten:
docs/archive/swift/bouwplan-swift-v3.mdstores/cortex-store.tscomponents/cortex/blocks/zoeken-block.tsx