improvement: treatment UX fully overhauled.
This commit is contained in:
@@ -4,9 +4,9 @@ import { useEffect, useState } from 'react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { Button } from '@/components/ui/shared/Button';
|
||||
import { Checkbox } from '@/components/ui/shared/Checkbox';
|
||||
import { Dropdown } from '@/components/ui/shared/Dropdown';
|
||||
import { isDetailReadyForLabDispatch } from '@/components/treatment/treatmentDetailRules';
|
||||
import { FORM_SELECT_CLASS } from '@/components/shared/formSelectStyles';
|
||||
import { SearchBar } from '@/components/ui/shared/SearchBar';
|
||||
import { LinkedOrganizationSearchCombobox } from '@/components/ui/treatment/LinkedOrganizationSearchCombobox';
|
||||
import { CaseSentLabel } from '@/components/ui/treatment/CaseSentLabel';
|
||||
import { LabCaseCommentsPanel } from '@/components/ui/lab/LabCaseCommentsPanel';
|
||||
import { treatmentTypeLabelFromCatalog } from '@/components/shared/treatmentTypeDisplay';
|
||||
@@ -30,6 +30,8 @@ interface LabCasesDispatchPanelProps {
|
||||
onOrganizationSearchChange: (value: string) => void;
|
||||
recentOrganizationIds: string[];
|
||||
onRecentOrganizationPick: (orgId: string) => void;
|
||||
canInviteLab?: boolean;
|
||||
onInviteLab?: () => void;
|
||||
sendBusyId: string | null;
|
||||
onAddLabCase: () => void;
|
||||
onSendLabCase: (labCase: LabCaseDraft, comment?: string) => void;
|
||||
@@ -89,6 +91,8 @@ export function LabCasesDispatchPanel({
|
||||
onOrganizationSearchChange,
|
||||
recentOrganizationIds,
|
||||
onRecentOrganizationPick,
|
||||
canInviteLab = false,
|
||||
onInviteLab,
|
||||
sendBusyId,
|
||||
onAddLabCase,
|
||||
onSendLabCase,
|
||||
@@ -100,18 +104,13 @@ export function LabCasesDispatchPanel({
|
||||
const [pendingComment, setPendingComment] = useState('');
|
||||
|
||||
const activeLinkedOrganizations = orgs.filter((o) => o.active);
|
||||
const filteredOrganizations = (() => {
|
||||
const q = organizationSearch.trim().toLowerCase();
|
||||
if (!q) return activeLinkedOrganizations;
|
||||
return activeLinkedOrganizations.filter((o) => o.name.toLowerCase().includes(q));
|
||||
})();
|
||||
const recentOrganizations = recentOrganizationIds
|
||||
.map((id) => activeLinkedOrganizations.find((o) => o.id === id))
|
||||
.filter(Boolean) as LinkedOrganizationOption[];
|
||||
|
||||
const activeDetail = details.find((d) => d.clientId === activeDetailId) ?? null;
|
||||
const isLabDependentDetail = Boolean(
|
||||
activeDetail && labDependentCodes.has(activeDetail.treatmentType),
|
||||
activeDetail && isDetailReadyForLabDispatch(activeDetail, labDependentCodes),
|
||||
);
|
||||
|
||||
const labCaseForActiveDetail =
|
||||
@@ -214,6 +213,14 @@ export function LabCasesDispatchPanel({
|
||||
updateActiveLabCase({ attachmentIds: [...set] });
|
||||
}
|
||||
|
||||
function handleSelectOrganization(org: LinkedOrganizationOption) {
|
||||
updateActiveLabCase({
|
||||
destinationOrganizationId: org.id,
|
||||
toothProsthesis: [],
|
||||
});
|
||||
setApplyAllProsthesis('');
|
||||
}
|
||||
|
||||
const activeDetailAttachments = activeDetail.attachmentMetas ?? [];
|
||||
|
||||
return (
|
||||
@@ -340,11 +347,16 @@ export function LabCasesDispatchPanel({
|
||||
|
||||
<div className="space-y-2">
|
||||
<p className="text-xs font-medium text-text-secondary">{t('selectLab')}</p>
|
||||
<SearchBar
|
||||
embedded
|
||||
value={organizationSearch}
|
||||
onChange={onOrganizationSearchChange}
|
||||
placeholder={t('searchOrgsPlaceholder')}
|
||||
<LinkedOrganizationSearchCombobox
|
||||
search={organizationSearch}
|
||||
onSearchChange={onOrganizationSearchChange}
|
||||
organizations={activeLinkedOrganizations}
|
||||
selectedOrganizationId={activeLabCase.destinationOrganizationId}
|
||||
onSelectOrganization={handleSelectOrganization}
|
||||
disabled={disabled}
|
||||
canInviteLab={canInviteLab}
|
||||
onInviteLab={onInviteLab}
|
||||
noPermissionMessage={t('noOrgInvitePermission')}
|
||||
/>
|
||||
{recentOrganizations.length > 0 && (
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
@@ -362,28 +374,6 @@ export function LabCasesDispatchPanel({
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<Dropdown
|
||||
value={activeLabCase.destinationOrganizationId ?? ''}
|
||||
onChange={(e) => {
|
||||
const nextOrgId = e.target.value || null;
|
||||
updateActiveLabCase({
|
||||
destinationOrganizationId: nextOrgId,
|
||||
toothProsthesis: [],
|
||||
});
|
||||
setApplyAllProsthesis('');
|
||||
}}
|
||||
disabled={disabled || filteredOrganizations.length === 0}
|
||||
>
|
||||
<option value="">{t('selectLabPlaceholder')}</option>
|
||||
{filteredOrganizations.map((o) => (
|
||||
<option key={o.id} value={o.id}>
|
||||
{o.name}
|
||||
</option>
|
||||
))}
|
||||
</Dropdown>
|
||||
{filteredOrganizations.length === 0 && (
|
||||
<p className="text-xs text-text-muted">{t('noOrgMatch')}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{prosthesisRows.length > 0 && activeLabCase.destinationOrganizationId ? (
|
||||
@@ -411,7 +401,7 @@ export function LabCasesDispatchPanel({
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<div className="overflow-x-auto">
|
||||
<div className="overflow-x-auto overscroll-x-contain">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="text-left text-xs text-text-muted">
|
||||
|
||||
Reference in New Issue
Block a user