'use client'; import { Check, FolderOpen, MessageSquare } from 'lucide-react'; import { useTranslations } from 'next-intl'; import { Badge } from '@/components/ui/shared/Badge'; import { Button } from '@/components/ui/shared/Button'; import { LAB_TASK_STATUS_SELECT_CLASS } from '@/components/shared/formSelectStyles'; import { LabCaseCommentsPanel } from '@/components/ui/lab/LabCaseCommentsPanel'; import { canEditLabTaskStatus, labTaskStatusSelectStyle, labTaskStatusVariant, } from '@/components/lab/labTaskStatusDisplay'; import { LabCaseDueDateBadge } from '@/components/lab/LabCaseDueDateBadge'; import { formatToothList, prosthesisTypeBadgeStyleFromCatalog, } from '@/components/treatment/prosthesisTypeDisplay'; import { tasksApi } from '@/lib/api/tasks'; import type { LabTaskListItem, LabTaskStatus } from '@/types/cases'; import type { ProsthesisCatalogEntry } from '@/types/treatment-catalog'; interface TaskRowProps { task: LabTaskListItem; locale: string; flatMode: boolean; highlighted?: boolean; exiting?: boolean; canEdit: boolean; currentUserId?: string; statusOptions: { value: LabTaskStatus; label: string }[]; updatingTaskId: string | null; commentsOpen: boolean; prosthesisCatalog: readonly ProsthesisCatalogEntry[]; onStatusUpdate: (taskId: string, status: LabTaskStatus) => void; onToggleComments: (taskId: string) => void; onCommentError: (message: string) => void; onShowInCase?: (task: LabTaskListItem) => void; } function formatPatientName(patient: { firstName: string; lastName: string }) { return `${patient.firstName} ${patient.lastName}`.trim(); } export function TaskRow({ task, locale, flatMode, highlighted = false, exiting = false, canEdit, currentUserId, statusOptions, updatingTaskId, commentsOpen, prosthesisCatalog, onStatusUpdate, onToggleComments, onCommentError, onShowInCase, }: TaskRowProps) { const t = useTranslations('tasks'); const canEditStatus = canEditLabTaskStatus(task, currentUserId, canEdit); const assignedToOther = Boolean(task.assignee) && task.assignee!.id !== currentUserId; const taskDate = new Intl.DateTimeFormat(locale, { year: 'numeric', month: 'short', day: 'numeric', }).format(new Date(task.createdAt)); const rowClassName = [ flatMode ? undefined : 'border-b border-border/40 last:border-b-0', exiting ? 'task-row-complete-exit' : undefined, !exiting && highlighted ? 'relative bg-primary/10 ring-2 ring-inset ring-primary/50 shadow-[0_0_16px_rgba(99,102,241,0.2)]' : undefined, ] .filter(Boolean) .join(' '); const commentsButton = canEdit && !exiting ? ( ) : null; const statusControl = canEditStatus && !exiting ? ( ) : assignedToOther && !exiting ? ( {t('assignedToStaff', { name: task.assignee!.name })} ) : ( {statusOptions.find((opt) => opt.value === task.status)?.label ?? task.status} ); return (
  • {task.stepOrder}. {task.stepLabel}

    {exiting ? ( {t('taskCompletedFlash')} ) : null} {flatMode && task.isImportant && !exiting ? ( {t('importantBadge')} ) : null} {flatMode && task.caseDueDate && !exiting ? ( ) : null}
    {flatMode ? (

    {t('fromClinic', { name: task.clinic.name })} · {formatPatientName(task.patient)}{' '} · {t('teethLabel', { teeth: formatToothList(task.teeth) })}

    ) : null}

    {t('taskDate', { date: taskDate })} {task.lastStatusChangedBy ? ( <> · {t('lastUpdatedBy', { name: task.lastStatusChangedBy.name })} ) : null}

    {statusControl}
    {commentsButton}
    {flatMode ? (
    {onShowInCase && !exiting ? ( ) : null} {task.prosthesisTypeLabel}
    ) : null}
    {commentsOpen && canEdit && !exiting ? (
    { const r = await tasksApi.listComments(task.labCaseId); return r.data; }} onPost={async (body, visibleToClinic) => { const r = await tasksApi.addComment(task.labCaseId, { body, visibleToClinic, }); return r.data; }} onToggleVisibility={async (commentId, visible) => { const r = await tasksApi.setCommentVisibility(commentId, visible); return r.data; }} onError={onCommentError} />
    ) : null}
  • ); }