'use client'; /** * NudgeChatMessage Component * * Displays a protocol-based nudge suggestion in the chat. * Shows protocol metadata, clinical rationale, and accept/dismiss buttons. * * Epic: E4 (Nudge) */ import { useEffect, useState, useCallback } from 'react'; import { Lightbulb, BookOpen, X } from 'lucide-react'; import { motion } from 'framer-motion'; import { Button } from '@/components/ui/button'; import { cn } from '@/lib/utils'; import type { NudgeSuggestion } from '@/lib/cortex/types'; import { useCortexStore } from '@/stores/cortex-store'; interface NudgeChatMessageProps { suggestion: NudgeSuggestion; onAccept: (suggestionId: string) => void; onDismiss: (suggestionId: string) => void; } /** * Priority-based styling for the nudge message */ const PRIORITY_STYLES = { low: { container: 'bg-slate-50 border-slate-200', badge: 'bg-slate-100 text-slate-700', text: 'text-slate-700', icon: 'text-slate-500', progress: 'bg-slate-300', }, medium: { container: 'bg-amber-50 border-amber-200', badge: 'bg-amber-100 text-amber-800', text: 'text-amber-900', icon: 'text-amber-600', progress: 'bg-amber-400', }, high: { container: 'bg-red-50 border-red-200', badge: 'bg-red-100 text-red-800', text: 'text-red-900', icon: 'text-red-600', progress: 'bg-red-400', }, }; /** * Get button text based on suggested intent */ function getAcceptButtonText(intent: string): string { switch (intent) { case 'create_appointment': return 'Ja, inplannen'; case 'dagnotitie': return 'Ja, notitie maken'; case 'cancel_appointment': return 'Ja, annuleren'; case 'register_no_show': return 'Ja, pas brief aan'; default: return 'Ja, uitvoeren'; } } export function NudgeChatMessage({ suggestion, onAccept, onDismiss, }: NudgeChatMessageProps) { const [progress, setProgress] = useState(100); const isNoShowProcessing = useCortexStore((s) => s.isNoShowProcessing); const styles = PRIORITY_STYLES[suggestion.priority]; const protocol = suggestion.suggestion.protocol; // Memoize dismiss handler const handleDismiss = useCallback(() => { onDismiss(suggestion.id); }, [onDismiss, suggestion.id]); // Countdown effect useEffect(() => { if (!suggestion.expiresAt) return; const expiresAt = new Date(suggestion.expiresAt).getTime(); const createdAt = new Date(suggestion.createdAt).getTime(); const total = expiresAt - createdAt; const interval = setInterval(() => { const now = Date.now(); const remaining = expiresAt - now; if (remaining <= 0) { handleDismiss(); clearInterval(interval); return; } setProgress((remaining / total) * 100); }, 1000); return () => clearInterval(interval); }, [suggestion.expiresAt, suggestion.createdAt, handleDismiss]); return ( {/* Header with icon and dismiss */}
Protocol Suggestie
{/* Protocol badge */} {protocol && (
{protocol.name} {protocol.reference && ( {protocol.reference} )}
)} {/* Suggestion message */}

{suggestion.suggestion.message}

{/* Clinical rationale */} {protocol?.rationale && (

{protocol.rationale}

)} {/* Action buttons */}
{/* Countdown progress bar */}
); }