improvement: patient search moved to the top of treatment feature.

This commit is contained in:
2026-08-22 20:11:43 +03:30
parent 50725b7b3f
commit b1405b22b1
10 changed files with 124 additions and 30 deletions

View File

@@ -206,6 +206,7 @@ function mapAppointment(record: AppointmentRecord): TreatmentAppointment {
patientId: record.patientId,
patientFirstName: record.patient.firstName,
patientLastName: record.patient.lastName,
patientMobile: record.patient.mobile,
providerUserId: record.providerUserId,
startAt: record.startAt,
endAt: record.endAt,
@@ -386,10 +387,12 @@ export function TreatmentWorkspace({
const [unreadLabCasesLoading, setUnreadLabCasesLoading] = useState(false);
const [labCasesScope, setLabCasesScope] = useState<TreatmentLabCasesScope>('patient');
const [selectedRailLabCaseId, setSelectedRailLabCaseId] = useState<string | null>(null);
const [searchedPatient, setSearchedPatient] = useState<Pick<
Patient,
'id' | 'firstName' | 'lastName'
> | null>(null);
const [searchedPatient, setSearchedPatient] = useState<
(Pick<Patient, 'id' | 'firstName' | 'lastName'> & {
mobile?: string | null;
email?: string | null;
}) | null
>(null);
const [patientSearchBusy, setPatientSearchBusy] = useState(false);
const [newTreatmentPickerOpen, setNewTreatmentPickerOpen] = useState(false);
const [creatingStandalone, setCreatingStandalone] = useState(false);
@@ -502,6 +505,8 @@ export function TreatmentWorkspace({
id: selectedAppointment.patientId,
firstName: selectedAppointment.patientFirstName,
lastName: selectedAppointment.patientLastName,
mobile: selectedAppointment.patientMobile ?? null,
email: null,
purpose: selectedAppointment.purpose,
isWalkIn: false,
};
@@ -512,6 +517,8 @@ export function TreatmentWorkspace({
id: selectedStandalone.patientId,
firstName: isWalkIn ? walkInLabel : (selectedStandalone.patient?.firstName ?? ''),
lastName: isWalkIn ? '' : (selectedStandalone.patient?.lastName ?? ''),
mobile: isWalkIn ? null : (selectedStandalone.patient?.mobile ?? null),
email: isWalkIn ? null : (selectedStandalone.patient?.email ?? null),
purpose: selectedStandalone.details[0]?.treatmentType,
isWalkIn,
};
@@ -521,7 +528,9 @@ export function TreatmentWorkspace({
id: searchedPatient.id,
firstName: searchedPatient.firstName,
lastName: searchedPatient.lastName,
purpose: undefined as string | undefined,
mobile: searchedPatient.mobile ?? null,
email: searchedPatient.email ?? null,
purpose: undefined,
isWalkIn: false,
};
}
@@ -532,6 +541,15 @@ export function TreatmentWorkspace({
const activePatientName = activePatient
? `${activePatient.firstName} ${activePatient.lastName}`.trim()
: null;
const namedActivePatient =
activePatient && !activePatient.isWalkIn && activePatient.id
? {
id: activePatient.id,
displayName: activePatientName ?? '',
mobile: activePatient.mobile ?? null,
email: activePatient.email ?? null,
}
: null;
const unreadUpdatesCount = unreadLabCases.length;
const otherPatientsUnreadCount = useMemo(
@@ -1557,6 +1575,8 @@ export function TreatmentWorkspace({
id: patient.id,
firstName: patient.firstName,
lastName: patient.lastName,
mobile: patient.mobile,
email: patient.email,
});
try {
const response = await treatmentsApi.listPatientHistory(patient.id, 1);
@@ -2146,11 +2166,24 @@ export function TreatmentWorkspace({
return (
<div className="space-y-4">
<header className="space-y-1">
<h1 className="text-xl sm:text-2xl font-semibold text-text-primary">{t('title')}</h1>
{!canEdit ? (
<p className="text-sm text-text-secondary">{t('subtitleReadOnly')}</p>
) : null}
<header className="flex flex-col gap-3 sm:flex-row sm:items-center sm:gap-4">
<div className="min-w-0 shrink-0">
<h1 className="text-xl sm:text-2xl font-semibold text-text-primary">{t('title')}</h1>
{!canEdit ? (
<p className="text-sm text-text-secondary mt-1">{t('subtitleReadOnly')}</p>
) : null}
</div>
<div className="min-w-0 flex-1">
<PatientSearchCombobox
search={patientSearch}
onSearchChange={setPatientSearch}
patients={patientSearchResults}
loading={patientSearchLoading || patientSearchBusy}
onSelectPatient={handleSelectSearchedPatient}
placeholder={tPatients('searchPlaceholder')}
emptyResultsMessage={tPatients('noResults')}
/>
</div>
</header>
<AppointmentsStrip
@@ -2181,15 +2214,6 @@ export function TreatmentWorkspace({
<div className="treatment-layout-grid grid grid-cols-1 xl:grid-cols-[minmax(300px,380px)_minmax(0,1fr)] gap-4 items-start">
<div className="space-y-3 min-w-0 xl:max-w-[380px]">
<div className="surface-card p-3 space-y-3">
<PatientSearchCombobox
search={patientSearch}
onSearchChange={setPatientSearch}
patients={patientSearchResults}
loading={patientSearchLoading || patientSearchBusy}
onSelectPatient={handleSelectSearchedPatient}
placeholder={tPatients('searchPlaceholder')}
emptyResultsMessage={tPatients('noResults')}
/>
{canEdit && !isViewingPastDay ? (
<div className="space-y-2">
<Button
@@ -2204,10 +2228,16 @@ export function TreatmentWorkspace({
{newTreatmentPickerOpen ? (
<NewTreatmentPatientPicker
creating={creatingStandalone}
currentPatient={namedActivePatient}
onSelectWalkIn={() => createStandaloneTreatment({ walkIn: true })}
onSelectPatient={(patient) =>
createStandaloneTreatment({ patientId: patient.id })
}
onSelectCurrentPatient={
namedActivePatient
? () => createStandaloneTreatment({ patientId: namedActivePatient.id })
: undefined
}
onCancel={() => setNewTreatmentPickerOpen(false)}
/>
) : null}
@@ -2215,8 +2245,14 @@ export function TreatmentWorkspace({
) : null}
{activePatient ? (
<div className="space-y-0.5 border-t border-border/60 pt-3">
<p className="text-[10px] uppercase tracking-wide text-text-muted">{t('selectedPatient')}</p>
<div
className={`space-y-0.5 ${
canEdit && !isViewingPastDay ? 'border-t border-border/60 pt-3' : ''
}`}
>
<p className="text-[10px] uppercase tracking-wide text-text-muted">
{t('selectedPatient')}
</p>
<p className="text-base font-semibold text-text-primary">{activePatientName}</p>
{activePatient.purpose ? (
<p className="text-[11px] text-text-secondary">
@@ -2228,7 +2264,11 @@ export function TreatmentWorkspace({
) : null}
</div>
) : (
<p className="text-sm text-text-muted border-t border-border/60 pt-3">
<p
className={`text-sm text-text-muted ${
canEdit && !isViewingPastDay ? 'border-t border-border/60 pt-3' : ''
}`}
>
{apptsLoading ? t('loadingAppointments') : t('selectDayWithAppointment')}
</p>
)}