'use client'; /** * Chat Panel (v3.0) * * Chat interface met scrollable message list, auto-scroll, en scroll-lock detection. * * Epic: E2 (Chat Panel & Messages) * Story: E2.S3 (ChatPanel component - scrolling) */ import { useRef, useEffect, useState, useCallback } from 'react'; import { ArrowDown } from 'lucide-react'; import { ChatMessage } from './chat-message'; import { useSwiftStore } from '@/stores/swift-store'; import { cn } from '@/lib/utils'; export function ChatPanel() { const chatMessages = useSwiftStore((s) => s.chatMessages); // Refs for scrolling const scrollContainerRef = useRef(null); const messagesEndRef = useRef(null); // Scroll-lock state const [isScrolledUp, setIsScrolledUp] = useState(false); const [showScrollButton, setShowScrollButton] = useState(false); // Demo messages for testing scrolling behavior (will be removed when chat input is implemented) const demoMessages = chatMessages.length === 0 ? [ { id: '1', type: 'system' as const, content: 'Welkom bij Swift Medical Scribe v3.0', timestamp: new Date(), }, { id: '2', type: 'user' as const, content: 'Hoi, ik wil een notitie maken', timestamp: new Date(), }, { id: '3', type: 'assistant' as const, content: 'Natuurlijk! Voor welke patiënt wil je een notitie maken?', timestamp: new Date(), }, { id: '4', type: 'user' as const, content: 'Notitie voor Jan: medicatie gegeven om 14:00', timestamp: new Date(), }, { id: '5', type: 'assistant' as const, content: 'Ik begrijp dat je een notitie wilt maken voor Jan over medicatie. Ik open een dagnotitie voor je waarin je dit kunt vastleggen.', timestamp: new Date(), }, { id: '6', type: 'user' as const, content: 'Zoek Marie van den Berg', timestamp: new Date(), }, { id: '7', type: 'assistant' as const, content: 'Ik zoek Marie van den Berg voor je op in het systeem.', timestamp: new Date(), }, { id: '8', type: 'user' as const, content: 'Maak overdracht voor deze dienst', timestamp: new Date(), }, { id: '9', type: 'assistant' as const, content: 'Ik maak een overdracht voor je. Welke dienst bedoel je precies? Nacht, ochtend, middag of avond?', timestamp: new Date(), }, { id: '10', type: 'user' as const, content: 'Avonddienst', timestamp: new Date(), }, { id: '11', type: 'assistant' as const, content: 'Prima! Ik open een overdracht voor de avonddienst. Je kunt hier alle relevante informatie voor de overdracht invullen.', timestamp: new Date(), }, { id: '12', type: 'system' as const, content: 'Dit is een lange conversatie om scrolling te testen', timestamp: new Date(), }, ] : chatMessages; const hasMessages = demoMessages.length > 0; // Scroll to bottom function const scrollToBottom = useCallback((behavior: ScrollBehavior = 'smooth') => { messagesEndRef.current?.scrollIntoView({ behavior }); setIsScrolledUp(false); setShowScrollButton(false); }, []); // Detect scroll position (scroll-lock detection) const handleScroll = useCallback(() => { if (!scrollContainerRef.current) return; const { scrollTop, scrollHeight, clientHeight } = scrollContainerRef.current; const isNearBottom = scrollHeight - scrollTop - clientHeight < 100; // 100px threshold setIsScrolledUp(!isNearBottom); // Show scroll button only if scrolled up AND there are messages setShowScrollButton(!isNearBottom && hasMessages); }, [hasMessages]); // Auto-scroll to latest message when new message arrives (unless user scrolled up) useEffect(() => { if (!isScrolledUp && hasMessages) { scrollToBottom('smooth'); } }, [demoMessages.length, isScrolledUp, hasMessages, scrollToBottom]); // Initial scroll to bottom on mount useEffect(() => { scrollToBottom('auto'); }, [scrollToBottom]); return (
{/* Chat messages area - scrollable */}
{hasMessages ? (
{demoMessages.map((message) => ( ))} {/* Invisible element to scroll to */}
) : (
💬

Welkom bij Swift Medical Scribe

Typ of spreek wat je wilt doen...

Voorbeelden:

• “Notitie voor Jan: medicatie gegeven”

• “Zoek Marie van den Berg”

• “Maak overdracht voor deze dienst”

)} {/* Scroll to bottom button */} {showScrollButton && ( )}
{/* Chat input - placeholder */}

E2.S3 in progress: Auto-scroll en scroll-lock werkend ✓

); }