import { useState, useEffect, useRef, useCallback, Component } from 'react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import './index.css'; // ── Error Boundary ──────────────────────────────────────────── class ErrorBoundary extends Component { constructor(props) { super(props); this.state = { hasError: false, error: null }; } static getDerivedStateFromError(error) { return { hasError: true, error }; } componentDidCatch(error, info) { console.error('[BaoThang-AI ErrorBoundary]', error, info); } render() { if (this.state.hasError) { return (

Đã xảy ra lỗi không mong muốn

Vui lòng tải lại trang để tiếp tục.

); } return this.props.children; } } // ── Utility Helpers ─────────────────────────────────────────── function formatTimeAgo(timestamp) { const now = new Date(); const past = new Date(timestamp); const diffMs = now - past; const diffMins = Math.floor(diffMs / 60000); const diffHours = Math.floor(diffMs / 3600000); const diffDays = Math.floor(diffMs / 86400000); if (diffMins < 1) return 'Vừa xong'; if (diffMins < 60) return `${diffMins} phút trước`; if (diffHours < 24) return `${diffHours} giờ trước`; if (diffDays < 7) return `${diffDays} ngày trước`; return past.toLocaleDateString(); } function buildDownloadText(chatHistory) { let content = 'BaoThang-AI — TTYT Khu vực Bảo Thắng\n' + '='.repeat(50) + '\n\n'; chatHistory.forEach((msg) => { content += `[${msg.timestamp}] ${msg.type === 'user' ? 'Bác sĩ' : 'BaoThang-AI'}:\n${msg.content}\n`; if (msg.source) content += `Nguồn: ${msg.source}\n`; content += '\n'; }); return content; } // ── Sidebar Component ───────────────────────────────────────── function Sidebar({ sidebarOpen, sessions, currentSessionId, onNewChat, onLoadSession, onDeleteSession, onToggleTheme, theme }) { return ( ); } // ── Chat Area Component ─────────────────────────────────────── function ChatArea({ messages, isTyping, showWelcome, chatAreaRef }) { return (
{/* Welcome Screen */} {showWelcome && (

BaoThang-AI Pro

Trợ lý y khoa thông minh hỗ trợ tra cứu phác đồ, thuốc và các hướng dẫn lâm sàng.

)} {/* Messages */} {messages.map((msg, idx) => (
{/* Avatar */}
{msg.type === 'user' ? 'Bác sĩ' : 'BaoThang-AI'} {msg.timestamp}
{msg.type === 'user' ? (
{msg.content}
) : (
{msg.content}
)}
{msg.type === 'assistant' && (
{msg.source ? ( {msg.source} ) : }
)}
))} {/* Typing Indicator */} {isTyping && (
BaoThang-AI
Đang phân tích
)}
); } // ── Input Area Component ────────────────────────────────────── function InputArea({ inputValue, setInputValue, onSend, isTyping, inputRef }) { const handleKeyDown = (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); onSend(); } }; const handleInput = (e) => { setInputValue(e.target.value); e.target.style.height = 'auto'; e.target.style.height = Math.min(e.target.scrollHeight, 120) + 'px'; }; const canSend = inputValue.trim() && !isTyping; return (
{ e.currentTarget.style.boxShadow = `0 0 0 2px color-mix(in srgb, var(--color-primary) 40%, transparent)`; e.currentTarget.style.borderColor = 'color-mix(in srgb, var(--color-primary) 50%, transparent)'; }} onBlurCapture={e => { e.currentTarget.style.boxShadow = 'var(--shadow-glass-sm)'; e.currentTarget.style.borderColor = 'var(--color-border-color)'; }}>