@kenyaemr/esm-patient-clinical-view-app 5.4.2-pre.2674 → 5.4.2-pre.2676
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +5 -5
- package/dist/127.js +1 -1
- package/dist/{177.js → 195.js} +1 -1
- package/dist/195.js.map +1 -0
- package/dist/295.js +1 -1
- package/dist/295.js.map +1 -1
- package/dist/40.js +1 -1
- package/dist/916.js +1 -1
- package/dist/kenyaemr-esm-patient-clinical-view-app.js +3 -3
- package/dist/kenyaemr-esm-patient-clinical-view-app.js.buildmanifest.json +19 -19
- package/dist/main.js +3 -3
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/config-schema.ts +2 -0
- package/src/in-patient/admission-request.component.tsx +117 -0
- package/src/in-patient/admission-request.test.tsx +450 -0
- package/src/in-patient/in-patient.component.tsx +3 -68
- package/src/in-patient/in-patient.resource.tsx +32 -2
- package/src/types/index.ts +28 -1
- package/translations/am.json +6 -4
- package/translations/en.json +6 -4
- package/translations/sw.json +6 -4
- package/dist/177.js.map +0 -1
package/dist/routes.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemr":"^19.0.0"},"pages":[],"extensions":[{"name":"hiv-care-and-treatment-dashboard-link","component":"hivCareAndTreatmentLink","slot":"patient-chart-dashboard-slot","meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-hiv-care-and-treatment-dashboard-slot","path":"hiv-care-and-treatment-dashboard","layoutMode":"anchored"}},{"name":"hiv-care-and-treatment-dashboard","slot":"patient-chart-hiv-care-and-treatment-dashboard-slot","component":"hivCareAndTreatment","order":0,"online":true,"offline":false},{"name":"relationship-dashboard-link","component":"relationshipsLink","order":24,"online":true,"offline":false,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-relationship-slot","path":"relationships","layoutMode":"anchored"}},{"name":"relationship-dashboard","slot":"patient-chart-relationship-slot","component":"relationships","order":0,"online":true,"offline":false},{"name":"clinical-encounter-dashboard-link","component":"clinicalEncounterLink","order":25,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-clinical-encounter-slot","path":"clinical-encounter","layoutMode":"anchored"}},{"name":"clinical-encounter-dashboard","slot":"patient-chart-clinical-encounter-slot","component":"clinicalEncounter","order":0,"online":true,"offline":false},{"name":"maternal-and-child-health-dashboard-link","component":"maternalAndChildHealthDashboardLink","order":26,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-maternal-and-child-health-slot","path":"maternal-and-child-health","layoutMode":"anchored"}},{"name":"maternal-and-child-health-dashboard","slot":"patient-chart-maternal-and-child-health-slot","component":"maternalAndChildHealthDashboard","order":0,"online":true,"offline":false},{"name":"maternal-and-child-health-partograph","slot":"maternal-and-child-health-partograph-slot","component":"partograph","order":0,"online":true,"offline":false},{"name":"contact-list-dashboard-link","component":"contactListLink","order":27,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-contact-list-slot","path":"contact-list","layoutMode":"anchored"}},{"name":"contact-list-dashboard","slot":"patient-chart-contact-list-slot","component":"contactList","order":0,"online":true,"offline":false},{"component":"caseManagementDashboardLink","name":"case-management-dashboard-link","meta":{"name":"case-management","title":"Case Management","slot":"case-management-dashboard-slot","path":"/case-management"}},{"name":"in-patient-dashboard-link","component":"inPatientChartLink","order":7,"meta":{"slot":"patient-chart-in-patient-dashboard-slot","path":"in-patient","layoutMode":"anchored","columns":1,"columnSpan":1}},{"name":"in-patient-dashboard","slot":"patient-chart-in-patient-dashboard-slot","component":"inPatientChartDashboard","meta":{"fullWidth":false}},{"name":"wrap-component-view","slot":"case-management-dashboard-slot","component":"wrapComponent","order":2,"online":true,"offline":false},{"name":"case-encounter-link","component":"caseEncounterDashboardLink","order":14,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-case-encounter-slot","path":"case-management-encounters","layoutMode":"anchored"}},{"name":"case-encounter-table","slot":"patient-chart-case-encounter-slot","component":"caseEncounterTable","order":0,"online":true,"offline":false},{"component":"peerCalendarDashboardLink","name":"peer-calendar-dashboard-link","meta":{"name":"peer-calendar","title":"Peer Calendar","slot":"peer-calendar-dashboard-slot","path":"peer-management"}},{"name":"peer-calendar","slot":"peer-calendar-dashboard-slot","component":"peerCalendar","order":0,"online":true,"offline":false},{"name":"special-clinics-dashboard-link","component":"specialClinicsDashboardLink","order":15,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-special-clinics-slot","path":"special-clinics","layoutMode":"anchored"}},{"name":"special-clinics-dashboard","slot":"patient-chart-special-clinics-slot","component":"specialClinicsDashboard","order":0,"online":true,"offline":false}],"modals":[{"name":"birth-date-calculator","component":"birthDateCalculator"},{"name":"relationship-delete-confirm-dialog","component":"relationshipDeleteConfirmialog"},{"name":"end-relationship-dialog","component":"endRelationshipModal"}],"workspaces":[{"name":"contact-list-form","component":"contactListForm","title":"Contact List Form","type":"form"},{"name":"case-management-form","component":"caseManagementForm","title":"Case Management Form","type":"form"},{"name":"add-patient-case-form","component":"addPatientCaseForm","title":"Add patient case Form","type":"form"},{"name":"family-relationship-form","component":"familyRelationshipForm","title":"Family Relationship Form","type":"form"},{"name":"peers-form","component":"peersForm","title":"Add New Peer","type":"form"},{"name":"kenyaemr-cusom-form-entry-workspace","component":"peerCalendarFormEntry","title":"KVP Peer Educator Outreach Calendar","type":"form","width":"extra-wide","canMaximize":true,"canHide":true},{"name":"contact-list-update-form","component":"contactListUpdateForm","title":"Contact List Update Form","type":"form"},{"name":"other-relationship-form","component":"otherRelationshipsForm","title":"Other Relationships Form","type":"form"},{"name":"end-relationship-form","component":"endRelationshipWorkspace","title":"Discontinue relationship form","type":"form"}],"version":"5.4.2-pre.
|
|
1
|
+
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemr":"^19.0.0"},"pages":[],"extensions":[{"name":"hiv-care-and-treatment-dashboard-link","component":"hivCareAndTreatmentLink","slot":"patient-chart-dashboard-slot","meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-hiv-care-and-treatment-dashboard-slot","path":"hiv-care-and-treatment-dashboard","layoutMode":"anchored"}},{"name":"hiv-care-and-treatment-dashboard","slot":"patient-chart-hiv-care-and-treatment-dashboard-slot","component":"hivCareAndTreatment","order":0,"online":true,"offline":false},{"name":"relationship-dashboard-link","component":"relationshipsLink","order":24,"online":true,"offline":false,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-relationship-slot","path":"relationships","layoutMode":"anchored"}},{"name":"relationship-dashboard","slot":"patient-chart-relationship-slot","component":"relationships","order":0,"online":true,"offline":false},{"name":"clinical-encounter-dashboard-link","component":"clinicalEncounterLink","order":25,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-clinical-encounter-slot","path":"clinical-encounter","layoutMode":"anchored"}},{"name":"clinical-encounter-dashboard","slot":"patient-chart-clinical-encounter-slot","component":"clinicalEncounter","order":0,"online":true,"offline":false},{"name":"maternal-and-child-health-dashboard-link","component":"maternalAndChildHealthDashboardLink","order":26,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-maternal-and-child-health-slot","path":"maternal-and-child-health","layoutMode":"anchored"}},{"name":"maternal-and-child-health-dashboard","slot":"patient-chart-maternal-and-child-health-slot","component":"maternalAndChildHealthDashboard","order":0,"online":true,"offline":false},{"name":"maternal-and-child-health-partograph","slot":"maternal-and-child-health-partograph-slot","component":"partograph","order":0,"online":true,"offline":false},{"name":"contact-list-dashboard-link","component":"contactListLink","order":27,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-contact-list-slot","path":"contact-list","layoutMode":"anchored"}},{"name":"contact-list-dashboard","slot":"patient-chart-contact-list-slot","component":"contactList","order":0,"online":true,"offline":false},{"component":"caseManagementDashboardLink","name":"case-management-dashboard-link","meta":{"name":"case-management","title":"Case Management","slot":"case-management-dashboard-slot","path":"/case-management"}},{"name":"in-patient-dashboard-link","component":"inPatientChartLink","order":7,"meta":{"slot":"patient-chart-in-patient-dashboard-slot","path":"in-patient","layoutMode":"anchored","columns":1,"columnSpan":1}},{"name":"in-patient-dashboard","slot":"patient-chart-in-patient-dashboard-slot","component":"inPatientChartDashboard","meta":{"fullWidth":false}},{"name":"wrap-component-view","slot":"case-management-dashboard-slot","component":"wrapComponent","order":2,"online":true,"offline":false},{"name":"case-encounter-link","component":"caseEncounterDashboardLink","order":14,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-case-encounter-slot","path":"case-management-encounters","layoutMode":"anchored"}},{"name":"case-encounter-table","slot":"patient-chart-case-encounter-slot","component":"caseEncounterTable","order":0,"online":true,"offline":false},{"component":"peerCalendarDashboardLink","name":"peer-calendar-dashboard-link","meta":{"name":"peer-calendar","title":"Peer Calendar","slot":"peer-calendar-dashboard-slot","path":"peer-management"}},{"name":"peer-calendar","slot":"peer-calendar-dashboard-slot","component":"peerCalendar","order":0,"online":true,"offline":false},{"name":"special-clinics-dashboard-link","component":"specialClinicsDashboardLink","order":15,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-special-clinics-slot","path":"special-clinics","layoutMode":"anchored"}},{"name":"special-clinics-dashboard","slot":"patient-chart-special-clinics-slot","component":"specialClinicsDashboard","order":0,"online":true,"offline":false}],"modals":[{"name":"birth-date-calculator","component":"birthDateCalculator"},{"name":"relationship-delete-confirm-dialog","component":"relationshipDeleteConfirmialog"},{"name":"end-relationship-dialog","component":"endRelationshipModal"}],"workspaces":[{"name":"contact-list-form","component":"contactListForm","title":"Contact List Form","type":"form"},{"name":"case-management-form","component":"caseManagementForm","title":"Case Management Form","type":"form"},{"name":"add-patient-case-form","component":"addPatientCaseForm","title":"Add patient case Form","type":"form"},{"name":"family-relationship-form","component":"familyRelationshipForm","title":"Family Relationship Form","type":"form"},{"name":"peers-form","component":"peersForm","title":"Add New Peer","type":"form"},{"name":"kenyaemr-cusom-form-entry-workspace","component":"peerCalendarFormEntry","title":"KVP Peer Educator Outreach Calendar","type":"form","width":"extra-wide","canMaximize":true,"canHide":true},{"name":"contact-list-update-form","component":"contactListUpdateForm","title":"Contact List Update Form","type":"form"},{"name":"other-relationship-form","component":"otherRelationshipsForm","title":"Other Relationships Form","type":"form"},{"name":"end-relationship-form","component":"endRelationshipWorkspace","title":"Discontinue relationship form","type":"form"}],"version":"5.4.2-pre.2676"}
|
package/package.json
CHANGED
package/src/config-schema.ts
CHANGED
|
@@ -52,6 +52,7 @@ export const configSchema = {
|
|
|
52
52
|
peerCalendarOutreactForm: '7492cffe-5874-4144-a1e6-c9e455472a35',
|
|
53
53
|
autopsyFormUuid: '2b61a73-4971-4fc0-b20b-9a30176317e2',
|
|
54
54
|
htsClientTracingFormUuid: '15ed03d2-c972-11e9-a32f-2a2ae2dbcce4',
|
|
55
|
+
admissionRequestFormUuid: '0bae7646-b079-4cbb-8130-b24274fc16f7',
|
|
55
56
|
},
|
|
56
57
|
},
|
|
57
58
|
htsClientTracingConceptsUuids: {
|
|
@@ -447,6 +448,7 @@ export interface ConfigObject {
|
|
|
447
448
|
peerCalendarOutreactForm: string;
|
|
448
449
|
autopsyFormUuid: string;
|
|
449
450
|
htsClientTracingFormUuid: string;
|
|
451
|
+
admissionRequestFormUuid: string;
|
|
450
452
|
};
|
|
451
453
|
defaulterTracingEncounterUuid: string;
|
|
452
454
|
autopsyEncounterFormUuid: string;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import {
|
|
4
|
+
Button,
|
|
5
|
+
DataTable,
|
|
6
|
+
DataTableSkeleton,
|
|
7
|
+
Table,
|
|
8
|
+
TableBody,
|
|
9
|
+
TableCell,
|
|
10
|
+
TableHead,
|
|
11
|
+
TableHeader,
|
|
12
|
+
TableRow,
|
|
13
|
+
} from '@carbon/react';
|
|
14
|
+
import { formatDatetime, isDesktop, launchWorkspace, useConfig, useLayoutType } from '@openmrs/esm-framework';
|
|
15
|
+
import { CardHeader, EmptyState, ErrorState } from '@openmrs/esm-patient-common-lib';
|
|
16
|
+
|
|
17
|
+
import { useAdmissionRequest } from './in-patient.resource';
|
|
18
|
+
import { ConfigObject } from '../config-schema';
|
|
19
|
+
import { Add } from '@carbon/react/icons';
|
|
20
|
+
|
|
21
|
+
type AdmissionRequestProps = {
|
|
22
|
+
patientUuid: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const AdmissionRequest: React.FC<AdmissionRequestProps> = ({ patientUuid }) => {
|
|
26
|
+
const { t } = useTranslation();
|
|
27
|
+
const layout = useLayoutType();
|
|
28
|
+
const controlSize = isDesktop(layout) ? 'sm' : 'md';
|
|
29
|
+
const {
|
|
30
|
+
formsList: { admissionRequestFormUuid },
|
|
31
|
+
} = useConfig<ConfigObject>();
|
|
32
|
+
const { admissionRequest, isLoading, error, mutate } = useAdmissionRequest(patientUuid);
|
|
33
|
+
|
|
34
|
+
const rows = useMemo(() => {
|
|
35
|
+
return admissionRequest.map((admissionRequest) => ({
|
|
36
|
+
id: admissionRequest.patient.uuid,
|
|
37
|
+
admissionLocation: admissionRequest.dispositionLocation?.display,
|
|
38
|
+
admissionType: admissionRequest.dispositionType,
|
|
39
|
+
disposition: admissionRequest.disposition.display,
|
|
40
|
+
requestDatetime: formatDatetime(new Date(admissionRequest.dispositionEncounter.encounterDatetime), {
|
|
41
|
+
mode: 'standard',
|
|
42
|
+
}),
|
|
43
|
+
}));
|
|
44
|
+
}, [admissionRequest]);
|
|
45
|
+
|
|
46
|
+
const headers = useMemo(() => {
|
|
47
|
+
return [
|
|
48
|
+
{ key: 'requestDatetime', header: t('requestDatetime', 'Request Datetime') },
|
|
49
|
+
{ key: 'admissionLocation', header: t('admissionLocation', 'Admission Location') },
|
|
50
|
+
{ key: 'admissionType', header: t('admissionType', 'Admission Type') },
|
|
51
|
+
{ key: 'disposition', header: t('disposition', 'Disposition') },
|
|
52
|
+
];
|
|
53
|
+
}, []);
|
|
54
|
+
|
|
55
|
+
const handleLaunchAdmissionRequestForm = () => {
|
|
56
|
+
launchWorkspace('patient-form-entry-workspace', {
|
|
57
|
+
workspaceTitle: 'Admission Request',
|
|
58
|
+
mutateForm: mutate,
|
|
59
|
+
formInfo: {
|
|
60
|
+
formUuid: admissionRequestFormUuid,
|
|
61
|
+
encounterUuid: '',
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
if (isLoading) {
|
|
67
|
+
return <DataTableSkeleton />;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (error) {
|
|
71
|
+
return <ErrorState error={error} headerTitle={t('admissionRequest', 'Admission Request')} />;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (admissionRequest.length === 0) {
|
|
75
|
+
return (
|
|
76
|
+
<EmptyState
|
|
77
|
+
displayText={t('admissionRequests', 'admission requests')}
|
|
78
|
+
headerTitle={t('admissionRequest', 'Admission Request')}
|
|
79
|
+
launchForm={handleLaunchAdmissionRequestForm}
|
|
80
|
+
/>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<div>
|
|
86
|
+
<CardHeader title={t('admissionRequest', 'Admission Request')}>
|
|
87
|
+
<Button renderIcon={Add} onClick={handleLaunchAdmissionRequestForm} kind="ghost">
|
|
88
|
+
{t('add', 'Add')}
|
|
89
|
+
</Button>
|
|
90
|
+
</CardHeader>
|
|
91
|
+
<DataTable size={controlSize} rows={rows} headers={headers}>
|
|
92
|
+
{({ rows, headers, getTableProps, getHeaderProps, getRowProps, getCellProps }) => (
|
|
93
|
+
<Table {...getTableProps()}>
|
|
94
|
+
<TableHead>
|
|
95
|
+
<TableRow>
|
|
96
|
+
{headers.map((header) => (
|
|
97
|
+
<TableHeader {...getHeaderProps({ header })}>{header.header}</TableHeader>
|
|
98
|
+
))}
|
|
99
|
+
</TableRow>
|
|
100
|
+
</TableHead>
|
|
101
|
+
<TableBody>
|
|
102
|
+
{rows.map((row) => (
|
|
103
|
+
<TableRow {...getRowProps({ row })}>
|
|
104
|
+
{row.cells.map((cell) => (
|
|
105
|
+
<TableCell {...getCellProps({ cell })}>{cell.value}</TableCell>
|
|
106
|
+
))}
|
|
107
|
+
</TableRow>
|
|
108
|
+
))}
|
|
109
|
+
</TableBody>
|
|
110
|
+
</Table>
|
|
111
|
+
)}
|
|
112
|
+
</DataTable>
|
|
113
|
+
</div>
|
|
114
|
+
);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export default AdmissionRequest;
|
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import { launchWorkspace, formatDatetime, useLayoutType, isDesktop } from '@openmrs/esm-framework';
|
|
5
|
+
|
|
6
|
+
import AdmissionRequest from './admission-request.component';
|
|
7
|
+
import { useAdmissionRequest } from './in-patient.resource';
|
|
8
|
+
import { type AdmissionRequest as AdmissionRequestType } from '../types';
|
|
9
|
+
|
|
10
|
+
const mockUseAdmissionRequest = useAdmissionRequest as jest.MockedFunction<typeof useAdmissionRequest>;
|
|
11
|
+
const mockLaunchWorkspace = launchWorkspace as jest.MockedFunction<typeof launchWorkspace>;
|
|
12
|
+
const mockFormatDatetime = formatDatetime as jest.MockedFunction<typeof formatDatetime>;
|
|
13
|
+
const mockUseLayoutType = useLayoutType as jest.MockedFunction<typeof useLayoutType>;
|
|
14
|
+
const mockIsDesktop = isDesktop as jest.MockedFunction<typeof isDesktop>;
|
|
15
|
+
|
|
16
|
+
jest.mock('./in-patient.resource', () => ({
|
|
17
|
+
useAdmissionRequest: jest.fn(),
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
jest.mock('@openmrs/esm-framework', () => ({
|
|
21
|
+
...jest.requireActual('@openmrs/esm-framework'),
|
|
22
|
+
useConfig: jest.fn().mockReturnValue({
|
|
23
|
+
formsList: {
|
|
24
|
+
admissionRequestFormUuid: 'test-admission-form-uuid',
|
|
25
|
+
},
|
|
26
|
+
}),
|
|
27
|
+
formatDatetime: jest.fn().mockReturnValue('2023-10-16 10:30 AM'),
|
|
28
|
+
useLayoutType: jest.fn().mockReturnValue('desktop'),
|
|
29
|
+
isDesktop: jest.fn().mockReturnValue(true),
|
|
30
|
+
launchWorkspace: jest.fn(),
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
const mockMutate = jest.fn();
|
|
34
|
+
const patientUuid = 'test-patient-uuid';
|
|
35
|
+
|
|
36
|
+
const mockAdmissionRequestData: AdmissionRequestType[] = [
|
|
37
|
+
{
|
|
38
|
+
patient: {
|
|
39
|
+
uuid: 'test-patient-uuid',
|
|
40
|
+
person: {
|
|
41
|
+
uuid: 'test-person-uuid',
|
|
42
|
+
age: 35,
|
|
43
|
+
dead: false,
|
|
44
|
+
display: 'John Doe',
|
|
45
|
+
causeOfDeath: '',
|
|
46
|
+
gender: 'M',
|
|
47
|
+
deathDate: '',
|
|
48
|
+
attributes: [],
|
|
49
|
+
},
|
|
50
|
+
identifiers: [{ uuid: 'test-identifier-uuid' }],
|
|
51
|
+
},
|
|
52
|
+
dispositionLocation: {
|
|
53
|
+
uuid: 'test-location-uuid',
|
|
54
|
+
display: 'Ward A',
|
|
55
|
+
},
|
|
56
|
+
dispositionType: 'ADMIT',
|
|
57
|
+
disposition: {
|
|
58
|
+
uuid: 'test-disposition-uuid',
|
|
59
|
+
display: 'Admit to hospital',
|
|
60
|
+
answers: [],
|
|
61
|
+
},
|
|
62
|
+
dispositionEncounter: {
|
|
63
|
+
uuid: 'test-encounter-uuid',
|
|
64
|
+
encounterDatetime: '2023-10-16T10:30:00.000+0000',
|
|
65
|
+
patient: { uuid: 'test-patient-uuid' },
|
|
66
|
+
location: { uuid: 'test-location-uuid' },
|
|
67
|
+
form: {
|
|
68
|
+
name: 'Admission Form',
|
|
69
|
+
uuid: 'test-form-uuid',
|
|
70
|
+
version: '1.0',
|
|
71
|
+
published: true,
|
|
72
|
+
retired: false,
|
|
73
|
+
resources: [],
|
|
74
|
+
encounterType: {
|
|
75
|
+
uuid: 'test-encounter-type-uuid',
|
|
76
|
+
name: 'Admission',
|
|
77
|
+
viewPrivilege: null,
|
|
78
|
+
editPrivilege: null,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
encounterType: { uuid: 'test-encounter-type-uuid', name: 'Admission', display: 'Admission' },
|
|
82
|
+
obs: [],
|
|
83
|
+
orders: [],
|
|
84
|
+
voided: false,
|
|
85
|
+
auditInfo: {
|
|
86
|
+
creator: { uuid: 'test-creator-uuid', display: 'Admin' },
|
|
87
|
+
dateCreated: '2023-10-16T10:30:00.000+0000',
|
|
88
|
+
changedBy: null,
|
|
89
|
+
dateChanged: null,
|
|
90
|
+
},
|
|
91
|
+
visit: {
|
|
92
|
+
uuid: 'test-visit-uuid',
|
|
93
|
+
startDatetime: '2023-10-16T10:00:00.000+0000',
|
|
94
|
+
encounters: [],
|
|
95
|
+
},
|
|
96
|
+
encounterProviders: [],
|
|
97
|
+
diagnoses: [],
|
|
98
|
+
resourceVersion: '1.9',
|
|
99
|
+
},
|
|
100
|
+
dispositionObsGroup: {
|
|
101
|
+
uuid: 'test-obs-group-uuid',
|
|
102
|
+
concept: { uuid: 'test-concept-uuid' },
|
|
103
|
+
value: null,
|
|
104
|
+
obsDatetime: '2023-10-16T10:30:00.000+0000',
|
|
105
|
+
},
|
|
106
|
+
visit: {
|
|
107
|
+
uuid: 'test-visit-uuid',
|
|
108
|
+
startDatetime: '2023-10-16T10:00:00.000+0000',
|
|
109
|
+
encounters: [],
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
patient: {
|
|
114
|
+
uuid: 'test-patient-uuid-2',
|
|
115
|
+
person: {
|
|
116
|
+
uuid: 'test-person-uuid-2',
|
|
117
|
+
age: 42,
|
|
118
|
+
dead: false,
|
|
119
|
+
display: 'Jane Smith',
|
|
120
|
+
causeOfDeath: '',
|
|
121
|
+
gender: 'F',
|
|
122
|
+
deathDate: '',
|
|
123
|
+
attributes: [],
|
|
124
|
+
},
|
|
125
|
+
identifiers: [{ uuid: 'test-identifier-uuid-2' }],
|
|
126
|
+
},
|
|
127
|
+
dispositionLocation: {
|
|
128
|
+
uuid: 'test-location-uuid-2',
|
|
129
|
+
display: 'Ward B',
|
|
130
|
+
},
|
|
131
|
+
dispositionType: 'ADMIT',
|
|
132
|
+
disposition: {
|
|
133
|
+
uuid: 'test-disposition-uuid-2',
|
|
134
|
+
display: 'Admit to ICU',
|
|
135
|
+
answers: [],
|
|
136
|
+
},
|
|
137
|
+
dispositionEncounter: {
|
|
138
|
+
uuid: 'test-encounter-uuid-2',
|
|
139
|
+
encounterDatetime: '2023-10-15T14:30:00.000+0000',
|
|
140
|
+
patient: { uuid: 'test-patient-uuid-2' },
|
|
141
|
+
location: { uuid: 'test-location-uuid-2' },
|
|
142
|
+
form: {
|
|
143
|
+
name: 'Admission Form',
|
|
144
|
+
uuid: 'test-form-uuid',
|
|
145
|
+
version: '1.0',
|
|
146
|
+
published: true,
|
|
147
|
+
retired: false,
|
|
148
|
+
resources: [],
|
|
149
|
+
encounterType: {
|
|
150
|
+
uuid: 'test-encounter-type-uuid',
|
|
151
|
+
name: 'Admission',
|
|
152
|
+
viewPrivilege: null,
|
|
153
|
+
editPrivilege: null,
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
encounterType: { uuid: 'test-encounter-type-uuid', name: 'Admission', display: 'Admission' },
|
|
157
|
+
obs: [],
|
|
158
|
+
orders: [],
|
|
159
|
+
voided: false,
|
|
160
|
+
auditInfo: {
|
|
161
|
+
creator: { uuid: 'test-creator-uuid', display: 'Admin' },
|
|
162
|
+
dateCreated: '2023-10-15T14:30:00.000+0000',
|
|
163
|
+
changedBy: null,
|
|
164
|
+
dateChanged: null,
|
|
165
|
+
},
|
|
166
|
+
visit: {
|
|
167
|
+
uuid: 'test-visit-uuid-2',
|
|
168
|
+
startDatetime: '2023-10-15T14:00:00.000+0000',
|
|
169
|
+
encounters: [],
|
|
170
|
+
},
|
|
171
|
+
encounterProviders: [],
|
|
172
|
+
diagnoses: [],
|
|
173
|
+
resourceVersion: '1.9',
|
|
174
|
+
},
|
|
175
|
+
dispositionObsGroup: {
|
|
176
|
+
uuid: 'test-obs-group-uuid-2',
|
|
177
|
+
concept: { uuid: 'test-concept-uuid' },
|
|
178
|
+
value: null,
|
|
179
|
+
obsDatetime: '2023-10-15T14:30:00.000+0000',
|
|
180
|
+
},
|
|
181
|
+
visit: {
|
|
182
|
+
uuid: 'test-visit-uuid-2',
|
|
183
|
+
startDatetime: '2023-10-15T14:00:00.000+0000',
|
|
184
|
+
encounters: [],
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
];
|
|
188
|
+
|
|
189
|
+
describe('AdmissionRequest', () => {
|
|
190
|
+
beforeEach(() => {
|
|
191
|
+
jest.clearAllMocks();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test('should render loading skeleton when data is loading', () => {
|
|
195
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
196
|
+
admissionRequest: [],
|
|
197
|
+
isLoading: true,
|
|
198
|
+
error: undefined,
|
|
199
|
+
mutate: mockMutate,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
203
|
+
|
|
204
|
+
const loadingSkeleton = screen.getByRole('table');
|
|
205
|
+
expect(loadingSkeleton).toBeInTheDocument();
|
|
206
|
+
expect(loadingSkeleton).toHaveClass('cds--skeleton cds--data-table');
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test('should render error state when there is an error', () => {
|
|
210
|
+
const errorMessage = 'Failed to fetch admission requests';
|
|
211
|
+
const error = new Error(errorMessage);
|
|
212
|
+
|
|
213
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
214
|
+
admissionRequest: [],
|
|
215
|
+
isLoading: false,
|
|
216
|
+
error: error,
|
|
217
|
+
mutate: mockMutate,
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
221
|
+
|
|
222
|
+
expect(screen.getByText(/Admission Request/i)).toBeInTheDocument();
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
test('should render empty state when there are no admission requests', () => {
|
|
226
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
227
|
+
admissionRequest: [],
|
|
228
|
+
isLoading: false,
|
|
229
|
+
error: undefined,
|
|
230
|
+
mutate: mockMutate,
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
234
|
+
|
|
235
|
+
// Check for the header title
|
|
236
|
+
expect(screen.getByText(/Admission Request/i)).toBeInTheDocument();
|
|
237
|
+
// Check for the empty state button
|
|
238
|
+
expect(screen.getByRole('button')).toBeInTheDocument();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test('should launch admission request form when clicking add button in empty state', async () => {
|
|
242
|
+
const user = userEvent.setup();
|
|
243
|
+
|
|
244
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
245
|
+
admissionRequest: [],
|
|
246
|
+
isLoading: false,
|
|
247
|
+
error: undefined,
|
|
248
|
+
mutate: mockMutate,
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
252
|
+
|
|
253
|
+
const addButton = screen.getByRole('button');
|
|
254
|
+
await user.click(addButton);
|
|
255
|
+
|
|
256
|
+
expect(mockLaunchWorkspace).toHaveBeenCalledWith('patient-form-entry-workspace', {
|
|
257
|
+
workspaceTitle: 'Admission Request',
|
|
258
|
+
mutateForm: mockMutate,
|
|
259
|
+
formInfo: {
|
|
260
|
+
formUuid: 'test-admission-form-uuid',
|
|
261
|
+
encounterUuid: '',
|
|
262
|
+
},
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
test('should render admission requests table with data', () => {
|
|
267
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
268
|
+
admissionRequest: mockAdmissionRequestData,
|
|
269
|
+
isLoading: false,
|
|
270
|
+
error: undefined,
|
|
271
|
+
mutate: mockMutate,
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
275
|
+
|
|
276
|
+
// Check table headers
|
|
277
|
+
expect(screen.getByText('Request Datetime')).toBeInTheDocument();
|
|
278
|
+
expect(screen.getByText('Admission Location')).toBeInTheDocument();
|
|
279
|
+
expect(screen.getByText('Admission Type')).toBeInTheDocument();
|
|
280
|
+
expect(screen.getByText('Disposition')).toBeInTheDocument();
|
|
281
|
+
|
|
282
|
+
// Check table data
|
|
283
|
+
expect(screen.getByText('Ward A')).toBeInTheDocument();
|
|
284
|
+
expect(screen.getByText('Ward B')).toBeInTheDocument();
|
|
285
|
+
expect(screen.getByText('Admit to hospital')).toBeInTheDocument();
|
|
286
|
+
expect(screen.getByText('Admit to ICU')).toBeInTheDocument();
|
|
287
|
+
expect(screen.getAllByText('ADMIT')).toHaveLength(2);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it('should render Add button in header when data is available', () => {
|
|
291
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
292
|
+
admissionRequest: mockAdmissionRequestData,
|
|
293
|
+
isLoading: false,
|
|
294
|
+
error: undefined,
|
|
295
|
+
mutate: mockMutate,
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
299
|
+
|
|
300
|
+
const addButton = screen.getByRole('button', { name: /Add/i });
|
|
301
|
+
expect(addButton).toBeInTheDocument();
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it('should launch admission request form when clicking Add button', async () => {
|
|
305
|
+
const user = userEvent.setup();
|
|
306
|
+
|
|
307
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
308
|
+
admissionRequest: mockAdmissionRequestData,
|
|
309
|
+
isLoading: false,
|
|
310
|
+
error: undefined,
|
|
311
|
+
mutate: mockMutate,
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
315
|
+
|
|
316
|
+
const addButton = screen.getByRole('button', { name: /Add/i });
|
|
317
|
+
await user.click(addButton);
|
|
318
|
+
|
|
319
|
+
expect(mockLaunchWorkspace).toHaveBeenCalledWith('patient-form-entry-workspace', {
|
|
320
|
+
workspaceTitle: 'Admission Request',
|
|
321
|
+
mutateForm: mockMutate,
|
|
322
|
+
formInfo: {
|
|
323
|
+
formUuid: 'test-admission-form-uuid',
|
|
324
|
+
encounterUuid: '',
|
|
325
|
+
},
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
test('should format dates correctly in the table', () => {
|
|
330
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
331
|
+
admissionRequest: mockAdmissionRequestData,
|
|
332
|
+
isLoading: false,
|
|
333
|
+
error: undefined,
|
|
334
|
+
mutate: mockMutate,
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
338
|
+
|
|
339
|
+
expect(mockFormatDatetime).toHaveBeenCalled();
|
|
340
|
+
expect(screen.getAllByText('2023-10-16 10:30 AM')).toHaveLength(2);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
test('should render table with correct number of rows', () => {
|
|
344
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
345
|
+
admissionRequest: mockAdmissionRequestData,
|
|
346
|
+
isLoading: false,
|
|
347
|
+
error: undefined,
|
|
348
|
+
mutate: mockMutate,
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
352
|
+
|
|
353
|
+
const tableRows = screen.getAllByRole('row');
|
|
354
|
+
// 1 header row + 2 data rows
|
|
355
|
+
expect(tableRows).toHaveLength(3);
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
test('should handle missing disposition location gracefully', () => {
|
|
359
|
+
const dataWithMissingLocation = [
|
|
360
|
+
{
|
|
361
|
+
...mockAdmissionRequestData[0],
|
|
362
|
+
dispositionLocation: undefined,
|
|
363
|
+
},
|
|
364
|
+
];
|
|
365
|
+
|
|
366
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
367
|
+
admissionRequest: dataWithMissingLocation,
|
|
368
|
+
isLoading: false,
|
|
369
|
+
error: undefined,
|
|
370
|
+
mutate: mockMutate,
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
374
|
+
|
|
375
|
+
// Should still render table
|
|
376
|
+
expect(screen.getByText('Request Datetime')).toBeInTheDocument();
|
|
377
|
+
expect(screen.getByText('Admission Location')).toBeInTheDocument();
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
test('should transform admission request data correctly', () => {
|
|
381
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
382
|
+
admissionRequest: mockAdmissionRequestData,
|
|
383
|
+
isLoading: false,
|
|
384
|
+
error: undefined,
|
|
385
|
+
mutate: mockMutate,
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
389
|
+
|
|
390
|
+
// Verify that all expected data is displayed
|
|
391
|
+
const expectedLocations = ['Ward A', 'Ward B'];
|
|
392
|
+
const expectedDispositions = ['Admit to hospital', 'Admit to ICU'];
|
|
393
|
+
|
|
394
|
+
expectedLocations.forEach((location) => {
|
|
395
|
+
expect(screen.getByText(location)).toBeInTheDocument();
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
expectedDispositions.forEach((disposition) => {
|
|
399
|
+
expect(screen.getByText(disposition)).toBeInTheDocument();
|
|
400
|
+
});
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
test('should call useAdmissionRequest with correct patient UUID', () => {
|
|
404
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
405
|
+
admissionRequest: [],
|
|
406
|
+
isLoading: false,
|
|
407
|
+
error: undefined,
|
|
408
|
+
mutate: mockMutate,
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
412
|
+
|
|
413
|
+
expect(mockUseAdmissionRequest).toHaveBeenCalledWith(patientUuid);
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
test('should render table headers in correct order', () => {
|
|
417
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
418
|
+
admissionRequest: mockAdmissionRequestData,
|
|
419
|
+
isLoading: false,
|
|
420
|
+
error: undefined,
|
|
421
|
+
mutate: mockMutate,
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
425
|
+
|
|
426
|
+
const headers = screen.getAllByRole('columnheader');
|
|
427
|
+
expect(headers[0]).toHaveTextContent('Request Datetime');
|
|
428
|
+
expect(headers[1]).toHaveTextContent('Admission Location');
|
|
429
|
+
expect(headers[2]).toHaveTextContent('Admission Type');
|
|
430
|
+
expect(headers[3]).toHaveTextContent('Disposition');
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
test('should use tablet size for non-desktop layouts', () => {
|
|
434
|
+
mockIsDesktop.mockReturnValue(false);
|
|
435
|
+
mockUseLayoutType.mockReturnValue('tablet' as any);
|
|
436
|
+
|
|
437
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
438
|
+
admissionRequest: mockAdmissionRequestData,
|
|
439
|
+
isLoading: false,
|
|
440
|
+
error: undefined,
|
|
441
|
+
mutate: mockMutate,
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
445
|
+
|
|
446
|
+
// Verify the table is still rendered correctly
|
|
447
|
+
const table = screen.getByRole('table');
|
|
448
|
+
expect(table).toBeInTheDocument();
|
|
449
|
+
});
|
|
450
|
+
});
|