From 73894ac879aa8a9d20011ae4921fbe48f08468fd Mon Sep 17 00:00:00 2001 From: colinislit Date: Sat, 3 Jan 2026 12:11:14 +0100 Subject: [PATCH] feat(cortex): Epic 2 - @Mention Systeem (E2.S1-S3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inline patient selectie via @naam in de chat input. YAGNI Versimpeling: 8→4 SP, 5→3 stories - Geen selectedMentions array (activePatient is al beschikbaar) - Geen API payload wijziging nodig - Geen meerdere mentions tracking E2.S1 - @-detectie: - Detecteer laatste @ in input - Track query en startIndex - Actief als geen space na @ en minimaal 1 char E2.S2 - PatientMentionDropdown: - Hergebruik usePatientSearch (debounce 150ms, limit 5) - Hergebruik PatientListItem (size="sm") - Positioned above input (bottom-full) - Escape sluit dropdown E2.S3 - Selectie flow: - Vervang @query met @naam in input - Zet activePatient via usePatientSelection - Sluit dropdown automatisch Bouwplan v1.4: Epic 2 compleet (14/19 SP - 74%) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../cortex/command-center/command-input.tsx | 64 ++++++++++++- .../patient-mention-dropdown.tsx | 90 +++++++++++++++++++ .../bouwplan-patient-selectie-v1.md | 24 ++--- 3 files changed, 164 insertions(+), 14 deletions(-) create mode 100644 components/cortex/command-center/patient-mention-dropdown.tsx diff --git a/components/cortex/command-center/command-input.tsx b/components/cortex/command-center/command-input.tsx index eca2962..5691bed 100644 --- a/components/cortex/command-center/command-input.tsx +++ b/components/cortex/command-center/command-input.tsx @@ -22,6 +22,9 @@ import { Mic, MicOff, Send, Loader2 } from 'lucide-react'; import { useToast } from '@/hooks/use-toast'; import { safeFetch, getErrorInfo } from '@/lib/cortex/error-handler'; import { routeIntentToArtifact } from '@/lib/cortex/action-parser'; +import { usePatientSelection } from '@/lib/cortex/hooks/use-patient-selection'; +import type { PatientSearchResult } from '@/lib/cortex/hooks/use-patient-search'; +import { PatientMentionDropdown } from './patient-mention-dropdown'; export const CommandInput = forwardRef(function CommandInput(_, ref) { const { @@ -52,8 +55,56 @@ export const CommandInput = forwardRef(function CommandInput(_ const waveformRef = useRef(null); const animationRef = useRef(null); + // @mention state (E2.S1) + const [mentionState, setMentionState] = useState<{ + query: string; + startIndex: number; + } | null>(null); + + // Patient selection hook (E2.S3) + const { selectPatient } = usePatientSelection({ + showSuccessToast: false, // Don't show toast for @mention selection + }); + const hasValue = inputValue.trim().length > 0; + // @mention detection (E2.S1) + const detectMention = (value: string) => { + const lastAtIndex = value.lastIndexOf('@'); + if (lastAtIndex !== -1) { + const afterAt = value.slice(lastAtIndex + 1); + // Active if: no space after @, and at least 1 char + if (!afterAt.includes(' ') && afterAt.length > 0) { + setMentionState({ query: afterAt, startIndex: lastAtIndex }); + return; + } + } + setMentionState(null); + }; + + // Handle input change with @mention detection + const handleInputChange = (value: string) => { + setInputValue(value); + detectMention(value); + }; + + // Handle @mention selection (E2.S3) + const handleMentionSelect = (patient: PatientSearchResult) => { + if (!mentionState) return; + + // 1. Replace @query with @name in input + const before = inputValue.slice(0, mentionState.startIndex); + const after = inputValue.slice(mentionState.startIndex + mentionState.query.length + 1); + const newValue = `${before}@${patient.name} ${after}`.trim(); + setInputValue(newValue); + + // 2. Set activePatient via selection hook + selectPatient(patient); + + // 3. Close dropdown + setMentionState(null); + }; + // Waveform visualization useEffect(() => { if (!analyserNode || !waveformRef.current || !isRecording) { @@ -216,8 +267,17 @@ export const CommandInput = forwardRef(function CommandInput(_ return (