@kenyaemr/esm-service-queues-app 8.1.1-pre.129 → 8.1.2-pre.154
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 +26 -26
- package/dist/1006.js +1 -0
- package/dist/1006.js.map +1 -0
- package/dist/1060.js +1 -0
- package/dist/1060.js.map +1 -0
- package/dist/130.js +1 -1
- package/dist/130.js.map +1 -1
- package/dist/1325.js +1 -0
- package/dist/1325.js.map +1 -0
- package/dist/1644.js +1 -0
- package/dist/1727.js +1 -0
- package/dist/1727.js.map +1 -0
- package/dist/1800.js +1 -0
- package/dist/1800.js.map +1 -0
- package/dist/236.js +1 -1
- package/dist/2757.js +1 -0
- package/dist/{282.js → 2760.js} +1 -1
- package/dist/2760.js.map +1 -0
- package/dist/2784.js +2 -0
- package/dist/2784.js.map +1 -0
- package/dist/3199.js +1 -0
- package/dist/3199.js.map +1 -0
- package/dist/3372.js +2 -0
- package/dist/3372.js.map +1 -0
- package/dist/3574.js +1 -0
- package/dist/3604.js +1 -0
- package/dist/3604.js.map +1 -0
- package/dist/3652.js +1 -0
- package/dist/3760.js +1 -0
- package/dist/3760.js.map +1 -0
- package/dist/3818.js +1 -0
- package/dist/3818.js.map +1 -0
- package/dist/3828.js +1 -0
- package/dist/3828.js.map +1 -0
- package/dist/4272.js +1 -0
- package/dist/4378.js +1 -0
- package/dist/443.js +1 -0
- package/dist/443.js.map +1 -0
- package/dist/4460.js +1 -0
- package/dist/4705.js +1 -0
- package/dist/4911.js +1 -0
- package/dist/4911.js.map +1 -0
- package/dist/5236.js +1 -0
- package/dist/5236.js.map +1 -0
- package/dist/5240.js +1 -0
- package/dist/5282.js +1 -0
- package/dist/5282.js.map +1 -0
- package/dist/5336.js +1 -0
- package/dist/539.js +1 -0
- package/dist/5673.js +1 -0
- package/dist/5711.js +1 -0
- package/dist/5737.js +1 -0
- package/dist/5833.js +1 -0
- package/dist/6566.js +1 -0
- package/dist/6578.js +2 -0
- package/dist/{660.js.LICENSE.txt → 6578.js.LICENSE.txt} +5 -0
- package/dist/6578.js.map +1 -0
- package/dist/6591.js +2 -0
- package/dist/6591.js.map +1 -0
- package/dist/6670.js +1 -0
- package/dist/6670.js.map +1 -0
- package/dist/6727.js +1 -0
- package/dist/744.js +1 -0
- package/dist/752.js +1 -1
- package/dist/752.js.map +1 -1
- package/dist/7807.js +1 -0
- package/dist/8271.js +1 -0
- package/dist/8319.js +1 -0
- package/dist/8788.js +1 -0
- package/dist/899.js +1 -0
- package/dist/9261.js +1 -0
- package/dist/9392.js +1 -0
- package/dist/9392.js.map +1 -0
- package/dist/9993.js +1 -0
- package/dist/9993.js.map +1 -0
- package/dist/kenyaemr-esm-service-queues-app.js +1 -1
- package/dist/kenyaemr-esm-service-queues-app.js.buildmanifest.json +541 -234
- package/dist/kenyaemr-esm-service-queues-app.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/main.js.LICENSE.txt +5 -0
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package-lock.json +2 -2
- package/package.json +8 -5
- package/src/active-visits/active-visits-table.resource.ts +0 -62
- package/src/active-visits/change-status-dialog.component.tsx +10 -3
- package/src/active-visits/change-status-dialog.scss +29 -1
- package/src/active-visits/change-status-dialog.test.tsx +11 -3
- package/src/add-provider-queue-room/add-provider-queue-room.component.tsx +53 -54
- package/src/add-provider-queue-room/add-provider-queue-room.scss +28 -0
- package/src/add-provider-queue-room/add-provider-queue-room.test.tsx +1 -1
- package/src/clear-queue-entries-dialog/clear-queue-entries-dialog.component.tsx +1 -0
- package/src/clear-queue-entries-dialog/clear-queue-entries-dialog.scss +29 -0
- package/src/clear-queue-entries-dialog/clear-queue-entries-dialog.test.tsx +4 -1
- package/src/config-schema.ts +28 -8
- package/src/create-queue-entry/create-queue-entry.workspace.tsx +99 -0
- package/src/create-queue-entry/existing-visit-form/existing-visit-form.component.tsx +73 -0
- package/src/{patient-search/visit-form-queue-fields/visit-form-queue-fields.component.tsx → create-queue-entry/queue-fields/queue-fields.component.tsx} +76 -50
- package/src/create-queue-entry/queue-fields/queue-fields.resource.ts +63 -0
- package/src/{patient-search/visit-form-queue-fields/visit-form-queue-fields.scss → create-queue-entry/queue-fields/queue-fields.scss} +0 -4
- package/src/{patient-search/visit-form-queue-fields/visit-form-queue-fields.test.tsx → create-queue-entry/queue-fields/queue-fields.test.tsx} +37 -17
- package/src/create-queue-entry/queue-fields/visit-form-queue-fields.extension.tsx +31 -0
- package/src/hooks/useQueueEntries.ts +13 -12
- package/src/index.ts +8 -14
- package/src/patient-info/patient-info.component.tsx +10 -8
- package/src/patient-queue-header/patient-queue-header.component.tsx +18 -13
- package/src/patient-queue-metrics/metrics-header.component.tsx +4 -4
- package/src/queue-entry-table-components/queue-priority.component.tsx +16 -11
- package/src/queue-entry-table-components/queue-priority.scss +5 -0
- package/src/queue-entry-table-components/transition-entry.component.tsx +1 -1
- package/src/queue-patient-linelists/queue-linelist-base-table.component.tsx +1 -1
- package/src/queue-patient-linelists/queue-linelist-filter.workspace.tsx +13 -12
- package/src/queue-patient-linelists/scheduled-appointments-table.component.tsx +1 -1
- package/src/queue-rooms/queue-room-form.test.tsx +2 -2
- package/src/queue-rooms/queue-room-form.workspace.tsx +1 -1
- package/src/queue-screen/queue-screen.test.tsx +11 -4
- package/src/queue-services/queue-service-form.test.tsx +76 -16
- package/src/queue-services/queue-service-form.workspace.tsx +131 -131
- package/src/queue-services/queue-service.resource.ts +7 -2
- package/src/queue-table/cells/columns.resource.ts +10 -7
- package/src/queue-table/cells/queue-table-visit-attribute-queue-number-cell.component.tsx +1 -0
- package/src/queue-table/default-queue-table.component.tsx +12 -13
- package/src/queue-table/default-queue-table.test.tsx +3 -3
- package/src/queue-table/queue-entry-actions/queue-entry-actions-modal.scss +28 -0
- package/src/queue-table/queue-entry-actions/queue-entry-actions.modal.tsx +8 -2
- package/src/queue-table/queue-entry-actions/queue-entry-confirm-action.modal.tsx +2 -1
- package/src/queue-table/queue-entry-actions/queue-entry-confirm-action.scss +29 -0
- package/src/queue-table/queue-table.component.tsx +1 -1
- package/src/queue-table/queue-table.scss +12 -2
- package/src/queue-table/queue-table.test.tsx +10 -1
- package/src/remove-queue-entry-dialog/remove-queue-entry.component.tsx +16 -4
- package/src/remove-queue-entry-dialog/remove-queue-entry.scss +29 -0
- package/src/routes.json +4 -8
- package/src/transition-latest-queue-entry/transition-latest-queue-entry.resource.ts +2 -10
- package/src/transition-queue-entry/transition-queue-entry-dialog.component.tsx +41 -32
- package/src/transition-queue-entry/transition-queue-entry-dialog.scss +28 -0
- package/src/types/index.ts +0 -8
- package/src/views/queue-tables-for-all-statuses.component.tsx +12 -15
- package/translations/am.json +5 -78
- package/translations/ar.json +5 -78
- package/translations/de.json +235 -0
- package/translations/en.json +9 -86
- package/translations/es.json +3 -76
- package/translations/fr.json +5 -78
- package/translations/he.json +5 -78
- package/translations/hi.json +235 -0
- package/translations/hi_IN.json +235 -0
- package/translations/id.json +235 -0
- package/translations/it.json +235 -0
- package/translations/km.json +5 -78
- package/translations/ne.json +235 -0
- package/translations/pt.json +235 -0
- package/translations/pt_BR.json +235 -0
- package/translations/qu.json +235 -0
- package/translations/si.json +235 -0
- package/translations/sw.json +235 -0
- package/translations/sw_KE.json +235 -0
- package/translations/tr.json +235 -0
- package/translations/tr_TR.json +235 -0
- package/translations/uk.json +235 -0
- package/translations/vi.json +235 -0
- package/translations/zh.json +6 -79
- package/translations/zh_CN.json +5 -78
- package/dist/169.js +0 -1
- package/dist/169.js.map +0 -1
- package/dist/199.js +0 -1
- package/dist/199.js.map +0 -1
- package/dist/236.js.map +0 -1
- package/dist/271.js +0 -1
- package/dist/282.js.map +0 -1
- package/dist/319.js +0 -1
- package/dist/325.js +0 -1
- package/dist/325.js.map +0 -1
- package/dist/366.js +0 -1
- package/dist/366.js.map +0 -1
- package/dist/372.js +0 -2
- package/dist/372.js.map +0 -1
- package/dist/392.js +0 -1
- package/dist/392.js.map +0 -1
- package/dist/460.js +0 -1
- package/dist/501.js +0 -1
- package/dist/501.js.map +0 -1
- package/dist/574.js +0 -1
- package/dist/591.js +0 -2
- package/dist/591.js.map +0 -1
- package/dist/6.js +0 -1
- package/dist/6.js.map +0 -1
- package/dist/60.js +0 -1
- package/dist/60.js.map +0 -1
- package/dist/604.js +0 -1
- package/dist/604.js.map +0 -1
- package/dist/644.js +0 -1
- package/dist/660.js +0 -2
- package/dist/660.js.map +0 -1
- package/dist/670.js +0 -1
- package/dist/670.js.map +0 -1
- package/dist/727.js +0 -1
- package/dist/727.js.map +0 -1
- package/dist/748.js +0 -1
- package/dist/748.js.map +0 -1
- package/dist/757.js +0 -1
- package/dist/760.js +0 -1
- package/dist/760.js.map +0 -1
- package/dist/784.js +0 -2
- package/dist/784.js.map +0 -1
- package/dist/788.js +0 -1
- package/dist/800.js +0 -1
- package/dist/800.js.map +0 -1
- package/dist/807.js +0 -1
- package/dist/818.js +0 -1
- package/dist/818.js.map +0 -1
- package/dist/828.js +0 -1
- package/dist/828.js.map +0 -1
- package/dist/833.js +0 -1
- package/dist/911.js +0 -1
- package/dist/911.js.map +0 -1
- package/dist/940.js +0 -1
- package/dist/940.js.map +0 -1
- package/src/add-patient-toqueue/add-patient-toqueue-dialog.component.tsx +0 -228
- package/src/add-patient-toqueue/add-patient-toqueue-dialog.scss +0 -32
- package/src/patient-search/advanced-search.component.tsx +0 -191
- package/src/patient-search/advanced-search.scss +0 -154
- package/src/patient-search/advanced-search.test.tsx +0 -26
- package/src/patient-search/basic-search.component.tsx +0 -112
- package/src/patient-search/basic-search.scss +0 -139
- package/src/patient-search/basic-search.test.tsx +0 -18
- package/src/patient-search/empty-data-illustration.component.tsx +0 -41
- package/src/patient-search/hooks/useActivePatientEnrollment.tsx +0 -29
- package/src/patient-search/hooks/useDefaultLocation.ts +0 -14
- package/src/patient-search/hooks/usePatients.tsx +0 -25
- package/src/patient-search/hooks/useRecommendedVisitTypes.tsx +0 -35
- package/src/patient-search/hooks/useScheduledVisits.ts +0 -52
- package/src/patient-search/patient-scheduled-visits.component.tsx +0 -315
- package/src/patient-search/patient-scheduled-visits.scss +0 -131
- package/src/patient-search/patient-scheduled-visits.test.tsx +0 -39
- package/src/patient-search/patient-search.workspace.tsx +0 -135
- package/src/patient-search/search-illustration.component.tsx +0 -27
- package/src/patient-search/search-results.component.tsx +0 -75
- package/src/patient-search/search-results.scss +0 -80
- package/src/patient-search/search-results.test.tsx +0 -69
- package/src/patient-search/search.resource.ts +0 -10
- package/src/patient-search/visit-form/existing-visit-form.component.tsx +0 -112
- package/src/patient-search/visit-form/queue.resource.ts +0 -64
- package/src/patient-search/visit-form/visit-form.component.tsx +0 -337
- package/src/patient-search/visit-form/visit-type-selector.component.tsx +0 -153
- package/src/patient-search/visit-form/visit-type-selector.scss +0 -100
- package/src/patient-search/visit-form/visit-type-selector.test.tsx +0 -84
- package/src/visits-missing-inqueue/visits-missing-inqueue.component.tsx +0 -277
- package/src/visits-missing-inqueue/visits-missing-inqueue.resource.ts +0 -93
- package/src/visits-missing-inqueue/visits-missing-inqueue.scss +0 -111
- /package/dist/{784.js.LICENSE.txt → 2784.js.LICENSE.txt} +0 -0
- /package/dist/{372.js.LICENSE.txt → 3372.js.LICENSE.txt} +0 -0
- /package/dist/{591.js.LICENSE.txt → 6591.js.LICENSE.txt} +0 -0
- /package/src/{patient-search/patient-search.scss → create-queue-entry/create-queue-entry.scss} +0 -0
- /package/src/{patient-search/visit-form/visit-form.scss → create-queue-entry/existing-visit-form/existing-visit-form.scss} +0 -0
- /package/src/{patient-search → create-queue-entry}/hooks/useQueueLocations.tsx +0 -0
|
@@ -1,166 +1,162 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import type { TFunction } from 'react-i18next';
|
|
4
|
+
import { useForm, Controller } from 'react-hook-form';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
3
7
|
import {
|
|
8
|
+
Button,
|
|
9
|
+
ButtonSet,
|
|
4
10
|
Column,
|
|
5
11
|
Form,
|
|
12
|
+
InlineLoading,
|
|
6
13
|
Layer,
|
|
7
|
-
Stack,
|
|
8
|
-
TextInput,
|
|
9
14
|
Select,
|
|
10
15
|
SelectItem,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
InlineNotification,
|
|
16
|
+
Stack,
|
|
17
|
+
TextInput,
|
|
14
18
|
} from '@carbon/react';
|
|
15
19
|
import { mutate } from 'swr';
|
|
16
20
|
import { type DefaultWorkspaceProps, restBaseUrl, showSnackbar } from '@openmrs/esm-framework';
|
|
17
21
|
import { saveQueue, useServiceConcepts } from './queue-service.resource';
|
|
18
|
-
import { useQueueLocations } from '../
|
|
22
|
+
import { useQueueLocations } from '../create-queue-entry/hooks/useQueueLocations';
|
|
19
23
|
import styles from './queue-service-form.scss';
|
|
20
24
|
|
|
25
|
+
const createQueueServiceSchema = (t: TFunction) =>
|
|
26
|
+
z.object({
|
|
27
|
+
queueName: z
|
|
28
|
+
.string({
|
|
29
|
+
required_error: t('queueNameRequired', 'Queue name is required'),
|
|
30
|
+
})
|
|
31
|
+
.trim()
|
|
32
|
+
.min(1, t('queueNameRequired', 'Queue name is required')),
|
|
33
|
+
queueServiceType: z
|
|
34
|
+
.string({
|
|
35
|
+
required_error: t('queueConceptRequired', 'Queue concept is required'),
|
|
36
|
+
})
|
|
37
|
+
.trim()
|
|
38
|
+
.min(1, t('queueConceptRequired', 'Queue concept is required')),
|
|
39
|
+
userLocation: z
|
|
40
|
+
.string({
|
|
41
|
+
required_error: t('queueLocationRequired', 'Queue location is required'),
|
|
42
|
+
})
|
|
43
|
+
.trim()
|
|
44
|
+
.min(1, t('queueLocationRequired', 'Queue location is required')),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
type QueueServiceFormData = z.infer<ReturnType<typeof createQueueServiceSchema>>;
|
|
48
|
+
|
|
21
49
|
const QueueServiceForm: React.FC<DefaultWorkspaceProps> = ({ closeWorkspace }) => {
|
|
22
50
|
const { t } = useTranslation();
|
|
23
51
|
const { queueConcepts } = useServiceConcepts();
|
|
24
|
-
const [queueName, setQueueName] = useState('');
|
|
25
|
-
const [queueConcept, setQueueConcept] = useState('');
|
|
26
|
-
const [isMissingName, setMissingName] = useState(false);
|
|
27
|
-
const [isMissingQueue, setMissingQueue] = useState(false);
|
|
28
|
-
const [isMissingLocation, setMissingLocation] = useState(false);
|
|
29
|
-
const [userLocation, setUserLocation] = useState('');
|
|
30
52
|
const { queueLocations } = useQueueLocations();
|
|
31
53
|
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
54
|
+
const QueueServiceSchema = createQueueServiceSchema(t);
|
|
55
|
+
|
|
56
|
+
const {
|
|
57
|
+
control,
|
|
58
|
+
handleSubmit,
|
|
59
|
+
formState: { errors, isSubmitting },
|
|
60
|
+
} = useForm<QueueServiceFormData>({
|
|
61
|
+
resolver: zodResolver(QueueServiceSchema),
|
|
62
|
+
defaultValues: {
|
|
63
|
+
queueName: '',
|
|
64
|
+
queueServiceType: '',
|
|
65
|
+
userLocation: '',
|
|
66
|
+
},
|
|
67
|
+
});
|
|
35
68
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
if (!queueConcept) {
|
|
41
|
-
setMissingQueue(true);
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
if (!userLocation) {
|
|
45
|
-
setMissingLocation(true);
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
69
|
+
const createQueue = async (data: QueueServiceFormData) => {
|
|
70
|
+
try {
|
|
71
|
+
await saveQueue(data.queueName, data.queueServiceType, '', data.userLocation);
|
|
48
72
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
73
|
+
showSnackbar({
|
|
74
|
+
title: t('queueServiceCreated', 'Queue service created'),
|
|
75
|
+
kind: 'success',
|
|
76
|
+
subtitle: t('queueServiceCreatedSuccessfully', 'Queue service created successfully'),
|
|
77
|
+
});
|
|
52
78
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
showSnackbar({
|
|
68
|
-
title: t('errorAddingQueue', 'Error adding queue'),
|
|
69
|
-
kind: 'error',
|
|
70
|
-
isLowContrast: false,
|
|
71
|
-
subtitle: error?.message,
|
|
72
|
-
});
|
|
73
|
-
},
|
|
74
|
-
);
|
|
75
|
-
},
|
|
76
|
-
[queueName, queueConcept, userLocation, t, closeWorkspace],
|
|
77
|
-
);
|
|
79
|
+
closeWorkspace();
|
|
80
|
+
await Promise.all([
|
|
81
|
+
mutate(`${restBaseUrl}/queue?${data.userLocation}`),
|
|
82
|
+
mutate(`${restBaseUrl}/queue?location=${data.userLocation}`),
|
|
83
|
+
]);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
showSnackbar({
|
|
86
|
+
title: t('errorCreatingQueueService', 'Error creating queue service'),
|
|
87
|
+
kind: 'error',
|
|
88
|
+
isLowContrast: false,
|
|
89
|
+
subtitle: error?.responseBody?.message || error?.message,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
};
|
|
78
93
|
|
|
79
94
|
return (
|
|
80
|
-
<Form onSubmit={createQueue} className={styles.form}>
|
|
81
|
-
<Stack gap={
|
|
95
|
+
<Form onSubmit={handleSubmit(createQueue)} className={styles.form}>
|
|
96
|
+
<Stack gap={5} className={styles.grid}>
|
|
82
97
|
<Column>
|
|
83
98
|
<Layer className={styles.input}>
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
style={{ margin: '0', minWidth: '100%' }}
|
|
95
|
-
kind="error"
|
|
96
|
-
lowContrast={true}
|
|
97
|
-
title={t('missingQueueName', 'Missing queue name')}
|
|
98
|
-
subtitle={t('addQueueName', 'Please add a queue name')}
|
|
99
|
+
<Controller
|
|
100
|
+
name="queueName"
|
|
101
|
+
control={control}
|
|
102
|
+
render={({ field }) => (
|
|
103
|
+
<TextInput
|
|
104
|
+
{...field}
|
|
105
|
+
id="queueName"
|
|
106
|
+
invalidText={errors.queueName?.message}
|
|
107
|
+
invalid={!!errors.queueName}
|
|
108
|
+
labelText={t('queueName', 'Queue name')}
|
|
99
109
|
/>
|
|
100
|
-
|
|
101
|
-
|
|
110
|
+
)}
|
|
111
|
+
/>
|
|
102
112
|
</Layer>
|
|
103
113
|
</Column>
|
|
104
|
-
|
|
105
114
|
<Column>
|
|
106
115
|
<Layer className={styles.input}>
|
|
107
|
-
<
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
<SelectItem
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
lowContrast={true}
|
|
128
|
-
title={t('missingService', 'Missing service')}
|
|
129
|
-
subtitle={t('selectServiceType', 'Select a service type')}
|
|
130
|
-
/>
|
|
131
|
-
</section>
|
|
132
|
-
)}
|
|
116
|
+
<Controller
|
|
117
|
+
name="queueServiceType"
|
|
118
|
+
control={control}
|
|
119
|
+
render={({ field }) => (
|
|
120
|
+
<Select
|
|
121
|
+
{...field}
|
|
122
|
+
labelText={t('selectServiceType', 'Select a service type')}
|
|
123
|
+
id="queueServiceType"
|
|
124
|
+
invalid={!!errors?.queueServiceType}
|
|
125
|
+
invalidText={errors?.queueServiceType?.message}>
|
|
126
|
+
<SelectItem text={t('selectServiceType', 'Select a service type')} value="" />
|
|
127
|
+
{queueConcepts?.length > 0 &&
|
|
128
|
+
queueConcepts.map((concept) => (
|
|
129
|
+
<SelectItem key={concept.uuid} text={concept.display} value={concept.uuid}>
|
|
130
|
+
{concept.display}
|
|
131
|
+
</SelectItem>
|
|
132
|
+
))}
|
|
133
|
+
</Select>
|
|
134
|
+
)}
|
|
135
|
+
/>
|
|
133
136
|
</Layer>
|
|
134
137
|
</Column>
|
|
135
|
-
|
|
136
138
|
<Column>
|
|
137
139
|
<Layer className={styles.input}>
|
|
138
|
-
<
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
<SelectItem
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
lowContrast={true}
|
|
159
|
-
title={t('missingLocation', 'Missing location')}
|
|
160
|
-
subtitle={t('pleaseSelectLocation', 'Please select a location')}
|
|
161
|
-
/>
|
|
162
|
-
</section>
|
|
163
|
-
)}
|
|
140
|
+
<Controller
|
|
141
|
+
name="userLocation"
|
|
142
|
+
control={control}
|
|
143
|
+
render={({ field }) => (
|
|
144
|
+
<Select
|
|
145
|
+
{...field}
|
|
146
|
+
id="location"
|
|
147
|
+
invalid={!!errors?.userLocation}
|
|
148
|
+
invalidText={errors?.userLocation?.message}
|
|
149
|
+
labelText={t('selectALocation', 'Select a location')}>
|
|
150
|
+
<SelectItem text={t('selectALocation', 'Select a location')} value="" />
|
|
151
|
+
{queueLocations?.length > 0 &&
|
|
152
|
+
queueLocations.map((location) => (
|
|
153
|
+
<SelectItem key={location.id} text={location.name} value={location.id}>
|
|
154
|
+
{location.name}
|
|
155
|
+
</SelectItem>
|
|
156
|
+
))}
|
|
157
|
+
</Select>
|
|
158
|
+
)}
|
|
159
|
+
/>
|
|
164
160
|
</Layer>
|
|
165
161
|
</Column>
|
|
166
162
|
</Stack>
|
|
@@ -168,8 +164,12 @@ const QueueServiceForm: React.FC<DefaultWorkspaceProps> = ({ closeWorkspace }) =
|
|
|
168
164
|
<Button className={styles.button} kind="secondary" onClick={closeWorkspace}>
|
|
169
165
|
{t('cancel', 'Cancel')}
|
|
170
166
|
</Button>
|
|
171
|
-
<Button className={styles.button} kind="primary" type="submit">
|
|
172
|
-
{
|
|
167
|
+
<Button className={styles.button} disabled={isSubmitting} kind="primary" type="submit">
|
|
168
|
+
{isSubmitting ? (
|
|
169
|
+
<InlineLoading description={t('saving', 'Saving') + '...'} />
|
|
170
|
+
) : (
|
|
171
|
+
<span>{t('save', 'Save')}</span>
|
|
172
|
+
)}
|
|
173
173
|
</Button>
|
|
174
174
|
</ButtonSet>
|
|
175
175
|
</Form>
|
|
@@ -12,7 +12,12 @@ export function useServiceConcepts() {
|
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export function saveQueue(
|
|
15
|
+
export function saveQueue(
|
|
16
|
+
queueName: string,
|
|
17
|
+
queueServiceType: string,
|
|
18
|
+
queueDescription?: string,
|
|
19
|
+
queueLocation?: string,
|
|
20
|
+
) {
|
|
16
21
|
const abortController = new AbortController();
|
|
17
22
|
|
|
18
23
|
return openmrsFetch(`${restBaseUrl}/queue`, {
|
|
@@ -24,7 +29,7 @@ export function saveQueue(queueName: string, queueConcept: string, queueDescript
|
|
|
24
29
|
body: {
|
|
25
30
|
name: queueName,
|
|
26
31
|
description: queueDescription,
|
|
27
|
-
service: { uuid:
|
|
32
|
+
service: { uuid: queueServiceType },
|
|
28
33
|
location: {
|
|
29
34
|
uuid: queueLocation,
|
|
30
35
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { showToast, translateFrom, useConfig } from '@openmrs/esm-framework';
|
|
2
1
|
import { useMemo } from 'react';
|
|
2
|
+
import { showToast, useConfig } from '@openmrs/esm-framework';
|
|
3
3
|
import { useTranslation, type TFunction } from 'react-i18next';
|
|
4
4
|
import {
|
|
5
5
|
builtInColumns,
|
|
@@ -30,11 +30,14 @@ export function useColumns(queue: string, status: string): QueueTableColumn[] {
|
|
|
30
30
|
const config = useConfig<ConfigObject>();
|
|
31
31
|
const { queueTables, visitQueueNumberAttributeUuid } = config;
|
|
32
32
|
const { columnDefinitions } = queueTables;
|
|
33
|
-
const tableDefinitions = [...queueTables.tableDefinitions, defaultQueueTable];
|
|
34
|
-
const globalColumnConfig =
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
const tableDefinitions = useMemo(() => [...queueTables.tableDefinitions, defaultQueueTable], [queueTables]);
|
|
34
|
+
const globalColumnConfig = useMemo(
|
|
35
|
+
() => ({
|
|
36
|
+
...defaultColumnConfig,
|
|
37
|
+
visitQueueNumberAttributeUuid,
|
|
38
|
+
}),
|
|
39
|
+
[visitQueueNumberAttributeUuid],
|
|
40
|
+
);
|
|
38
41
|
|
|
39
42
|
const columnsMap = useMemo(() => {
|
|
40
43
|
const map = new Map<string, QueueTableColumn>();
|
|
@@ -49,7 +52,7 @@ export function useColumns(queue: string, status: string): QueueTableColumn[] {
|
|
|
49
52
|
map.set(columnDef.id, getColumnFromDefinition(t, columnDef));
|
|
50
53
|
}
|
|
51
54
|
return map;
|
|
52
|
-
}, [columnDefinitions, t]);
|
|
55
|
+
}, [columnDefinitions, globalColumnConfig, t, visitQueueNumberAttributeUuid]);
|
|
53
56
|
|
|
54
57
|
const tableDefinition = useMemo(
|
|
55
58
|
() =>
|
|
@@ -15,6 +15,7 @@ export const queueTableVisitAttributeQueueNumberColumn: QueueTableColumnFunction
|
|
|
15
15
|
|
|
16
16
|
const QueueTableVisitAttributeQueueNumberCell = ({ queueEntry }: QueueTableCellComponentProps) => {
|
|
17
17
|
const { t } = useTranslation();
|
|
18
|
+
|
|
18
19
|
return (
|
|
19
20
|
<>
|
|
20
21
|
{visitQueueNumberAttributeUuid ? (
|
|
@@ -27,13 +27,15 @@ import QueueTableExpandedRow from './queue-table-expanded-row.component';
|
|
|
27
27
|
import QueueTable from './queue-table.component';
|
|
28
28
|
import styles from './queue-table.scss';
|
|
29
29
|
|
|
30
|
-
const serviceQueuesPatientSearchWorkspace = '
|
|
30
|
+
const serviceQueuesPatientSearchWorkspace = 'create-queue-entry-workspace';
|
|
31
31
|
|
|
32
32
|
/*
|
|
33
33
|
Component with default values / sub-components passed into the more generic QueueTable.
|
|
34
34
|
This is used in the main dashboard of the queues app. (Currently behind a feature flag)
|
|
35
35
|
*/
|
|
36
36
|
function DefaultQueueTable() {
|
|
37
|
+
const { t } = useTranslation();
|
|
38
|
+
const layout = useLayoutType();
|
|
37
39
|
const selectedService = useSelectedService();
|
|
38
40
|
const currentLocationUuid = useSelectedQueueLocationUuid();
|
|
39
41
|
const selectedQueueStatus = useSelectedQueueStatus();
|
|
@@ -48,8 +50,6 @@ function DefaultQueueTable() {
|
|
|
48
50
|
);
|
|
49
51
|
const { queueEntries, isLoading, error, isValidating } = useQueueEntries(searchCriteria);
|
|
50
52
|
|
|
51
|
-
const { t } = useTranslation();
|
|
52
|
-
|
|
53
53
|
useEffect(() => {
|
|
54
54
|
if (error?.message) {
|
|
55
55
|
showSnackbar({
|
|
@@ -58,11 +58,10 @@ function DefaultQueueTable() {
|
|
|
58
58
|
subtitle: error?.message,
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
|
-
}, [error?.message]);
|
|
62
|
-
const layout = useLayoutType();
|
|
61
|
+
}, [error?.message, t]);
|
|
63
62
|
|
|
64
63
|
const [isPatientSearchOpen, setIsPatientSearchOpen] = useState(false);
|
|
65
|
-
const [patientSearchQuery, setPatientSearchQuery] = useState
|
|
64
|
+
const [patientSearchQuery, setPatientSearchQuery] = useState('');
|
|
66
65
|
|
|
67
66
|
const handleBackToSearchList = useCallback(() => {
|
|
68
67
|
setIsPatientSearchOpen(true);
|
|
@@ -88,7 +87,7 @@ function DefaultQueueTable() {
|
|
|
88
87
|
return columnSearchTerm?.includes(searchTermLowercase);
|
|
89
88
|
});
|
|
90
89
|
});
|
|
91
|
-
}, [queueEntries, searchTerm]);
|
|
90
|
+
}, [columns, queueEntries, searchTerm]);
|
|
92
91
|
|
|
93
92
|
return (
|
|
94
93
|
<div className={styles.defaultQueueTable}>
|
|
@@ -172,13 +171,13 @@ function QueueDropdownFilter() {
|
|
|
172
171
|
<div className={styles.filterContainer}>
|
|
173
172
|
<Dropdown
|
|
174
173
|
id="serviceFilter"
|
|
175
|
-
titleText={t('filterByService', 'Filter by service:')}
|
|
176
|
-
label={selectedService?.serviceDisplay ?? t('all', 'All')}
|
|
177
|
-
type="inline"
|
|
178
174
|
items={[{ display: `${t('all', 'All')}` }, ...(services ?? [])]}
|
|
179
175
|
itemToString={(item) => (item ? item.display : '')}
|
|
176
|
+
label={selectedService?.serviceDisplay ?? t('all', 'All')}
|
|
180
177
|
onChange={handleServiceChange}
|
|
181
178
|
size={isDesktop(layout) ? 'sm' : 'lg'}
|
|
179
|
+
titleText={t('filterByService', 'Filter by service:')}
|
|
180
|
+
type="inline"
|
|
182
181
|
/>
|
|
183
182
|
</div>
|
|
184
183
|
</>
|
|
@@ -199,13 +198,13 @@ function StatusDropdownFilter() {
|
|
|
199
198
|
<div className={styles.filterContainer}>
|
|
200
199
|
<Dropdown
|
|
201
200
|
id="statusFilter"
|
|
202
|
-
titleText={t('filterByStatus', 'Filter by status:')}
|
|
203
|
-
label={queueStatus?.statusDisplay ?? t('all', 'All')}
|
|
204
|
-
type="inline"
|
|
205
201
|
items={[{ display: `${t('all', 'All')}` }, ...(statuses ?? [])]}
|
|
206
202
|
itemToString={(item) => (item ? item.display : '')}
|
|
203
|
+
label={queueStatus?.statusDisplay ?? t('all', 'All')}
|
|
207
204
|
onChange={handleServiceChange}
|
|
208
205
|
size={isDesktop(layout) ? 'sm' : 'lg'}
|
|
206
|
+
titleText={t('filterByStatus', 'Filter by status:')}
|
|
207
|
+
type="inline"
|
|
209
208
|
/>
|
|
210
209
|
</div>
|
|
211
210
|
</>
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import { renderWithSwr } from 'tools';
|
|
14
14
|
import { useQueueEntries } from '../hooks/useQueueEntries';
|
|
15
15
|
import { useQueueRooms } from '../add-provider-queue-room/add-provider-queue-room.resource';
|
|
16
|
-
import { useQueueLocations } from '../
|
|
16
|
+
import { useQueueLocations } from '../create-queue-entry/hooks/useQueueLocations';
|
|
17
17
|
import { type ConfigObject, configSchema } from '../config-schema';
|
|
18
18
|
import DefaultQueueTable from '../queue-table/default-queue-table.component';
|
|
19
19
|
|
|
@@ -29,8 +29,8 @@ jest.mock('../hooks/useQueues', () => {
|
|
|
29
29
|
};
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
jest.mock('../
|
|
33
|
-
...jest.requireActual('../
|
|
32
|
+
jest.mock('../create-queue-entry/hooks/useQueueLocations', () => ({
|
|
33
|
+
...jest.requireActual('../create-queue-entry/hooks/useQueueLocations'),
|
|
34
34
|
useQueueLocations: jest.fn(),
|
|
35
35
|
}));
|
|
36
36
|
|
|
@@ -34,3 +34,31 @@ section {
|
|
|
34
34
|
.dateTimeFields {
|
|
35
35
|
display: flex;
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
.modalHeader {
|
|
39
|
+
:global {
|
|
40
|
+
.cds--modal-close-button {
|
|
41
|
+
position: absolute;
|
|
42
|
+
inset-block-start: 0;
|
|
43
|
+
inset-inline-end: 0;
|
|
44
|
+
margin: 0;
|
|
45
|
+
margin-top: calc(-1 * #{layout.$spacing-05});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.cds--modal-close {
|
|
49
|
+
background-color: rgba(0, 0, 0, 0);
|
|
50
|
+
|
|
51
|
+
&:hover {
|
|
52
|
+
background-color: var(--cds-layer-hover);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.cds--popover--left > .cds--popover > .cds--popover-content {
|
|
57
|
+
transform: translate(-4rem, 0.85rem);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.cds--popover--left > .cds--popover > .cds--popover-caret {
|
|
61
|
+
transform: translate(-3.75rem, 1.25rem);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -198,13 +198,19 @@ export const QueueEntryActionModal: React.FC<QueueEntryActionModalProps> = ({
|
|
|
198
198
|
);
|
|
199
199
|
}
|
|
200
200
|
return null;
|
|
201
|
-
}, [
|
|
201
|
+
}, [
|
|
202
|
+
formState.transitionDate,
|
|
203
|
+
formState.transitionTime,
|
|
204
|
+
formState.transitionTimeFormat,
|
|
205
|
+
queueEntry.previousQueueEntry?.startedAt,
|
|
206
|
+
t,
|
|
207
|
+
]);
|
|
202
208
|
|
|
203
209
|
const selectedPriorityIndex = priorities?.findIndex((p) => p.uuid == formState.selectedPriority);
|
|
204
210
|
|
|
205
211
|
return (
|
|
206
212
|
<>
|
|
207
|
-
<ModalHeader closeModal={closeModal} title={modalTitle} />
|
|
213
|
+
<ModalHeader className={styles.modalHeader} closeModal={closeModal} title={modalTitle} />
|
|
208
214
|
<ModalBody>
|
|
209
215
|
<div className={styles.queueEntryActionModalBody}>
|
|
210
216
|
<Stack gap={4}>
|
|
@@ -4,6 +4,7 @@ import { type QueueEntry } from '../../types';
|
|
|
4
4
|
import { Button, ModalHeader, ModalBody, ModalFooter, Stack } from '@carbon/react';
|
|
5
5
|
import { type FetchResponse, showSnackbar } from '@openmrs/esm-framework';
|
|
6
6
|
import { useMutateQueueEntries } from '../../hooks/useQueueEntries';
|
|
7
|
+
import styles from './queue-entry-confirm-action.scss';
|
|
7
8
|
|
|
8
9
|
interface QueueEntryUndoActionsModalProps {
|
|
9
10
|
queueEntry: QueueEntry;
|
|
@@ -75,7 +76,7 @@ export const QueueEntryConfirmActionModal: React.FC<QueueEntryUndoActionsModalPr
|
|
|
75
76
|
|
|
76
77
|
return (
|
|
77
78
|
<>
|
|
78
|
-
<ModalHeader closeModal={closeModal} title={modalTitle} />
|
|
79
|
+
<ModalHeader className={styles.modalHeader} closeModal={closeModal} title={modalTitle} />
|
|
79
80
|
<ModalBody>
|
|
80
81
|
<Stack gap={4}>
|
|
81
82
|
<h5>{queueEntry.display}</h5>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
@use '@carbon/layout';
|
|
2
|
+
|
|
3
|
+
.modalHeader {
|
|
4
|
+
:global {
|
|
5
|
+
.cds--modal-close-button {
|
|
6
|
+
position: absolute;
|
|
7
|
+
inset-block-start: 0;
|
|
8
|
+
inset-inline-end: 0;
|
|
9
|
+
margin: 0;
|
|
10
|
+
margin-top: calc(-1 * #{layout.$spacing-05});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.cds--modal-close {
|
|
14
|
+
background-color: rgba(0, 0, 0, 0);
|
|
15
|
+
|
|
16
|
+
&:hover {
|
|
17
|
+
background-color: var(--cds-layer-hover);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.cds--popover--left > .cds--popover > .cds--popover-content {
|
|
22
|
+
transform: translate(-4rem, 0.85rem);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.cds--popover--left > .cds--popover > .cds--popover-caret {
|
|
26
|
+
transform: translate(-3.75rem, 1.25rem);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -192,13 +192,12 @@ html[dir='rtl'] {
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
.tileContainer {
|
|
195
|
-
background-color: $ui-02;
|
|
196
195
|
border-top: 1px solid $ui-03;
|
|
197
196
|
padding: layout.$spacing-07 0;
|
|
198
|
-
// margin: 0 layout.$spacing-05;
|
|
199
197
|
}
|
|
200
198
|
|
|
201
199
|
.tile {
|
|
200
|
+
background-color: $ui-01;
|
|
202
201
|
margin: auto;
|
|
203
202
|
width: fit-content;
|
|
204
203
|
}
|
|
@@ -209,3 +208,14 @@ html[dir='rtl'] {
|
|
|
209
208
|
justify-content: center;
|
|
210
209
|
align-items: center;
|
|
211
210
|
}
|
|
211
|
+
|
|
212
|
+
.content {
|
|
213
|
+
@include type.type-style('heading-compact-02');
|
|
214
|
+
color: $text-02;
|
|
215
|
+
margin-bottom: layout.$spacing-03;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.helper {
|
|
219
|
+
@include type.type-style('body-compact-01');
|
|
220
|
+
color: $text-02;
|
|
221
|
+
}
|
|
@@ -3,7 +3,7 @@ import React from 'react';
|
|
|
3
3
|
import { getDefaultsFromConfigSchema, useConfig, useSession } from '@openmrs/esm-framework';
|
|
4
4
|
import { screen, within } from '@testing-library/react';
|
|
5
5
|
import { type ConfigObject, configSchema } from '../config-schema';
|
|
6
|
-
import { mockPriorityNonUrgent, mockQueueEntries, mockSession } from '__mocks__';
|
|
6
|
+
import { mockPriorityNonUrgent, mockPriorityUrgent, mockQueueEntries, mockSession } from '__mocks__';
|
|
7
7
|
import { renderWithSwr } from 'tools';
|
|
8
8
|
import QueueTable from './queue-table.component';
|
|
9
9
|
|
|
@@ -176,6 +176,11 @@ describe('QueueTable', () => {
|
|
|
176
176
|
color: 'blue',
|
|
177
177
|
style: 'bold',
|
|
178
178
|
},
|
|
179
|
+
{
|
|
180
|
+
conceptUuid: mockPriorityUrgent.uuid,
|
|
181
|
+
color: 'orange',
|
|
182
|
+
style: null,
|
|
183
|
+
},
|
|
179
184
|
],
|
|
180
185
|
statusConfigs: [],
|
|
181
186
|
visitQueueNumberAttributeUuid: 'queue-number-visit-attr-uuid',
|
|
@@ -200,6 +205,10 @@ describe('QueueTable', () => {
|
|
|
200
205
|
const firstRow = rows[1];
|
|
201
206
|
const cells = within(firstRow).getAllByRole('cell');
|
|
202
207
|
expect(cells[1].childNodes[0]).toHaveClass('bold');
|
|
208
|
+
|
|
209
|
+
const secondRow = rows[2];
|
|
210
|
+
const secondCells = within(secondRow).getAllByRole('cell');
|
|
211
|
+
expect(secondCells[1].childNodes[0]).toHaveClass('orange');
|
|
203
212
|
});
|
|
204
213
|
|
|
205
214
|
it('uses the visitQueueNumberAttributeUuid defined at the top level', () => {
|