'use client'; import { useEffect, useRef, type ReactNode, type RefObject } from 'react'; import { useTranslations } from 'next-intl'; import { Trash2 } from 'lucide-react'; import { Button } from '@/components/ui/shared/Button'; import { Dropdown } from '@/components/ui/shared/Dropdown'; import { formatDetailChipLabel } from '@/components/treatment/detailChipLabel'; import { autosaveStatusClass, labBlockedBannerClass } from '@/components/treatment/treatmentStatusStyles'; import { TreatmentDetailAttachmentsStrip } from '@/components/ui/treatment/TreatmentDetailAttachmentsStrip'; import type { TreatmentDetailDraft } from '@/types/treatment'; import type { TreatmentCatalogEntry } from '@/types/treatment-catalog'; import { treatmentTypeColor, treatmentTypeOptionStyle } from '@/components/shared/treatmentTypeDisplay'; import { isDetailTypeSelected, isLabDependentDetailMissingTeeth, } from '@/components/treatment/treatmentDetailRules'; interface TreatmentDetailsEditorProps { details: TreatmentDetailDraft[]; activeDetailId: string; onActiveDetailChange: (id: string) => void; onDetailsChange: (details: TreatmentDetailDraft[]) => void; isDetailLocked: (detail: TreatmentDetailDraft) => boolean; labDependentCodes: Set; treatmentCatalog: TreatmentCatalogEntry[]; disabled: boolean; canEdit: boolean; saveStatus: 'idle' | 'dirty' | 'saving' | 'saved' | 'error'; uploadBusy: boolean; onAddDetail: () => void; onRemoveDetail?: (detailClientId: string) => void; onUploadFiles: (files: File[], onProgress: (percent: number) => void) => Promise; onRemoveAttachment?: (attachmentId: string) => void; /** Detail chips + Add detail (default true). */ showChrome?: boolean; /** Type / notes / attachments fields (default true). */ showFields?: boolean; /** FDI chart (or other) rendered beside notes on wide screens. */ chart?: ReactNode; /** Shown below chrome (e.g. prosthesis wizard). */ stepper?: ReactNode; /** Shown below type + chart + notes (e.g. Continue to lab). */ footer?: ReactNode; /** Dim the chart until a treatment type is chosen. */ chartLocked?: boolean; chartLockMessage?: string; } export function TreatmentDetailsEditor({ details, activeDetailId, onActiveDetailChange, onDetailsChange, isDetailLocked, labDependentCodes, treatmentCatalog, disabled, canEdit, saveStatus, uploadBusy, onAddDetail, onRemoveDetail, onUploadFiles, onRemoveAttachment, showChrome = true, showFields = true, chart, stepper, footer, chartLocked = false, chartLockMessage, }: TreatmentDetailsEditorProps) { const t = useTranslations('treatment'); const tCommon = useTranslations('common'); const notesRef = useRef(null); const activeDetail = details.find((d) => d.clientId === activeDetailId) ?? details[0]; const locked = Boolean(activeDetail && isDetailLocked(activeDetail)); const readOnly = !activeDetail || disabled || locked; const showMissingTeethLabBlock = Boolean( activeDetail && isLabDependentDetailMissingTeeth(activeDetail, labDependentCodes), ); if (!showChrome && !showFields && !stepper) return null; const treatmentTypeTextColor = activeDetail && isDetailTypeSelected(activeDetail) ? treatmentTypeColor( activeDetail.treatmentType, treatmentCatalog.findIndex((e) => e.code === activeDetail.treatmentType), ) : undefined; function setActiveType(nextType: string) { onDetailsChange( details.map((d) => d.clientId === activeDetailId ? { ...d, treatmentType: nextType } : d, ), ); } return (
{showChrome ? ( <>

{t('detailsTitle')}

{details.map((d, idx) => { const detailLocked = isDetailLocked(d); const isActive = d.clientId === activeDetailId; const showRemoveAction = Boolean(onRemoveDetail); const removeDisabled = !canEdit || disabled || detailLocked || uploadBusy; const chipLabel = formatDetailChipLabel( d, treatmentCatalog, t('detailLabel', { n: idx + 1 }), ); const showLabStatus = isDetailTypeSelected(d) && labDependentCodes.has(d.treatmentType); return (
{showRemoveAction ? ( ) : null}
); })}
) : null} {stepper && activeDetail ?
{stepper}
: null} {showFields && activeDetail ? (
{showMissingTeethLabBlock && (

{t('labShipmentBlockedBody')}

)}
setActiveType(e.target.value)} disabled={readOnly} style={{ color: treatmentTypeTextColor }} > {treatmentCatalog.map((entry, index) => ( ))}
{chart ? (
{chartLocked ? (

{chartLockMessage}

) : null}
{chart}
) : null} { onDetailsChange( details.map((d) => (d.clientId === activeDetailId ? { ...d, comment: v } : d)), ); }} /> {canEdit && saveStatus !== 'idle' && (

{saveStatus === 'dirty' && t('unsavedChanges')} {saveStatus === 'saving' && t('saveStatusSaving')} {saveStatus === 'saved' && t('saveStatusSaved')} {saveStatus === 'error' && t('saveStatusError')}

)} {footer ?
{footer}
: null}
) : null}
); } function NotesField({ textareaRef, value, disabled, label, placeholder, onChange, }: { textareaRef: RefObject; value: string; disabled: boolean; label: string; placeholder: string; onChange: (value: string) => void; }) { useEffect(() => { const el = textareaRef.current; if (!el) return; el.style.height = '0px'; el.style.height = `${el.scrollHeight}px`; }, [textareaRef, value]); return (