feat(cortex): Epic 1 - Patient Sidebar (E1.S1-S4)

Collapsible overlay sidebar voor snelle patient selectie met search en recent patients.

E1.S1 - Store uitbreiding:
- recentPatients: Patient[] (max 5, nieuwste eerst, geen duplicaten)
- patientSidebarOpen: boolean
- addRecentPatient, togglePatientSidebar, setPatientSidebarOpen actions

E1.S2 - PatientSidebar component:
- Overlay sidebar (w-80, z-50) met backdrop
- Search input met debounce (200ms)
- Recent patients sectie
- Hergebruik usePatientSearch, usePatientSelection hooks
- Hergebruik PatientListItem component

E1.S3 - Toggle button + shortcut:
- Users icon button in ContextBar
- Cmd/Ctrl+P keyboard shortcut
- Escape sluit sidebar (prioriteit boven artifacts)

E1.S4 - Click-to-select flow:
- Selectie zet activePatient
- Voegt toe aan recentPatients
- Sluit sidebar automatisch

Bouwplan v1.3: Epic 1 compleet (10/23 SP - 43%)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
colinislit
2026-01-03 11:52:13 +01:00
parent 43d4d095ce
commit 9b0352de44
6 changed files with 301 additions and 19 deletions

View File

@@ -23,6 +23,7 @@ import { cn } from '@/lib/utils';
import { ContextBar } from './context-bar';
import { OfflineBanner } from './offline-banner';
import { NudgeToast } from './nudge-toast';
import { PatientSidebar } from '../patient-sidebar';
import { ChatPanel } from '../chat/chat-panel';
import { ArtifactArea } from '../artifacts/artifact-area';
import { getArtifactTitle } from '../artifacts/artifact-container';
@@ -40,16 +41,27 @@ export function CommandCenter() {
suggestions,
acceptSuggestion,
dismissSuggestion,
// Patient sidebar (E1)
togglePatientSidebar,
patientSidebarOpen,
setPatientSidebarOpen,
} = useCortexStore();
const inputRef = useRef<HTMLInputElement>(null);
// Global keyboard shortcuts
const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
// Escape: close all artifacts
if (e.key === 'Escape' && openArtifacts.length > 0) {
e.preventDefault();
closeAllArtifacts();
// Escape: close sidebar first, then artifacts
if (e.key === 'Escape') {
if (patientSidebarOpen) {
e.preventDefault();
setPatientSidebarOpen(false);
return;
}
if (openArtifacts.length > 0) {
e.preventDefault();
closeAllArtifacts();
}
}
// Cmd/Ctrl + K: focus input (chat input in v3.0)
@@ -57,8 +69,14 @@ export function CommandCenter() {
e.preventDefault();
inputRef.current?.focus();
}
// Cmd/Ctrl + P: toggle patient sidebar (E1.S3)
if ((e.metaKey || e.ctrlKey) && e.key === 'p') {
e.preventDefault();
togglePatientSidebar();
}
},
[openArtifacts, closeAllArtifacts]
[openArtifacts, closeAllArtifacts, patientSidebarOpen, setPatientSidebarOpen, togglePatientSidebar]
);
useEffect(() => {
@@ -114,6 +132,9 @@ export function CommandCenter() {
return (
<div className="flex flex-col h-screen overflow-hidden">
{/* Patient Sidebar (E1.S2) */}
<PatientSidebar />
{/* Offline Banner */}
<OfflineBanner />