'use client'; import { useEffect, useMemo, useState, type ReactNode } from 'react'; import { useTranslations } from 'next-intl'; import { MessageSquare } from 'lucide-react'; import { Badge } from '@/components/ui/shared/Badge'; import { Button } from '@/components/ui/shared/Button'; import { Checkbox } from '@/components/ui/shared/Checkbox'; import { CaseToothChartPanel } from '@/components/ui/lab/CaseToothChartPanel'; import { FORM_SELECT_CLASS } from '@/components/shared/formSelectStyles'; import { LabCaseAttachmentPreview } from '@/components/ui/lab/LabCaseAttachmentPreview'; import { LabCaseAttachmentsDialog } from '@/components/ui/lab/LabCaseAttachmentsDialog'; import { LabCaseShareQrDialog, LabCaseShareQrThumb, } from '@/components/ui/lab/LabCaseShareQrDialog'; import { labTaskStatusVariant } from '@/components/lab/labTaskStatusDisplay'; import { LabCaseDueDateBadge } from '@/components/lab/LabCaseDueDateBadge'; import { formatToothList, prosthesisTypeBadgeStyleFromCatalog, } from '@/components/treatment/prosthesisTypeDisplay'; import { prosthesisCatalogApi } from '@/lib/api/prosthesis-catalog'; import { buildCaseProsthesisRows, formatCaseDateTime, formatPatientName, latestCaseAttachment, } from '@/components/lab/caseDetailUtils'; import type { AssignableTaskStaff, LabCaseDetail, LabTaskStatus } from '@/types/cases'; import type { ProsthesisCatalogEntry } from '@/types/treatment-catalog'; function CaseTaskProgressBar({ completed, total }: { completed: number; total: number }) { const pct = total > 0 ? Math.round((completed / total) * 100) : 0; return (
{completed}/{total} {pct}%
); } export interface CaseDetailPanelProps { labCase: LabCaseDetail; locale: string; treatmentLabel: (type: string) => string; statusOptions: { value: LabTaskStatus; label: string }[]; loadAttachmentBlob: (caseId: string, attachmentId: string) => Promise; /** Extra lines below patient mobile (e.g. connection-specific clinic/lab line). */ headerMetaLines?: ReactNode; showCommentsButton?: boolean; commentCount?: number; onCommentsClick?: () => void; canEditImportant?: boolean; updatingImportant?: boolean; onImportantChange?: (checked: boolean) => void; commentsSection?: ReactNode; assignableStaff?: AssignableTaskStaff[]; canAssignTasks?: boolean; assigningTaskId?: string | null; onAssignTask?: (taskId: string, assigneeUserId: string | null) => void; } export function CaseDetailPanel({ labCase, locale, treatmentLabel, statusOptions, loadAttachmentBlob, headerMetaLines, showCommentsButton = false, commentCount = 0, onCommentsClick, canEditImportant = false, updatingImportant = false, onImportantChange, commentsSection, assignableStaff = [], canAssignTasks = false, assigningTaskId = null, onAssignTask, }: CaseDetailPanelProps) { const t = useTranslations('cases'); const [attachmentsDialogOpen, setAttachmentsDialogOpen] = useState(false); const [shareQrDialogOpen, setShareQrDialogOpen] = useState(false); const [prosthesisCatalog, setProsthesisCatalog] = useState([]); useEffect(() => { void prosthesisCatalogApi .list() .then((response) => setProsthesisCatalog(response.data)) .catch(() => {}); }, []); const prosthesisRows = useMemo(() => buildCaseProsthesisRows(labCase), [labCase]); const previewAttachment = useMemo(() => latestCaseAttachment(labCase), [labCase]); return (

{formatPatientName(labCase.patient)}

{!canEditImportant && labCase.isImportant ? ( {t('importantLabel')} ) : null}

{t('patientMobile')}: {labCase.patient.mobile}

{headerMetaLines}

{t('sentAt', { date: formatCaseDateTime(labCase.sentAt, locale) })}

{t('taskProgressLabel', { completed: labCase.taskProgress.completed, total: labCase.taskProgress.total, })}

{canEditImportant ? ( onImportantChange?.(checked)} /> ) : null} {showCommentsButton && onCommentsClick ? ( ) : null} {labCase.shareUrl || (previewAttachment && labCase.attachments.length > 0) ? (
{previewAttachment && labCase.attachments.length > 0 ? ( ) : null} {labCase.shareUrl ? ( setShareQrDialogOpen(true)} /> ) : null}
) : null}
{labCase.detail ? (

{t('treatmentDetails')}

{treatmentLabel(labCase.detail.treatmentType)}
{t('teethLabel')}: {labCase.detail.teeth.join(', ') || '—'}
{labCase.detail.comment ? (
{labCase.detail.comment}
) : null}
) : null}

{t('tasksByTooth')}

{labCase.tasksByTooth.length === 0 ? (

{t('noTasks')}

) : ( labCase.tasksByTooth.map((group) => (
{group.prosthesisTypeLabel} {t('toothGroupTitle', { teeth: formatToothList(group.teeth), prosthesis: group.prosthesisTypeLabel, })}
    {group.tasks.map((task) => (
  • {task.stepOrder}. {task.stepLabel} {task.lastStatusChangedBy ? t('lastUpdatedBy', { name: task.lastStatusChangedBy.name }) : t('lastUpdatedUnknown')} {task.lastStatusChangedAt ? ` · ${formatCaseDateTime(task.lastStatusChangedAt, locale)}` : ''} {canAssignTasks && onAssignTask ? ( ) : null} {statusOptions.find((opt) => opt.value === task.status)?.label ?? task.status}
  • ))}
)) )}
{commentsSection} setAttachmentsDialogOpen(false)} caseId={labCase.id} attachments={labCase.attachments} loadBlob={loadAttachmentBlob} /> {labCase.shareUrl ? ( setShareQrDialogOpen(false)} shareUrl={labCase.shareUrl} /> ) : null}
); } export { CaseTaskProgressBar };