Files
triqura-ecd/components/cortex/blocks/zoeken-block.tsx
colinislit b095b1e492 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>
2026-02-03 23:21:18 +01:00

128 lines
3.7 KiB
TypeScript

'use client';
/**
* Zoeken Block
*
* Block voor het zoeken naar patienten.
* Refactored to use extracted hooks and components (E0 - DRY).
*
* Epic: E3.S4 (Original), E0 (Refactor)
*/
import { useEffect, useRef } from 'react';
import { useCortexStore } from '@/stores/cortex-store';
import { BlockContainer } from './block-container';
import type { BlockPrefillData } from '@/stores/cortex-store';
import { BLOCK_CONFIGS } from '@/lib/cortex/types';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Search, User } from 'lucide-react';
// Use extracted hooks and components (DRY)
import { usePatientSearch, usePatientSelection } from '@/lib/cortex/hooks';
import {
PatientListItem,
PatientListEmpty,
PatientListLoading,
BlockEmpty,
} from '@/components/cortex/shared';
interface ZoekenBlockProps {
prefill?: BlockPrefillData;
}
export function ZoekenBlock({ prefill }: ZoekenBlockProps) {
const config = BLOCK_CONFIGS.zoeken;
const { closeBlock, openArtifact } = useCortexStore();
const dropdownRef = useRef<HTMLDivElement>(null);
// Get prefill query from various sources
const prefillQuery = prefill?.patientName || prefill?.query || '';
// Use extracted hooks
const { query, setQuery, results, isSearching, searchPatients } = usePatientSearch({
initialQuery: prefillQuery,
limit: 10,
});
const { selectPatient, selectedId } = usePatientSelection({
onSuccess: (dbPatient, patientName) => {
// Close block and open patient dashboard
closeBlock();
openArtifact({
type: 'patient-dashboard',
title: `Dashboard - ${patientName}`,
prefill: {
patientId: dbPatient.id,
patientName: patientName,
},
});
},
});
// Auto-search on prefill
useEffect(() => {
if (prefillQuery && prefillQuery.length >= 2) {
searchPatients(prefillQuery);
}
}, [prefillQuery, searchPatients]);
const showResults = query.length >= 2;
return (
<BlockContainer title={config.title} size={config.size}>
<div className="space-y-4">
{/* Search Input */}
<div className="space-y-2">
<Label htmlFor="patient-search">Zoek patient</Label>
<div className="relative" ref={dropdownRef}>
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-slate-400" />
<Input
id="patient-search"
type="text"
placeholder="Typ naam, BSN of clientnummer..."
value={query}
onChange={(e) => setQuery(e.target.value)}
className="pl-9"
autoFocus
/>
</div>
</div>
{/* Search Results */}
{showResults && (
<div className="space-y-2">
{isSearching ? (
<PatientListLoading />
) : results.length > 0 ? (
<div className="space-y-1 max-h-96 overflow-y-auto">
{results.map((patient) => (
<PatientListItem
key={patient.id}
patient={patient}
isLoading={selectedId === patient.id}
onClick={() => selectPatient(patient)}
/>
))}
</div>
) : (
<PatientListEmpty
message="Geen patienten gevonden"
submessage="Probeer een andere zoekterm"
/>
)}
</div>
)}
{/* Empty State - waiting for input */}
{!showResults && (
<BlockEmpty
icon={User}
message="Typ minimaal 2 karakters om te zoeken"
/>
)}
</div>
</BlockContainer>
);
}