@kenyaemr/esm-ward-app 8.5.1-pre.52 → 8.5.1-pre.65
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 +30 -20
- package/dist/1498.js +1 -1
- package/dist/1498.js.LICENSE.txt +65 -0
- package/dist/1498.js.map +1 -1
- package/dist/1899.js +1 -1
- package/dist/1899.js.map +1 -1
- package/dist/1917.js +1 -1
- package/dist/1917.js.map +1 -1
- package/dist/2557.js +1 -1
- package/dist/2557.js.map +1 -1
- package/dist/2932.js +1 -1
- package/dist/3103.js +1 -0
- package/dist/3103.js.map +1 -0
- package/dist/3104.js +1 -0
- package/dist/3365.js +1 -1
- package/dist/3737.js +1 -1
- package/dist/4224.js +1 -2
- package/dist/4224.js.map +1 -1
- package/dist/4300.js +1 -1
- package/dist/6009.js +1 -1
- package/dist/6009.js.map +1 -1
- package/dist/6871.js +1 -2
- package/dist/6871.js.map +1 -1
- package/dist/717.js +1 -0
- package/dist/717.js.map +1 -0
- package/dist/7179.js +1 -2
- package/dist/7179.js.map +1 -1
- package/dist/723.js +1 -1
- package/dist/723.js.map +1 -0
- package/dist/7449.js +1 -1
- package/dist/7449.js.map +1 -1
- package/dist/7495.js +2 -0
- package/dist/7495.js.map +1 -0
- package/dist/7524.js +1 -1
- package/dist/7524.js.map +1 -1
- package/dist/7661.js +1 -1
- package/dist/7661.js.map +1 -1
- package/dist/7893.js +1 -0
- package/dist/7893.js.map +1 -0
- package/dist/8130.js +1 -0
- package/dist/8130.js.map +1 -0
- package/dist/8205.js +1 -1
- package/dist/8308.js +1 -1
- package/dist/8308.js.map +1 -1
- package/dist/8411.js +1 -0
- package/dist/8411.js.map +1 -0
- package/dist/8501.js +1 -2
- package/dist/8501.js.map +1 -1
- package/dist/9045.js +1 -1
- package/dist/9045.js.map +1 -1
- package/dist/9830.js +1 -0
- package/dist/9830.js.map +1 -0
- package/dist/9876.js +1 -2
- package/dist/9876.js.map +1 -1
- package/dist/{1879.js → 9954.js} +1 -1
- package/dist/9954.js.map +1 -0
- package/dist/kenyaemr-esm-ward-app.js +1 -1
- package/dist/kenyaemr-esm-ward-app.js.buildmanifest.json +251 -326
- package/dist/kenyaemr-esm-ward-app.js.map +1 -1
- package/dist/main.js +2 -1
- package/dist/main.js.LICENSE.txt +114 -0
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/config-schema.ts +61 -0
- package/src/hooks/useSummaryMetrics.ts +1 -1
- package/src/in-patient/admission-request.component.tsx +114 -0
- package/src/in-patient/admission-request.test.tsx +472 -0
- package/src/in-patient/encounter-observations/encounter-observations.component.tsx +71 -0
- package/src/in-patient/encounter-observations/index.ts +3 -0
- package/src/in-patient/encounter-observations/styles.scss +22 -0
- package/src/in-patient/encounter-observations/visit.resource.tsx +161 -0
- package/src/in-patient/in-patient-table/in-patient-table.component.tsx +155 -0
- package/src/in-patient/in-patient-table/in-patient-table.scss +37 -0
- package/src/in-patient/in-patient.component.tsx +32 -0
- package/src/in-patient/in-patient.meta.tsx +10 -0
- package/src/in-patient/in-patient.resource.tsx +56 -0
- package/src/in-patient/inpatient-detail-view.component.tsx +146 -0
- package/src/in-patient/inpatient-forms.component.tsx +75 -0
- package/src/in-patient/inpatient.scss +23 -0
- package/src/index.ts +9 -0
- package/src/routes.json +20 -0
- package/src/ward-view/linelist-wards/LineListTable.tsx +2 -2
- package/src/ward-workspace/admit-patient-form-workspace/admit-patient-form.workspace.tsx +17 -8
- package/src/ward-workspace/admit-patient-form-workspace/patient-admission.resources.ts +2 -6
- package/src/ward.resource.ts +10 -2
- package/translations/en.json +25 -0
- package/dist/1879.js.map +0 -1
- package/dist/1919.js +0 -1
- package/dist/2123.js +0 -1
- package/dist/2123.js.map +0 -1
- package/dist/237.js +0 -2
- package/dist/237.js.LICENSE.txt +0 -54
- package/dist/237.js.map +0 -1
- package/dist/2898.js +0 -2
- package/dist/2898.js.map +0 -1
- package/dist/2953.js +0 -2
- package/dist/2953.js.LICENSE.txt +0 -9
- package/dist/2953.js.map +0 -1
- package/dist/4191.js +0 -2
- package/dist/4191.js.LICENSE.txt +0 -9
- package/dist/4191.js.map +0 -1
- package/dist/4224.js.LICENSE.txt +0 -9
- package/dist/4300.js.map +0 -1
- package/dist/465.js +0 -1
- package/dist/465.js.map +0 -1
- package/dist/681.js +0 -2
- package/dist/681.js.LICENSE.txt +0 -9
- package/dist/681.js.map +0 -1
- package/dist/6871.js.LICENSE.txt +0 -9
- package/dist/7179.js.LICENSE.txt +0 -9
- package/dist/8501.js.LICENSE.txt +0 -5
- package/dist/8622.js +0 -1
- package/dist/8622.js.map +0 -1
- package/dist/9876.js.LICENSE.txt +0 -9
- /package/dist/{2898.js.LICENSE.txt → 7495.js.LICENSE.txt} +0 -0
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
import { formatDatetime, isDesktop, launchWorkspace, type Person, useLayoutType } from '@openmrs/esm-framework';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
|
|
6
|
+
import AdmissionRequest from './admission-request.component';
|
|
7
|
+
import { useAdmissionRequest } from './in-patient.resource';
|
|
8
|
+
import { type InpatientRequest } from '../types';
|
|
9
|
+
const mockUseAdmissionRequest = useAdmissionRequest as jest.MockedFunction<typeof useAdmissionRequest>;
|
|
10
|
+
const mockLaunchWorkspace = launchWorkspace as jest.MockedFunction<typeof launchWorkspace>;
|
|
11
|
+
const mockFormatDatetime = formatDatetime as jest.MockedFunction<typeof formatDatetime>;
|
|
12
|
+
const mockUseLayoutType = useLayoutType as jest.MockedFunction<typeof useLayoutType>;
|
|
13
|
+
const mockIsDesktop = isDesktop as jest.MockedFunction<typeof isDesktop>;
|
|
14
|
+
|
|
15
|
+
jest.mock('./in-patient.resource', () => ({
|
|
16
|
+
useAdmissionRequest: jest.fn(),
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
jest.mock('@openmrs/esm-framework', () => ({
|
|
20
|
+
...jest.requireActual('@openmrs/esm-framework'),
|
|
21
|
+
useConfig: jest.fn().mockReturnValue({
|
|
22
|
+
admissionRequestFormUuid: 'test-admission-form-uuid',
|
|
23
|
+
}),
|
|
24
|
+
|
|
25
|
+
formatDatetime: jest.fn().mockReturnValue('2023-10-16 10:30 AM'),
|
|
26
|
+
useLayoutType: jest.fn().mockReturnValue('desktop'),
|
|
27
|
+
isDesktop: jest.fn().mockReturnValue(true),
|
|
28
|
+
launchWorkspace: jest.fn(),
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
const mockMutate = jest.fn();
|
|
32
|
+
const patientUuid = 'test-patient-uuid';
|
|
33
|
+
|
|
34
|
+
const mockAdmissionRequestData: Array<InpatientRequest> = [
|
|
35
|
+
{
|
|
36
|
+
patient: {
|
|
37
|
+
uuid: 'test-patient-uuid',
|
|
38
|
+
person: {
|
|
39
|
+
uuid: 'test-person-uuid',
|
|
40
|
+
age: 35,
|
|
41
|
+
dead: false,
|
|
42
|
+
display: 'John Doe',
|
|
43
|
+
causeOfDeath: {} as Person['causeOfDeath'],
|
|
44
|
+
gender: 'M',
|
|
45
|
+
deathDate: '',
|
|
46
|
+
attributes: [],
|
|
47
|
+
},
|
|
48
|
+
identifiers: [{ uuid: 'test-identifier-uuid' }],
|
|
49
|
+
},
|
|
50
|
+
dispositionLocation: {
|
|
51
|
+
uuid: 'test-location-uuid',
|
|
52
|
+
display: 'Ward A',
|
|
53
|
+
},
|
|
54
|
+
dispositionType: 'ADMIT',
|
|
55
|
+
disposition: {
|
|
56
|
+
uuid: 'test-disposition-uuid',
|
|
57
|
+
display: 'Admit to hospital',
|
|
58
|
+
answers: [],
|
|
59
|
+
},
|
|
60
|
+
dispositionEncounter: {
|
|
61
|
+
uuid: 'test-encounter-uuid',
|
|
62
|
+
encounterDatetime: '2023-10-16T10:30:00.000+0000',
|
|
63
|
+
patient: { uuid: 'test-patient-uuid' },
|
|
64
|
+
location: { uuid: 'test-location-uuid' },
|
|
65
|
+
form: {
|
|
66
|
+
name: 'Admission Form',
|
|
67
|
+
uuid: 'test-form-uuid',
|
|
68
|
+
version: '1.0',
|
|
69
|
+
published: true,
|
|
70
|
+
retired: false,
|
|
71
|
+
resources: [],
|
|
72
|
+
encounterType: {
|
|
73
|
+
uuid: 'test-encounter-type-uuid',
|
|
74
|
+
name: 'Admission',
|
|
75
|
+
viewPrivilege: null,
|
|
76
|
+
editPrivilege: null,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
encounterType: { uuid: 'test-encounter-type-uuid', name: 'Admission', display: 'Admission' },
|
|
80
|
+
obs: [],
|
|
81
|
+
orders: [],
|
|
82
|
+
voided: false,
|
|
83
|
+
auditInfo: {
|
|
84
|
+
creator: { uuid: 'test-creator-uuid', display: 'Admin' },
|
|
85
|
+
dateCreated: '2023-10-16T10:30:00.000+0000',
|
|
86
|
+
changedBy: null,
|
|
87
|
+
dateChanged: null,
|
|
88
|
+
},
|
|
89
|
+
visit: {
|
|
90
|
+
uuid: 'test-visit-uuid',
|
|
91
|
+
startDatetime: '2023-10-16T10:00:00.000+0000',
|
|
92
|
+
encounters: [],
|
|
93
|
+
visitType: undefined,
|
|
94
|
+
},
|
|
95
|
+
encounterProviders: [],
|
|
96
|
+
diagnoses: [],
|
|
97
|
+
resourceVersion: '1.9',
|
|
98
|
+
},
|
|
99
|
+
dispositionObsGroup: {
|
|
100
|
+
uuid: 'test-obs-group-uuid',
|
|
101
|
+
concept: { uuid: 'test-concept-uuid' },
|
|
102
|
+
value: null,
|
|
103
|
+
obsDatetime: '2023-10-16T10:30:00.000+0000',
|
|
104
|
+
person: undefined,
|
|
105
|
+
accessionNumber: '',
|
|
106
|
+
obsGroup: undefined,
|
|
107
|
+
valueCodedName: undefined,
|
|
108
|
+
groupMembers: [],
|
|
109
|
+
comment: '',
|
|
110
|
+
location: undefined,
|
|
111
|
+
order: undefined,
|
|
112
|
+
encounter: undefined,
|
|
113
|
+
voided: false,
|
|
114
|
+
},
|
|
115
|
+
visit: {
|
|
116
|
+
uuid: 'test-visit-uuid',
|
|
117
|
+
startDatetime: '2023-10-16T10:00:00.000+0000',
|
|
118
|
+
encounters: [],
|
|
119
|
+
visitType: undefined,
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
patient: {
|
|
124
|
+
uuid: 'test-patient-uuid-2',
|
|
125
|
+
person: {
|
|
126
|
+
uuid: 'test-person-uuid-2',
|
|
127
|
+
age: 42,
|
|
128
|
+
dead: false,
|
|
129
|
+
display: 'Jane Smith',
|
|
130
|
+
causeOfDeath: {} as Person['causeOfDeath'],
|
|
131
|
+
gender: 'F',
|
|
132
|
+
deathDate: '',
|
|
133
|
+
attributes: [],
|
|
134
|
+
},
|
|
135
|
+
identifiers: [{ uuid: 'test-identifier-uuid-2' }],
|
|
136
|
+
},
|
|
137
|
+
dispositionLocation: {
|
|
138
|
+
uuid: 'test-location-uuid-2',
|
|
139
|
+
display: 'Ward B',
|
|
140
|
+
},
|
|
141
|
+
dispositionType: 'ADMIT',
|
|
142
|
+
disposition: {
|
|
143
|
+
uuid: 'test-disposition-uuid-2',
|
|
144
|
+
display: 'Admit to ICU',
|
|
145
|
+
answers: [],
|
|
146
|
+
},
|
|
147
|
+
dispositionEncounter: {
|
|
148
|
+
uuid: 'test-encounter-uuid-2',
|
|
149
|
+
encounterDatetime: '2023-10-15T14:30:00.000+0000',
|
|
150
|
+
patient: { uuid: 'test-patient-uuid-2' },
|
|
151
|
+
location: { uuid: 'test-location-uuid-2' },
|
|
152
|
+
form: {
|
|
153
|
+
name: 'Admission Form',
|
|
154
|
+
uuid: 'test-form-uuid',
|
|
155
|
+
version: '1.0',
|
|
156
|
+
published: true,
|
|
157
|
+
retired: false,
|
|
158
|
+
resources: [],
|
|
159
|
+
encounterType: {
|
|
160
|
+
uuid: 'test-encounter-type-uuid',
|
|
161
|
+
name: 'Admission',
|
|
162
|
+
viewPrivilege: null,
|
|
163
|
+
editPrivilege: null,
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
encounterType: { uuid: 'test-encounter-type-uuid', name: 'Admission', display: 'Admission' },
|
|
167
|
+
obs: [],
|
|
168
|
+
orders: [],
|
|
169
|
+
voided: false,
|
|
170
|
+
auditInfo: {
|
|
171
|
+
creator: { uuid: 'test-creator-uuid', display: 'Admin' },
|
|
172
|
+
dateCreated: '2023-10-15T14:30:00.000+0000',
|
|
173
|
+
changedBy: null,
|
|
174
|
+
dateChanged: null,
|
|
175
|
+
},
|
|
176
|
+
visit: {
|
|
177
|
+
uuid: 'test-visit-uuid-2',
|
|
178
|
+
startDatetime: '2023-10-15T14:00:00.000+0000',
|
|
179
|
+
encounters: [],
|
|
180
|
+
visitType: undefined,
|
|
181
|
+
},
|
|
182
|
+
encounterProviders: [],
|
|
183
|
+
diagnoses: [],
|
|
184
|
+
resourceVersion: '1.9',
|
|
185
|
+
},
|
|
186
|
+
dispositionObsGroup: {
|
|
187
|
+
uuid: 'test-obs-group-uuid-2',
|
|
188
|
+
concept: { uuid: 'test-concept-uuid' },
|
|
189
|
+
value: null,
|
|
190
|
+
obsDatetime: '2023-10-15T14:30:00.000+0000',
|
|
191
|
+
person: undefined,
|
|
192
|
+
accessionNumber: '',
|
|
193
|
+
obsGroup: undefined,
|
|
194
|
+
valueCodedName: undefined,
|
|
195
|
+
groupMembers: [],
|
|
196
|
+
comment: '',
|
|
197
|
+
location: undefined,
|
|
198
|
+
order: undefined,
|
|
199
|
+
encounter: undefined,
|
|
200
|
+
voided: false,
|
|
201
|
+
},
|
|
202
|
+
visit: {
|
|
203
|
+
uuid: 'test-visit-uuid-2',
|
|
204
|
+
startDatetime: '2023-10-15T14:00:00.000+0000',
|
|
205
|
+
encounters: [],
|
|
206
|
+
visitType: undefined,
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
];
|
|
210
|
+
|
|
211
|
+
describe('AdmissionRequest', () => {
|
|
212
|
+
beforeEach(() => {
|
|
213
|
+
jest.clearAllMocks();
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test('should render loading skeleton when data is loading', () => {
|
|
217
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
218
|
+
admissionRequest: [],
|
|
219
|
+
isLoading: true,
|
|
220
|
+
error: undefined,
|
|
221
|
+
mutate: mockMutate,
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
225
|
+
|
|
226
|
+
const loadingSkeleton = screen.getByRole('table');
|
|
227
|
+
expect(loadingSkeleton).toBeInTheDocument();
|
|
228
|
+
expect(loadingSkeleton).toHaveClass('cds--skeleton cds--data-table');
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test('should render error state when there is an error', () => {
|
|
232
|
+
const errorMessage = 'Failed to fetch admission requests';
|
|
233
|
+
const error = new Error(errorMessage);
|
|
234
|
+
|
|
235
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
236
|
+
admissionRequest: [],
|
|
237
|
+
isLoading: false,
|
|
238
|
+
error: error,
|
|
239
|
+
mutate: mockMutate,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
243
|
+
|
|
244
|
+
expect(screen.getByText(/Admission Request/i)).toBeInTheDocument();
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test('should render empty state when there are no admission requests', () => {
|
|
248
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
249
|
+
admissionRequest: [],
|
|
250
|
+
isLoading: false,
|
|
251
|
+
error: undefined,
|
|
252
|
+
mutate: mockMutate,
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
256
|
+
|
|
257
|
+
// Check for the header title
|
|
258
|
+
expect(screen.getByRole('heading', { level: 4, name: /admission request/i })).toBeInTheDocument();
|
|
259
|
+
// Check for the empty state button
|
|
260
|
+
expect(screen.getByRole('button')).toBeInTheDocument();
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
test('should launch admission request form when clicking add button in empty state', async () => {
|
|
264
|
+
const user = userEvent.setup();
|
|
265
|
+
|
|
266
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
267
|
+
admissionRequest: [],
|
|
268
|
+
isLoading: false,
|
|
269
|
+
error: undefined,
|
|
270
|
+
mutate: mockMutate,
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
274
|
+
|
|
275
|
+
const addButton = screen.getByRole('button');
|
|
276
|
+
await user.click(addButton);
|
|
277
|
+
|
|
278
|
+
expect(mockLaunchWorkspace).toHaveBeenCalledWith('patient-form-entry-workspace', {
|
|
279
|
+
workspaceTitle: 'Admission Request',
|
|
280
|
+
mutateForm: mockMutate,
|
|
281
|
+
formInfo: {
|
|
282
|
+
formUuid: 'test-admission-form-uuid',
|
|
283
|
+
encounterUuid: '',
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
test('should render admission requests table with data', () => {
|
|
289
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
290
|
+
admissionRequest: mockAdmissionRequestData,
|
|
291
|
+
isLoading: false,
|
|
292
|
+
error: undefined,
|
|
293
|
+
mutate: mockMutate,
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
297
|
+
|
|
298
|
+
// Check table headers
|
|
299
|
+
expect(screen.getByText('Request Datetime')).toBeInTheDocument();
|
|
300
|
+
expect(screen.getByText('Admission Location')).toBeInTheDocument();
|
|
301
|
+
expect(screen.getByText('Admission Type')).toBeInTheDocument();
|
|
302
|
+
expect(screen.getByText('Disposition')).toBeInTheDocument();
|
|
303
|
+
|
|
304
|
+
// Check table data
|
|
305
|
+
expect(screen.getByText('Ward A')).toBeInTheDocument();
|
|
306
|
+
expect(screen.getByText('Ward B')).toBeInTheDocument();
|
|
307
|
+
expect(screen.getByText('Admit to hospital')).toBeInTheDocument();
|
|
308
|
+
expect(screen.getByText('Admit to ICU')).toBeInTheDocument();
|
|
309
|
+
expect(screen.getAllByText('ADMIT')).toHaveLength(2);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it('should render Add button in header when data is available', () => {
|
|
313
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
314
|
+
admissionRequest: mockAdmissionRequestData,
|
|
315
|
+
isLoading: false,
|
|
316
|
+
error: undefined,
|
|
317
|
+
mutate: mockMutate,
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
321
|
+
|
|
322
|
+
const addButton = screen.getByRole('button', { name: /Add/i });
|
|
323
|
+
expect(addButton).toBeInTheDocument();
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it('should launch admission request form when clicking Add button', async () => {
|
|
327
|
+
const user = userEvent.setup();
|
|
328
|
+
|
|
329
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
330
|
+
admissionRequest: mockAdmissionRequestData,
|
|
331
|
+
isLoading: false,
|
|
332
|
+
error: undefined,
|
|
333
|
+
mutate: mockMutate,
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
337
|
+
|
|
338
|
+
const addButton = screen.getByRole('button', { name: /Add/i });
|
|
339
|
+
await user.click(addButton);
|
|
340
|
+
|
|
341
|
+
expect(mockLaunchWorkspace).toHaveBeenCalledWith('patient-form-entry-workspace', {
|
|
342
|
+
workspaceTitle: 'Admission Request',
|
|
343
|
+
mutateForm: mockMutate,
|
|
344
|
+
formInfo: {
|
|
345
|
+
formUuid: 'test-admission-form-uuid',
|
|
346
|
+
encounterUuid: '',
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
test('should format dates correctly in the table', () => {
|
|
352
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
353
|
+
admissionRequest: mockAdmissionRequestData,
|
|
354
|
+
isLoading: false,
|
|
355
|
+
error: undefined,
|
|
356
|
+
mutate: mockMutate,
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
360
|
+
|
|
361
|
+
expect(mockFormatDatetime).toHaveBeenCalled();
|
|
362
|
+
expect(screen.getAllByText('2023-10-16 10:30 AM')).toHaveLength(2);
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
test('should render table with correct number of rows', () => {
|
|
366
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
367
|
+
admissionRequest: mockAdmissionRequestData,
|
|
368
|
+
isLoading: false,
|
|
369
|
+
error: undefined,
|
|
370
|
+
mutate: mockMutate,
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
374
|
+
|
|
375
|
+
const tableRows = screen.getAllByRole('row');
|
|
376
|
+
// 1 header row + 2 data rows
|
|
377
|
+
expect(tableRows).toHaveLength(3);
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
test('should handle missing disposition location gracefully', () => {
|
|
381
|
+
const dataWithMissingLocation = [
|
|
382
|
+
{
|
|
383
|
+
...mockAdmissionRequestData[0],
|
|
384
|
+
dispositionLocation: undefined,
|
|
385
|
+
},
|
|
386
|
+
];
|
|
387
|
+
|
|
388
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
389
|
+
admissionRequest: dataWithMissingLocation,
|
|
390
|
+
isLoading: false,
|
|
391
|
+
error: undefined,
|
|
392
|
+
mutate: mockMutate,
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
396
|
+
|
|
397
|
+
// Should still render table
|
|
398
|
+
expect(screen.getByText('Request Datetime')).toBeInTheDocument();
|
|
399
|
+
expect(screen.getByText('Admission Location')).toBeInTheDocument();
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
test('should transform admission request data correctly', () => {
|
|
403
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
404
|
+
admissionRequest: mockAdmissionRequestData,
|
|
405
|
+
isLoading: false,
|
|
406
|
+
error: undefined,
|
|
407
|
+
mutate: mockMutate,
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
411
|
+
|
|
412
|
+
// Verify that all expected data is displayed
|
|
413
|
+
const expectedLocations = ['Ward A', 'Ward B'];
|
|
414
|
+
const expectedDispositions = ['Admit to hospital', 'Admit to ICU'];
|
|
415
|
+
|
|
416
|
+
expectedLocations.forEach((location) => {
|
|
417
|
+
expect(screen.getByText(location)).toBeInTheDocument();
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
expectedDispositions.forEach((disposition) => {
|
|
421
|
+
expect(screen.getByText(disposition)).toBeInTheDocument();
|
|
422
|
+
});
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
test('should call useAdmissionRequest with correct patient UUID', () => {
|
|
426
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
427
|
+
admissionRequest: [],
|
|
428
|
+
isLoading: false,
|
|
429
|
+
error: undefined,
|
|
430
|
+
mutate: mockMutate,
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
434
|
+
|
|
435
|
+
expect(mockUseAdmissionRequest).toHaveBeenCalledWith(patientUuid);
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
test('should render table headers in correct order', () => {
|
|
439
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
440
|
+
admissionRequest: mockAdmissionRequestData,
|
|
441
|
+
isLoading: false,
|
|
442
|
+
error: undefined,
|
|
443
|
+
mutate: mockMutate,
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
447
|
+
|
|
448
|
+
const headers = screen.getAllByRole('columnheader');
|
|
449
|
+
expect(headers[0]).toHaveTextContent('Request Datetime');
|
|
450
|
+
expect(headers[1]).toHaveTextContent('Admission Location');
|
|
451
|
+
expect(headers[2]).toHaveTextContent('Admission Type');
|
|
452
|
+
expect(headers[3]).toHaveTextContent('Disposition');
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
test('should use tablet size for non-desktop layouts', () => {
|
|
456
|
+
mockIsDesktop.mockReturnValue(false);
|
|
457
|
+
mockUseLayoutType.mockReturnValue('tablet' as any);
|
|
458
|
+
|
|
459
|
+
mockUseAdmissionRequest.mockReturnValue({
|
|
460
|
+
admissionRequest: mockAdmissionRequestData,
|
|
461
|
+
isLoading: false,
|
|
462
|
+
error: undefined,
|
|
463
|
+
mutate: mockMutate,
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
render(<AdmissionRequest patientUuid={patientUuid} />);
|
|
467
|
+
|
|
468
|
+
// Verify the table is still rendered correctly
|
|
469
|
+
const table = screen.getByRole('table');
|
|
470
|
+
expect(table).toBeInTheDocument();
|
|
471
|
+
});
|
|
472
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { SkeletonText } from '@carbon/react';
|
|
4
|
+
import { useConfig } from '@openmrs/esm-framework';
|
|
5
|
+
import { type Observation } from './visit.resource';
|
|
6
|
+
import styles from './styles.scss';
|
|
7
|
+
|
|
8
|
+
interface EncounterObservationsProps {
|
|
9
|
+
observations: Array<Observation>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const EncounterObservations: React.FC<EncounterObservationsProps> = ({ observations }) => {
|
|
13
|
+
const { t } = useTranslation();
|
|
14
|
+
const { obsConceptUuidsToHide = [] } = useConfig();
|
|
15
|
+
|
|
16
|
+
function getAnswerFromDisplay(display: string): string {
|
|
17
|
+
const colonIndex = display.indexOf(':');
|
|
18
|
+
if (colonIndex === -1) {
|
|
19
|
+
return '';
|
|
20
|
+
} else {
|
|
21
|
+
return display.substring(colonIndex + 1).trim();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!observations) {
|
|
26
|
+
return <SkeletonText />;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (observations) {
|
|
30
|
+
const filteredObservations = !!obsConceptUuidsToHide.length
|
|
31
|
+
? observations?.filter((obs) => {
|
|
32
|
+
return !obsConceptUuidsToHide.includes(obs?.concept?.uuid);
|
|
33
|
+
})
|
|
34
|
+
: observations;
|
|
35
|
+
return (
|
|
36
|
+
<div className={styles.observation}>
|
|
37
|
+
{filteredObservations?.map((obs, index) => {
|
|
38
|
+
if (obs.groupMembers) {
|
|
39
|
+
return (
|
|
40
|
+
<React.Fragment key={index}>
|
|
41
|
+
<span className={styles.parentConcept}>{obs.concept.display}</span>
|
|
42
|
+
<span />
|
|
43
|
+
{obs.groupMembers.map((member) => (
|
|
44
|
+
<React.Fragment key={index}>
|
|
45
|
+
<span className={styles.childConcept}>{member.concept.display}</span>
|
|
46
|
+
<span>{getAnswerFromDisplay(member.display)}</span>
|
|
47
|
+
</React.Fragment>
|
|
48
|
+
))}
|
|
49
|
+
</React.Fragment>
|
|
50
|
+
);
|
|
51
|
+
} else {
|
|
52
|
+
return (
|
|
53
|
+
<React.Fragment key={index}>
|
|
54
|
+
<span>{obs.concept.display}</span>
|
|
55
|
+
<span>{getAnswerFromDisplay(obs.display)}</span>
|
|
56
|
+
</React.Fragment>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
})}
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<div className={styles.observation}>
|
|
66
|
+
<p>{t('noObservationsFound', 'No observations found')}</p>
|
|
67
|
+
</div>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export default EncounterObservations;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
@use '@carbon/layout';
|
|
2
|
+
|
|
3
|
+
.observation {
|
|
4
|
+
display: grid;
|
|
5
|
+
grid-template-columns: 1fr 1fr;
|
|
6
|
+
grid-gap: layout.$spacing-03;
|
|
7
|
+
margin-block: layout.$spacing-05;
|
|
8
|
+
margin-inline: 0 layout.$spacing-05;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.observation > span {
|
|
12
|
+
align-self: center;
|
|
13
|
+
justify-self: start;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.parentConcept {
|
|
17
|
+
font-weight: bold;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.childConcept {
|
|
21
|
+
padding-inline-start: 0.8rem;
|
|
22
|
+
}
|