feat(cortex): add Intake Blocks MVP for voice/text commands

Adds 4 new intents for intake workflow:
- intake_status: shows completion percentage and section checklist
- intake_navigeer: navigation to specific intake tabs
- risico_query: displays risk assessments with severity indicators
- diagnose_query: shows primary/secondary diagnoses

New components:
- IntakeStatusBlock, RisicoBlock, DiagnoseBlock
- Shared block components (BlockLoading, BlockError, BlockEmpty, BlockSection, BlockItem, BlockFooter)
- useBlockData and useIntakeContext hooks

New API routes:
- GET /api/cortex/intake/status
- GET /api/cortex/intake/risico
- GET /api/cortex/intake/diagnose

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
colinislit
2026-02-03 23:21:18 +01:00
parent 05836c5c6a
commit b095b1e492
22 changed files with 2415 additions and 15 deletions

View File

@@ -8,7 +8,10 @@
*/
import { useCortexStore, type CortexIntent } from '@/stores/cortex-store';
import { FileText, Search, ArrowRightLeft, HelpCircle, Clock, Calendar, Plus, X } from 'lucide-react';
import {
FileText, Search, ArrowRightLeft, HelpCircle, Clock, Calendar, Plus, X,
ClipboardList, AlertTriangle, Stethoscope, Navigation,
} from 'lucide-react';
const INTENT_CONFIG: Record<CortexIntent, { icon: typeof FileText; color: string; label: string }> = {
dagnotitie: { icon: FileText, color: 'text-blue-600 bg-blue-50 border border-blue-200', label: 'Notitie' },
@@ -18,6 +21,11 @@ const INTENT_CONFIG: Record<CortexIntent, { icon: typeof FileText; color: string
create_appointment: { icon: Plus, color: 'text-green-600 bg-green-50 border border-green-200', label: 'Afspraak' },
cancel_appointment: { icon: X, color: 'text-red-600 bg-red-50 border border-red-200', label: 'Annuleren' },
reschedule_appointment: { icon: Clock, color: 'text-amber-600 bg-amber-50 border border-amber-200', label: 'Verzetten' },
// Intake intents (MVP)
intake_status: { icon: ClipboardList, color: 'text-cyan-600 bg-cyan-50 border border-cyan-200', label: 'Status' },
intake_navigeer: { icon: Navigation, color: 'text-indigo-600 bg-indigo-50 border border-indigo-200', label: 'Navigeer' },
risico_query: { icon: AlertTriangle, color: 'text-orange-600 bg-orange-50 border border-orange-200', label: 'Risico' },
diagnose_query: { icon: Stethoscope, color: 'text-rose-600 bg-rose-50 border border-rose-200', label: 'Diagnose' },
unknown: { icon: HelpCircle, color: 'text-slate-600 bg-slate-50 border border-slate-200', label: 'Actie' },
};
@@ -34,18 +42,27 @@ function formatRelativeTime(date: Date): string {
}
export function RecentStrip() {
const { recentActions, setInputValue, openBlock } = useCortexStore();
const { recentActions, setInputValue, openBlock, activePatient } = useCortexStore();
const handleActionClick = (action: typeof recentActions[0]) => {
// Set the input to repeat the action
setInputValue(action.label);
// If it's a known intent, open the block directly
if (action.intent !== 'unknown') {
openBlock(action.intent, {
patientName: action.patientName,
});
// Skip 'unknown' intent
if (action.intent === 'unknown') return;
// intake_navigeer is navigation-only (no block)
if (action.intent === 'intake_navigeer') {
// For navigation, we need patient context
// TODO: Implement navigation when patient + intake context is available
console.log('[RecentStrip] intake_navigeer - navigation not yet implemented');
return;
}
// Open the block for other intents
openBlock(action.intent, {
patientName: action.patientName,
});
};
return (