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:
@@ -12,6 +12,9 @@ import type { BlockType, BlockPrefillData } from '@/stores/cortex-store';
|
||||
import { DagnotatieBlock } from '../blocks/dagnotitie-block';
|
||||
import { ZoekenBlock } from '../blocks/zoeken-block';
|
||||
import { OverdrachtBlock } from '../blocks/overdracht-block';
|
||||
import { IntakeStatusBlock } from '../blocks/intake-status-block';
|
||||
import { RisicoBlock } from '../blocks/risico-block';
|
||||
import { DiagnoseBlock } from '../blocks/diagnose-block';
|
||||
import { PatientContextCard } from '../blocks/patient-context-card';
|
||||
import { FallbackPicker } from '../blocks/fallback-picker';
|
||||
|
||||
@@ -26,6 +29,13 @@ export function CanvasArea() {
|
||||
return <ZoekenBlock prefill={prefill} />;
|
||||
case 'overdracht':
|
||||
return <OverdrachtBlock prefill={prefill} />;
|
||||
// Intake blocks (MVP)
|
||||
case 'intake_status':
|
||||
return <IntakeStatusBlock prefill={prefill} />;
|
||||
case 'risico_query':
|
||||
return <RisicoBlock prefill={prefill} />;
|
||||
case 'diagnose_query':
|
||||
return <DiagnoseBlock prefill={prefill} />;
|
||||
case 'fallback':
|
||||
return <FallbackPicker originalInput={prefill.content} />;
|
||||
default:
|
||||
|
||||
@@ -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 (
|
||||
|
||||
Reference in New Issue
Block a user