'use client'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useTranslations } from 'next-intl'; import { formatApiErrorMessage } from '@/components/shared/formatApiError'; import { canEditCases } from '@/components/shared/permissions'; import { useAuth } from '@/lib/hooks/useAuth'; import { useToast } from '@/lib/hooks/useToast'; import { organizationApi } from '@/lib/api/organization'; import { treatmentCatalogApi } from '@/lib/api/treatment-catalog'; import { treatmentTypeLabelFromCatalog } from '@/components/ui/treatment/treatmentTypeDisplay'; import { Button } from '@/components/ui/shared/Button'; import { SearchBar } from '@/components/ui/shared/SearchBar'; import { ToastStack } from '@/components/ui/shared/Toast'; import { CaseDetailPanel, CaseTaskProgressBar } from '@/components/ui/lab/CaseDetailPanel'; import { LabCaseCommentsPanel } from '@/components/ui/lab/LabCaseCommentsPanel'; import { formatCaseDateTime, formatPatientName, } from '@/components/ui/lab/caseDetailUtils'; import { treatmentsApi } from '@/lib/api/treatments'; import { casesApi } from '@/lib/api/cases'; import type { CounterpartItemDto } from '@/lib/api/organization'; import type { LabCaseDetail, LabCaseListItem, LabTaskStatus } from '@/types/cases'; import type { TreatmentCatalogEntry } from '@/types/treatment-catalog'; const PAGE_SIZE = 20; interface ConnectionCaseHistoryContentProps { connection: CounterpartItemDto; onBack: () => void; } export function ConnectionCaseHistoryContent({ connection, onBack, }: ConnectionCaseHistoryContentProps) { const t = useTranslations('organizations'); const tCases = useTranslations('cases'); const tCommon = useTranslations('common'); const { currentOrganization, user } = useAuth(); const { showError, setError, messages: toastMessages } = useToast(); const [search, setSearch] = useState(''); const [page, setPage] = useState(1); const [cases, setCases] = useState([]); const [pagination, setPagination] = useState({ page: 1, limit: PAGE_SIZE, total: 0, totalPages: 1, }); const [selectedCaseId, setSelectedCaseId] = useState(null); const [selectedCase, setSelectedCase] = useState(null); const [treatmentCatalog, setTreatmentCatalog] = useState([]); const [loadingList, setLoadingList] = useState(false); const [loadingDetail, setLoadingDetail] = useState(false); const [updatingImportant, setUpdatingImportant] = useState(false); const [commentCount, setCommentCount] = useState(0); const locale = user?.language ?? 'en'; const isClinic = currentOrganization?.type === 'CLINIC'; const canEditImportant = !isClinic && canEditCases(currentOrganization); const tRef = useRef(t); tRef.current = t; const treatmentLabel = useCallback( (type: string) => treatmentTypeLabelFromCatalog(type, treatmentCatalog), [treatmentCatalog], ); useEffect(() => { void treatmentCatalogApi.list().then((r) => setTreatmentCatalog(r.data)).catch(() => {}); }, []); const statusOptions: { value: LabTaskStatus; label: string }[] = useMemo( () => [ { value: 'IN_PROGRESS', label: tCases('statusInProgress') }, { value: 'COMPLETED', label: tCases('statusCompleted') }, ], [tCases], ); useEffect(() => { let cancelled = false; const timeout = setTimeout(() => { void (async () => { setLoadingList(true); setError(''); try { const response = await organizationApi.listConnectionCases(connection.id, { q: search.trim() || undefined, page, limit: PAGE_SIZE, }); if (cancelled) return; setCases(response.data.items); setPagination(response.data.pagination); } catch (error: unknown) { if (cancelled) return; showError(formatApiErrorMessage(error, tRef.current('caseHistoryErrorLoadList'))); } finally { if (!cancelled) setLoadingList(false); } })(); }, search ? 300 : 0); return () => { cancelled = true; clearTimeout(timeout); }; }, [search, page, connection.id, showError, setError]); useEffect(() => { if (!selectedCaseId) { setSelectedCase(null); setCommentCount(0); return; } let cancelled = false; void organizationApi .listConnectionCaseComments(connection.id, selectedCaseId) .then((r) => { if (!cancelled) setCommentCount(r.data.length); }) .catch(() => { if (!cancelled) setCommentCount(0); }); void (async () => { setLoadingDetail(true); setError(''); try { const response = await organizationApi.getConnectionCase(connection.id, selectedCaseId); if (cancelled) return; setSelectedCase(response.data); } catch (error: unknown) { if (cancelled) return; showError(formatApiErrorMessage(error, tRef.current('caseHistoryErrorLoadDetail'))); setSelectedCase(null); } finally { if (!cancelled) setLoadingDetail(false); } })(); return () => { cancelled = true; }; }, [selectedCaseId, connection.id, showError, setError]); function scrollToComments() { document.getElementById('case-comments')?.scrollIntoView({ behavior: 'smooth' }); } const loadClinicAttachmentBlob = useCallback( (_caseId: string, attachmentId: string) => treatmentsApi.getAttachmentFileBlob(attachmentId), [], ); async function handleCaseImportantToggle(isImportant: boolean) { if (!selectedCaseId || !canEditImportant || !selectedCase) return; const previousCase = selectedCase; setSelectedCase({ ...selectedCase, isImportant }); setUpdatingImportant(true); setError(''); try { const response = await casesApi.setCaseImportant(selectedCaseId, isImportant); setSelectedCase(response.data); } catch (error: unknown) { setSelectedCase(previousCase); showError(formatApiErrorMessage(error, tCases('errorUpdateTask'))); } finally { setUpdatingImportant(false); } } return (

{t('caseHistoryTitle', { name: connection.organizationName })}

{isClinic ? t('caseHistorySubtitleClinic') : t('caseHistorySubtitleLab')}

{ setSearch(value); setPage(1); }} placeholder={tCases('searchPlaceholder')} />
{loadingList ? (

{tCommon('loading')}

) : cases.length === 0 ? (

{t('caseHistoryEmpty')}

) : (
    {cases.map((item) => { const isActive = item.id === selectedCaseId; return (
  • ); })}
)}
{pagination.totalPages > 1 ? (
{tCases('pageSummary', { page: pagination.page, totalPages: pagination.totalPages, total: pagination.total, })}
) : null}
{!selectedCaseId ? (

{tCases('selectCaseHint')}

) : loadingDetail || !selectedCase ? (

{tCommon('loading')}

) : ( void handleCaseImportantToggle(checked)} headerMetaLines={ !isClinic ? (

{tCases('fromClinic', { name: selectedCase.clinic.name })}

) : (

{t('caseHistorySentToLab', { name: connection.organizationName })}

) } commentsSection={ isClinic && selectedCaseId ? (
{ const r = await organizationApi.listConnectionCaseComments( connection.id, selectedCaseId, ); setCommentCount(r.data.length); return r.data; }} onPost={async (body) => { const r = await organizationApi.addConnectionCaseComment( connection.id, selectedCaseId, body, ); setCommentCount((n) => n + 1); return r.data; }} onError={showError} />
) : null } /> )}
); }