@kenyaemr/esm-service-queues-app 7.0.2-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 +40 -0
- package/README.md +20 -0
- package/dist/130.js +2 -0
- package/dist/130.js.LICENSE.txt +3 -0
- package/dist/130.js.map +1 -0
- package/dist/152.js +1 -0
- package/dist/152.js.map +1 -0
- package/dist/169.js +1 -0
- package/dist/169.js.map +1 -0
- package/dist/185.js +1 -0
- package/dist/185.js.map +1 -0
- package/dist/233.js +1 -0
- package/dist/233.js.map +1 -0
- package/dist/237.js +1 -0
- package/dist/237.js.map +1 -0
- package/dist/255.js +2 -0
- package/dist/255.js.LICENSE.txt +9 -0
- package/dist/255.js.map +1 -0
- package/dist/271.js +1 -0
- package/dist/276.js +1 -0
- package/dist/276.js.map +1 -0
- package/dist/303.js +1 -0
- package/dist/303.js.map +1 -0
- package/dist/319.js +1 -0
- package/dist/401.js +1 -0
- package/dist/401.js.map +1 -0
- package/dist/430.js +2 -0
- package/dist/430.js.LICENSE.txt +50 -0
- package/dist/430.js.map +1 -0
- package/dist/460.js +1 -0
- package/dist/501.js +1 -0
- package/dist/501.js.map +1 -0
- package/dist/574.js +1 -0
- package/dist/591.js +2 -0
- package/dist/591.js.LICENSE.txt +32 -0
- package/dist/591.js.map +1 -0
- package/dist/644.js +1 -0
- package/dist/647.js +1 -0
- package/dist/647.js.map +1 -0
- package/dist/650.js +1 -0
- package/dist/650.js.map +1 -0
- package/dist/669.js +1 -0
- package/dist/669.js.map +1 -0
- package/dist/696.js +1 -0
- package/dist/696.js.map +1 -0
- package/dist/703.js +1 -0
- package/dist/703.js.map +1 -0
- package/dist/729.js +1 -0
- package/dist/729.js.map +1 -0
- package/dist/738.js +1 -0
- package/dist/738.js.map +1 -0
- package/dist/757.js +1 -0
- package/dist/764.js +1 -0
- package/dist/764.js.map +1 -0
- package/dist/784.js +2 -0
- package/dist/784.js.LICENSE.txt +9 -0
- package/dist/784.js.map +1 -0
- package/dist/788.js +1 -0
- package/dist/806.js +1 -0
- package/dist/806.js.map +1 -0
- package/dist/807.js +1 -0
- package/dist/833.js +1 -0
- package/dist/877.js +1 -0
- package/dist/877.js.map +1 -0
- package/dist/917.js +1 -0
- package/dist/917.js.map +1 -0
- package/dist/940.js +1 -0
- package/dist/940.js.map +1 -0
- package/dist/981.js +1 -0
- package/dist/981.js.map +1 -0
- package/dist/kenyaemr-esm-service-queues-app.js +1 -0
- package/dist/kenyaemr-esm-service-queues-app.js.buildmanifest.json +965 -0
- package/dist/kenyaemr-esm-service-queues-app.js.map +1 -0
- package/dist/main.js +2 -0
- package/dist/main.js.LICENSE.txt +60 -0
- package/dist/main.js.map +1 -0
- package/dist/routes.json +1 -0
- package/jest.config.js +3 -0
- package/package.json +54 -0
- package/src/active-visits/active-visits-row-actions.component.tsx +25 -0
- package/src/active-visits/active-visits-row-actions.scss +4 -0
- package/src/active-visits/active-visits-table.resource.ts +273 -0
- package/src/active-visits/change-status-dialog.component.tsx +272 -0
- package/src/active-visits/change-status-dialog.scss +47 -0
- package/src/active-visits/change-status-dialog.test.tsx +154 -0
- package/src/add-patient-toqueue/add-patient-toqueue-dialog.component.tsx +228 -0
- package/src/add-patient-toqueue/add-patient-toqueue-dialog.scss +32 -0
- package/src/add-provider-queue-room/add-provider-queue-room.component.tsx +238 -0
- package/src/add-provider-queue-room/add-provider-queue-room.resource.ts +76 -0
- package/src/add-provider-queue-room/add-provider-queue-room.scss +17 -0
- package/src/add-provider-queue-room/add-provider-queue-room.test.tsx +105 -0
- package/src/clear-queue-entries-dialog/clear-queue-entries-dialog.component.tsx +76 -0
- package/src/clear-queue-entries-dialog/clear-queue-entries-dialog.resource.ts +7 -0
- package/src/clear-queue-entries-dialog/clear-queue-entries-dialog.scss +8 -0
- package/src/clear-queue-entries-dialog/clear-queue-entries-dialog.test.tsx +43 -0
- package/src/clear-queue-entries-dialog/clear-queue-entries.component.tsx +43 -0
- package/src/config-schema.ts +465 -0
- package/src/constants.ts +10 -0
- package/src/createDashboardLink.component.tsx +39 -0
- package/src/current-visit/current-visit-summary.component.tsx +38 -0
- package/src/current-visit/current-visit-summary.test.tsx +43 -0
- package/src/current-visit/current-visit.resource.ts +84 -0
- package/src/current-visit/current-visit.scss +34 -0
- package/src/current-visit/hooks/useVitalsConceptMetadata.tsx +101 -0
- package/src/current-visit/visit-details/biometrics-config-schema.ts +14 -0
- package/src/current-visit/visit-details/current-visit-details.component.tsx +96 -0
- package/src/current-visit/visit-details/triage-note.component.tsx +53 -0
- package/src/current-visit/visit-details/triage-note.scss +89 -0
- package/src/current-visit/visit-details/vitals-config-schema.ts +17 -0
- package/src/current-visit/visit-details/vitals.component.tsx +165 -0
- package/src/dashboard.meta.ts +5 -0
- package/src/declarations.d.ts +4 -0
- package/src/helpers/functions.ts +28 -0
- package/src/helpers/helpers.ts +177 -0
- package/src/helpers/time-helpers.ts +15 -0
- package/src/home.component.tsx +16 -0
- package/src/home.test.tsx +48 -0
- package/src/hooks/useConcept.ts +13 -0
- package/src/hooks/useQueue.ts +10 -0
- package/src/hooks/useQueueEntries.ts +187 -0
- package/src/hooks/useQueues.ts +22 -0
- package/src/hooks/useSystemSetting.ts +18 -0
- package/src/index.ts +172 -0
- package/src/past-visit/past-visit-details/encounter-list.component.tsx +54 -0
- package/src/past-visit/past-visit-details/medications-list.component.tsx +98 -0
- package/src/past-visit/past-visit-details/notes-list.component.tsx +41 -0
- package/src/past-visit/past-visit-details/past-visit-summary.component.tsx +181 -0
- package/src/past-visit/past-visit-details/past-visit-summary.scss +58 -0
- package/src/past-visit/past-visit.component.tsx +37 -0
- package/src/past-visit/past-visit.resource.ts +83 -0
- package/src/past-visit/past-visit.scss +126 -0
- package/src/past-visit/past-visit.test.tsx +41 -0
- package/src/patient-info/appointment-details.component.tsx +98 -0
- package/src/patient-info/appointment-details.scss +34 -0
- package/src/patient-info/appointment-details.test.tsx +36 -0
- package/src/patient-info/appointments.resource.ts +43 -0
- package/src/patient-info/hooks/usePatientAttributes.tsx +42 -0
- package/src/patient-info/patient-info.component.tsx +82 -0
- package/src/patient-info/patient-info.scss +60 -0
- package/src/patient-info/patient-info.test.tsx +43 -0
- package/src/patient-queue-header/patient-queue-header.component.tsx +99 -0
- package/src/patient-queue-header/patient-queue-header.scss +90 -0
- package/src/patient-queue-header/patient-queue-illustration.component.tsx +22 -0
- package/src/patient-queue-metrics/clinic-metrics.component.tsx +98 -0
- package/src/patient-queue-metrics/clinic-metrics.resource.ts +58 -0
- package/src/patient-queue-metrics/clinic-metrics.scss +11 -0
- package/src/patient-queue-metrics/clinic-metrics.test.tsx +76 -0
- package/src/patient-queue-metrics/metrics-card.component.tsx +68 -0
- package/src/patient-queue-metrics/metrics-card.scss +80 -0
- package/src/patient-queue-metrics/metrics-header.component.tsx +61 -0
- package/src/patient-queue-metrics/metrics-header.scss +26 -0
- package/src/patient-queue-metrics/queue-metrics.resource.ts +42 -0
- package/src/patient-search/advanced-search.component.tsx +191 -0
- package/src/patient-search/advanced-search.scss +154 -0
- package/src/patient-search/advanced-search.test.tsx +29 -0
- package/src/patient-search/basic-search.component.tsx +112 -0
- package/src/patient-search/basic-search.scss +139 -0
- package/src/patient-search/basic-search.test.tsx +23 -0
- package/src/patient-search/empty-data-illustration.component.tsx +41 -0
- package/src/patient-search/hooks/useActivePatientEnrollment.tsx +29 -0
- package/src/patient-search/hooks/useDefaultLocation.ts +14 -0
- package/src/patient-search/hooks/usePatients.tsx +25 -0
- package/src/patient-search/hooks/useQueueLocations.tsx +23 -0
- package/src/patient-search/hooks/useRecommendedVisitTypes.tsx +35 -0
- package/src/patient-search/hooks/useScheduledVisits.ts +52 -0
- package/src/patient-search/patient-scheduled-visits.component.tsx +324 -0
- package/src/patient-search/patient-scheduled-visits.scss +131 -0
- package/src/patient-search/patient-scheduled-visits.test.tsx +44 -0
- package/src/patient-search/patient-search.scss +43 -0
- package/src/patient-search/patient-search.workspace.tsx +135 -0
- package/src/patient-search/search-illustration.component.tsx +27 -0
- package/src/patient-search/search-results.component.tsx +75 -0
- package/src/patient-search/search-results.scss +80 -0
- package/src/patient-search/search-results.test.tsx +77 -0
- package/src/patient-search/search.resource.ts +10 -0
- package/src/patient-search/visit-form/existing-visit-form.component.tsx +112 -0
- package/src/patient-search/visit-form/queue.resource.ts +64 -0
- package/src/patient-search/visit-form/visit-form.component.tsx +344 -0
- package/src/patient-search/visit-form/visit-form.scss +73 -0
- package/src/patient-search/visit-form/visit-type-selector.component.tsx +155 -0
- package/src/patient-search/visit-form/visit-type-selector.scss +100 -0
- package/src/patient-search/visit-form/visit-type-selector.test.tsx +83 -0
- package/src/patient-search/visit-form-queue-fields/visit-form-queue-fields.component.tsx +178 -0
- package/src/patient-search/visit-form-queue-fields/visit-form-queue-fields.scss +19 -0
- package/src/patient-search/visit-form-queue-fields/visit-form-queue-fields.test.tsx +63 -0
- package/src/queue-entry-table-components/edit-entry.scss +14 -0
- package/src/queue-entry-table-components/queue-duration.component.tsx +41 -0
- package/src/queue-entry-table-components/queue-priority.component.tsx +38 -0
- package/src/queue-entry-table-components/queue-priority.scss +12 -0
- package/src/queue-entry-table-components/queue-status.component.tsx +39 -0
- package/src/queue-entry-table-components/transition-entry.component.tsx +55 -0
- package/src/queue-entry-table-components/transition-entry.scss +22 -0
- package/src/queue-patient-linelists/queue-linelist-base-table.component.tsx +241 -0
- package/src/queue-patient-linelists/queue-linelist-base-table.scss +110 -0
- package/src/queue-patient-linelists/queue-linelist-base-table.test.tsx +93 -0
- package/src/queue-patient-linelists/queue-linelist-filter.scss +63 -0
- package/src/queue-patient-linelists/queue-linelist-filter.test.tsx +94 -0
- package/src/queue-patient-linelists/queue-linelist-filter.workspace.tsx +185 -0
- package/src/queue-patient-linelists/queue-linelist.resource.ts +84 -0
- package/src/queue-patient-linelists/queue-services-table.component.tsx +63 -0
- package/src/queue-patient-linelists/scheduled-appointments-table.component.tsx +305 -0
- package/src/queue-patient-linelists/scheduled-appointments-table.test.tsx +41 -0
- package/src/queue-rooms/queue-room-form.scss +56 -0
- package/src/queue-rooms/queue-room-form.test.tsx +80 -0
- package/src/queue-rooms/queue-room-form.workspace.tsx +169 -0
- package/src/queue-rooms/queue-room.resource.ts +20 -0
- package/src/queue-screen/queue-screen.component.tsx +47 -0
- package/src/queue-screen/queue-screen.scss +39 -0
- package/src/queue-screen/queue-screen.test.tsx +51 -0
- package/src/queue-screen/useActiveTickets.tsx +13 -0
- package/src/queue-services/queue-service-form.scss +61 -0
- package/src/queue-services/queue-service-form.test.tsx +60 -0
- package/src/queue-services/queue-service-form.workspace.tsx +179 -0
- package/src/queue-services/queue-service.resource.ts +33 -0
- package/src/queue-table/cells/columns.resource.ts +135 -0
- package/src/queue-table/cells/queue-table-action-cell.component.tsx +88 -0
- package/src/queue-table/cells/queue-table-action-cell.scss +7 -0
- package/src/queue-table/cells/queue-table-coming-from-cell.component.tsx +13 -0
- package/src/queue-table/cells/queue-table-extension-cell.component.tsx +16 -0
- package/src/queue-table/cells/queue-table-name-cell.component.tsx +20 -0
- package/src/queue-table/cells/queue-table-patient-age-cell.component.tsx +18 -0
- package/src/queue-table/cells/queue-table-patient-identifier-cell.component.tsx +25 -0
- package/src/queue-table/cells/queue-table-priority-cell.component.tsx +23 -0
- package/src/queue-table/cells/queue-table-queue-name-cell.component.tsx +14 -0
- package/src/queue-table/cells/queue-table-status-cell.component.tsx +18 -0
- package/src/queue-table/cells/queue-table-visit-attribute-queue-number-cell.component.tsx +37 -0
- package/src/queue-table/cells/queue-table-visit-start-time-cell.component.tsx +20 -0
- package/src/queue-table/cells/queue-table-wait-time-cell.component.tsx +17 -0
- package/src/queue-table/default-queue-table.component.tsx +174 -0
- package/src/queue-table/default-queue-table.test.tsx +131 -0
- package/src/queue-table/queue-entry-actions/edit-queue-entry-modal.component.tsx +52 -0
- package/src/queue-table/queue-entry-actions/end-queue-entry-modal.component.tsx +39 -0
- package/src/queue-table/queue-entry-actions/queue-entry-actions-modal.component.tsx +362 -0
- package/src/queue-table/queue-entry-actions/queue-entry-actions-modal.test.tsx +152 -0
- package/src/queue-table/queue-entry-actions/queue-entry-actions.resource.ts +83 -0
- package/src/queue-table/queue-entry-actions/queue-entry-actons-modal.scss +36 -0
- package/src/queue-table/queue-entry-actions/queue-entry-confirm-action-modal.component.tsx +97 -0
- package/src/queue-table/queue-entry-actions/queue-entry-confirm-action-modal.test.tsx +106 -0
- package/src/queue-table/queue-entry-actions/queue-entry-undo-actions-modal.test.tsx +76 -0
- package/src/queue-table/queue-entry-actions/transition-queue-entry-modal.component.tsx +51 -0
- package/src/queue-table/queue-entry-actions/undo-transition-queue-entry-modal.component.tsx +58 -0
- package/src/queue-table/queue-entry-actions/void-queue-entry-modal.component.tsx +34 -0
- package/src/queue-table/queue-table-by-status-menu.component.tsx +42 -0
- package/src/queue-table/queue-table-by-status-menu.scss +11 -0
- package/src/queue-table/queue-table-by-status-skeleton.component.tsx +32 -0
- package/src/queue-table/queue-table-by-status.component.tsx +96 -0
- package/src/queue-table/queue-table-expanded-row.component.tsx +29 -0
- package/src/queue-table/queue-table-metrics-card.component.tsx +50 -0
- package/src/queue-table/queue-table-metrics-card.scss +48 -0
- package/src/queue-table/queue-table-metrics.component.tsx +30 -0
- package/src/queue-table/queue-table-metrics.scss +11 -0
- package/src/queue-table/queue-table.component.tsx +179 -0
- package/src/queue-table/queue-table.scss +192 -0
- package/src/queue-table/queue-table.test.tsx +210 -0
- package/src/remove-queue-entry-dialog/remove-queue-entry.component.tsx +87 -0
- package/src/remove-queue-entry-dialog/remove-queue-entry.resource.ts +93 -0
- package/src/remove-queue-entry-dialog/remove-queue-entry.scss +7 -0
- package/src/remove-queue-entry-dialog/remove-queue-entry.test.tsx +45 -0
- package/src/root.component.tsx +28 -0
- package/src/root.scss +15 -0
- package/src/root.test.tsx +24 -0
- package/src/routes.json +133 -0
- package/src/side-menu/nav-group/createNavGroup.tsx +17 -0
- package/src/side-menu/nav-group/nav-group.component.tsx +24 -0
- package/src/side-menu/nav-group/nav-group.test.tsx +32 -0
- package/src/side-menu/nav-group/nav-group.ts +10 -0
- package/src/side-menu/side-menu.component.tsx +6 -0
- package/src/side-menu/side-menu.test.tsx +17 -0
- package/src/transition-queue-entry/transition-queue-entry-dialog.component.tsx +134 -0
- package/src/transition-queue-entry/transition-queue-entry-dialog.scss +12 -0
- package/src/transition-queue-entry/transition-queue-entry-dialog.test.tsx +102 -0
- package/src/transition-queue-entry/transition-queue-entry.resource.ts +16 -0
- package/src/types/index.ts +494 -0
- package/src/views/queue-table-by-status-view.component.tsx +25 -0
- package/src/views/queue-tables-for-all-statuses.component.tsx +150 -0
- package/src/visits-missing-inqueue/visits-missing-inqueue.component.tsx +277 -0
- package/src/visits-missing-inqueue/visits-missing-inqueue.resource.ts +93 -0
- package/src/visits-missing-inqueue/visits-missing-inqueue.scss +108 -0
- package/translations/am.json +295 -0
- package/translations/ar.json +295 -0
- package/translations/en.json +305 -0
- package/translations/es.json +295 -0
- package/translations/fr.json +295 -0
- package/translations/he.json +295 -0
- package/translations/km.json +295 -0
- package/translations/zh.json +295 -0
- package/translations/zh_CN.json +295 -0
- package/tsconfig.json +5 -0
- package/webpack.config.js +1 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import React, { type ReactNode, useState } from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { type QueueEntry } from '../../types';
|
|
4
|
+
import { Button, ModalHeader, ModalBody, ModalFooter, Stack } from '@carbon/react';
|
|
5
|
+
import { type FetchResponse, showSnackbar } from '@openmrs/esm-framework';
|
|
6
|
+
import { useMutateQueueEntries } from '../../hooks/useQueueEntries';
|
|
7
|
+
|
|
8
|
+
interface QueueEntryUndoActionsModalProps {
|
|
9
|
+
queueEntry: QueueEntry;
|
|
10
|
+
closeModal: () => void;
|
|
11
|
+
modalParams: ModalParams;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface ModalParams {
|
|
15
|
+
modalTitle: string;
|
|
16
|
+
modalInstruction: ReactNode;
|
|
17
|
+
submitButtonText: string;
|
|
18
|
+
submitSuccessTitle: string;
|
|
19
|
+
submitSuccessText: string;
|
|
20
|
+
submitFailureTitle: string;
|
|
21
|
+
submitAction: (queueEntry: QueueEntry) => Promise<FetchResponse<any>>;
|
|
22
|
+
}
|
|
23
|
+
// Modal for confirming a queue entry action that does not require additional form fields / inputs from user
|
|
24
|
+
// Used by UndoTransitionQueueEntryModal, VoidQueueEntryModal and EndQueueEntryModal
|
|
25
|
+
export const QueueEntryConfirmActionModal: React.FC<QueueEntryUndoActionsModalProps> = ({
|
|
26
|
+
queueEntry,
|
|
27
|
+
closeModal,
|
|
28
|
+
modalParams,
|
|
29
|
+
}) => {
|
|
30
|
+
const { t } = useTranslation();
|
|
31
|
+
const { mutateQueueEntries } = useMutateQueueEntries();
|
|
32
|
+
const {
|
|
33
|
+
modalTitle,
|
|
34
|
+
modalInstruction,
|
|
35
|
+
submitButtonText,
|
|
36
|
+
submitSuccessTitle,
|
|
37
|
+
submitSuccessText,
|
|
38
|
+
submitFailureTitle,
|
|
39
|
+
submitAction,
|
|
40
|
+
} = modalParams;
|
|
41
|
+
|
|
42
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
43
|
+
|
|
44
|
+
const submitForm = (e) => {
|
|
45
|
+
e.preventDefault();
|
|
46
|
+
setIsSubmitting(true);
|
|
47
|
+
|
|
48
|
+
submitAction(queueEntry)
|
|
49
|
+
.then(({ status }) => {
|
|
50
|
+
const success = status >= 200 && status < 300;
|
|
51
|
+
if (success) {
|
|
52
|
+
showSnackbar({
|
|
53
|
+
isLowContrast: true,
|
|
54
|
+
title: submitSuccessTitle,
|
|
55
|
+
kind: 'success',
|
|
56
|
+
subtitle: submitSuccessText,
|
|
57
|
+
});
|
|
58
|
+
mutateQueueEntries();
|
|
59
|
+
closeModal();
|
|
60
|
+
} else {
|
|
61
|
+
throw { message: t('unexpectedServerResponse', 'Unexpected Server Response') };
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
.catch((error) => {
|
|
65
|
+
showSnackbar({
|
|
66
|
+
title: submitFailureTitle,
|
|
67
|
+
kind: 'error',
|
|
68
|
+
subtitle: error?.message,
|
|
69
|
+
});
|
|
70
|
+
})
|
|
71
|
+
.finally(() => {
|
|
72
|
+
setIsSubmitting(false);
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<>
|
|
78
|
+
<ModalHeader closeModal={closeModal} title={modalTitle} />
|
|
79
|
+
<ModalBody>
|
|
80
|
+
<Stack gap={4}>
|
|
81
|
+
<h5>{queueEntry.display}</h5>
|
|
82
|
+
{modalInstruction}
|
|
83
|
+
</Stack>
|
|
84
|
+
</ModalBody>
|
|
85
|
+
<ModalFooter>
|
|
86
|
+
<Button kind="secondary" onClick={closeModal}>
|
|
87
|
+
{t('cancel', 'Cancel')}
|
|
88
|
+
</Button>
|
|
89
|
+
<Button disabled={isSubmitting} onClick={submitForm}>
|
|
90
|
+
{submitButtonText}
|
|
91
|
+
</Button>
|
|
92
|
+
</ModalFooter>
|
|
93
|
+
</>
|
|
94
|
+
);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export default QueueEntryConfirmActionModal;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { openmrsFetch, showSnackbar } from '@openmrs/esm-framework';
|
|
2
|
+
import { screen } from '@testing-library/react';
|
|
3
|
+
import { mockQueues, mockQueueEntryAlice } from '__mocks__';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { renderWithSwr } from 'tools';
|
|
6
|
+
import userEvent from '@testing-library/user-event';
|
|
7
|
+
import UndoTransitionQueueEntryModal from './undo-transition-queue-entry-modal.component';
|
|
8
|
+
import VoidQueueEntryModal from './void-queue-entry-modal.component';
|
|
9
|
+
import EndQueueEntryModal from './end-queue-entry-modal.component';
|
|
10
|
+
|
|
11
|
+
const mockedOpenmrsFetch = openmrsFetch as jest.Mock;
|
|
12
|
+
|
|
13
|
+
jest.mock('../../hooks/useQueues', () => {
|
|
14
|
+
return {
|
|
15
|
+
useQueues: jest.fn().mockReturnValue({
|
|
16
|
+
queues: mockQueues,
|
|
17
|
+
}),
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('UndoTransitionQueueEntryModal: ', () => {
|
|
22
|
+
const queueEntry = mockQueueEntryAlice;
|
|
23
|
+
|
|
24
|
+
it('has a cancel button that closes the modal', async () => {
|
|
25
|
+
const closeModal = jest.fn();
|
|
26
|
+
const user = userEvent.setup();
|
|
27
|
+
|
|
28
|
+
renderWithSwr(<UndoTransitionQueueEntryModal queueEntry={queueEntry} closeModal={closeModal} />);
|
|
29
|
+
const cancelButton = screen.getByText('Cancel');
|
|
30
|
+
await user.click(cancelButton);
|
|
31
|
+
expect(closeModal).toHaveBeenCalled();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('has an working submit button', async () => {
|
|
35
|
+
mockedOpenmrsFetch.mockResolvedValue({
|
|
36
|
+
status: 200,
|
|
37
|
+
});
|
|
38
|
+
const user = userEvent.setup();
|
|
39
|
+
renderWithSwr(<UndoTransitionQueueEntryModal queueEntry={queueEntry} closeModal={() => {}} />);
|
|
40
|
+
|
|
41
|
+
const submitButton = screen.getByRole('button', { name: /Undo transition/ });
|
|
42
|
+
expect(submitButton).not.toBeDisabled();
|
|
43
|
+
await user.click(submitButton);
|
|
44
|
+
|
|
45
|
+
expect(mockedOpenmrsFetch).toHaveBeenCalled();
|
|
46
|
+
expect(showSnackbar).toHaveBeenCalled();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe('VoidQueueEntryModal: ', () => {
|
|
51
|
+
const queueEntry = mockQueueEntryAlice;
|
|
52
|
+
|
|
53
|
+
it('has a cancel button that closes the modal', async () => {
|
|
54
|
+
const closeModal = jest.fn();
|
|
55
|
+
const user = userEvent.setup();
|
|
56
|
+
|
|
57
|
+
renderWithSwr(<VoidQueueEntryModal queueEntry={queueEntry} closeModal={closeModal} />);
|
|
58
|
+
const cancelButton = screen.getByText('Cancel');
|
|
59
|
+
await user.click(cancelButton);
|
|
60
|
+
expect(closeModal).toHaveBeenCalled();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('has an working submit button', async () => {
|
|
64
|
+
mockedOpenmrsFetch.mockResolvedValue({
|
|
65
|
+
status: 200,
|
|
66
|
+
});
|
|
67
|
+
const user = userEvent.setup();
|
|
68
|
+
renderWithSwr(<VoidQueueEntryModal queueEntry={queueEntry} closeModal={() => {}} />);
|
|
69
|
+
|
|
70
|
+
const submitButton = screen.getByRole('button', { name: /Delete queue entry/ });
|
|
71
|
+
expect(submitButton).not.toBeDisabled();
|
|
72
|
+
await user.click(submitButton);
|
|
73
|
+
|
|
74
|
+
expect(mockedOpenmrsFetch).toHaveBeenCalled();
|
|
75
|
+
expect(showSnackbar).toHaveBeenCalled();
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe('EndQueueEntryModal: ', () => {
|
|
80
|
+
const queueEntry = mockQueueEntryAlice;
|
|
81
|
+
|
|
82
|
+
it('has a cancel button that closes the modal', async () => {
|
|
83
|
+
const closeModal = jest.fn();
|
|
84
|
+
const user = userEvent.setup();
|
|
85
|
+
|
|
86
|
+
renderWithSwr(<EndQueueEntryModal queueEntry={queueEntry} closeModal={closeModal} />);
|
|
87
|
+
const cancelButton = screen.getByText('Cancel');
|
|
88
|
+
await user.click(cancelButton);
|
|
89
|
+
expect(closeModal).toHaveBeenCalled();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('has an working submit button', async () => {
|
|
93
|
+
mockedOpenmrsFetch.mockResolvedValue({
|
|
94
|
+
status: 200,
|
|
95
|
+
});
|
|
96
|
+
const user = userEvent.setup();
|
|
97
|
+
renderWithSwr(<EndQueueEntryModal queueEntry={queueEntry} closeModal={() => {}} />);
|
|
98
|
+
|
|
99
|
+
const submitButton = screen.getByRole('button', { name: /Remove patient/ });
|
|
100
|
+
expect(submitButton).not.toBeDisabled();
|
|
101
|
+
await user.click(submitButton);
|
|
102
|
+
|
|
103
|
+
expect(mockedOpenmrsFetch).toHaveBeenCalled();
|
|
104
|
+
expect(showSnackbar).toHaveBeenCalled();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { openmrsFetch, showSnackbar } from '@openmrs/esm-framework';
|
|
2
|
+
import { screen } from '@testing-library/react';
|
|
3
|
+
import { mockQueues, mockQueueEntryAlice } from '__mocks__';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { renderWithSwr } from 'tools';
|
|
6
|
+
import userEvent from '@testing-library/user-event';
|
|
7
|
+
import UndoTransitionQueueEntryModal from './undo-transition-queue-entry-modal.component';
|
|
8
|
+
import VoidQueueEntryModal from './void-queue-entry-modal.component';
|
|
9
|
+
|
|
10
|
+
const mockedOpenmrsFetch = openmrsFetch as jest.Mock;
|
|
11
|
+
|
|
12
|
+
jest.mock('../../hooks/useQueues', () => {
|
|
13
|
+
return {
|
|
14
|
+
useQueues: jest.fn().mockReturnValue({
|
|
15
|
+
queues: mockQueues,
|
|
16
|
+
}),
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('UndoTransitionQueueEntryModal: ', () => {
|
|
21
|
+
const queueEntry = mockQueueEntryAlice;
|
|
22
|
+
|
|
23
|
+
it('has a cancel button that closes the modal', async () => {
|
|
24
|
+
const closeModal = jest.fn();
|
|
25
|
+
const user = userEvent.setup();
|
|
26
|
+
|
|
27
|
+
renderWithSwr(<UndoTransitionQueueEntryModal queueEntry={queueEntry} closeModal={closeModal} />);
|
|
28
|
+
const cancelButton = screen.getByText('Cancel');
|
|
29
|
+
await user.click(cancelButton);
|
|
30
|
+
expect(closeModal).toHaveBeenCalled();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('has an working submit button', async () => {
|
|
34
|
+
mockedOpenmrsFetch.mockResolvedValue({
|
|
35
|
+
status: 200,
|
|
36
|
+
});
|
|
37
|
+
const user = userEvent.setup();
|
|
38
|
+
renderWithSwr(<UndoTransitionQueueEntryModal queueEntry={queueEntry} closeModal={() => {}} />);
|
|
39
|
+
|
|
40
|
+
const submitButton = screen.getByRole('button', { name: /Undo transition/ });
|
|
41
|
+
expect(submitButton).not.toBeDisabled();
|
|
42
|
+
await user.click(submitButton);
|
|
43
|
+
|
|
44
|
+
expect(mockedOpenmrsFetch).toHaveBeenCalled();
|
|
45
|
+
expect(showSnackbar).toHaveBeenCalled();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('VoidQueueEntryModal: ', () => {
|
|
50
|
+
const queueEntry = mockQueueEntryAlice;
|
|
51
|
+
|
|
52
|
+
it('has a cancel button that closes the modal', async () => {
|
|
53
|
+
const closeModal = jest.fn();
|
|
54
|
+
const user = userEvent.setup();
|
|
55
|
+
|
|
56
|
+
renderWithSwr(<VoidQueueEntryModal queueEntry={queueEntry} closeModal={closeModal} />);
|
|
57
|
+
const cancelButton = screen.getByText('Cancel');
|
|
58
|
+
await user.click(cancelButton);
|
|
59
|
+
expect(closeModal).toHaveBeenCalled();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('has an working submit button', async () => {
|
|
63
|
+
mockedOpenmrsFetch.mockResolvedValue({
|
|
64
|
+
status: 200,
|
|
65
|
+
});
|
|
66
|
+
const user = userEvent.setup();
|
|
67
|
+
renderWithSwr(<VoidQueueEntryModal queueEntry={queueEntry} closeModal={() => {}} />);
|
|
68
|
+
|
|
69
|
+
const submitButton = screen.getByRole('button', { name: /Delete queue entry/ });
|
|
70
|
+
expect(submitButton).not.toBeDisabled();
|
|
71
|
+
await user.click(submitButton);
|
|
72
|
+
|
|
73
|
+
expect(mockedOpenmrsFetch).toHaveBeenCalled();
|
|
74
|
+
expect(showSnackbar).toHaveBeenCalled();
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { type QueueEntry } from '../../types';
|
|
4
|
+
import QueueEntryActionModal from './queue-entry-actions-modal.component';
|
|
5
|
+
import { transitionQueueEntry } from './queue-entry-actions.resource';
|
|
6
|
+
import { convertTime12to24 } from '../../helpers/time-helpers';
|
|
7
|
+
|
|
8
|
+
interface TransitionQueueEntryModalProps {
|
|
9
|
+
queueEntry: QueueEntry;
|
|
10
|
+
closeModal: () => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const TransitionQueueEntryModal: React.FC<TransitionQueueEntryModalProps> = ({ queueEntry, closeModal }) => {
|
|
14
|
+
const { t } = useTranslation();
|
|
15
|
+
return (
|
|
16
|
+
<QueueEntryActionModal
|
|
17
|
+
queueEntry={queueEntry}
|
|
18
|
+
closeModal={closeModal}
|
|
19
|
+
modalParams={{
|
|
20
|
+
modalTitle: t('transitionPatient', 'Transition patient'),
|
|
21
|
+
modalInstruction: t(
|
|
22
|
+
'transitionPatientStatusOrQueue',
|
|
23
|
+
'Select a new status or queue for patient to transition to.',
|
|
24
|
+
),
|
|
25
|
+
submitButtonText: t('transitionPatient', 'Transition patient'),
|
|
26
|
+
submitSuccessTitle: t('queueEntryTransitioned', 'Queue entry transitioned'),
|
|
27
|
+
submitSuccessText: t('queueEntryTransitionedSuccessfully', 'Queue entry transitioned successfully'),
|
|
28
|
+
submitFailureTitle: t('queueEntryTransitionFailed', 'Error transitioning queue entry'),
|
|
29
|
+
submitAction: (queueEntry, formState) => {
|
|
30
|
+
const transitionDate = new Date(formState.transitionDate);
|
|
31
|
+
const [hour, minute] = convertTime12to24(formState.transitionTime, formState.transitionTimeFormat);
|
|
32
|
+
transitionDate.setHours(hour, minute, 0, 0);
|
|
33
|
+
|
|
34
|
+
return transitionQueueEntry({
|
|
35
|
+
queueEntryToTransition: queueEntry.uuid,
|
|
36
|
+
newQueue: formState.selectedQueue,
|
|
37
|
+
newStatus: formState.selectedStatus,
|
|
38
|
+
newPriority: formState.selectedPriority,
|
|
39
|
+
newPriorityComment: formState.prioritycomment,
|
|
40
|
+
...(formState.modifyDefaultTransitionDateTime ? { transitionDate: transitionDate.toISOString() } : {}),
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
disableSubmit: (queueEntry, formState) =>
|
|
44
|
+
formState.selectedQueue == queueEntry.queue.uuid && formState.selectedStatus == queueEntry.status.uuid,
|
|
45
|
+
isTransition: true,
|
|
46
|
+
}}
|
|
47
|
+
/>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default TransitionQueueEntryModal;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { type QueueEntry } from '../../types';
|
|
4
|
+
import { undoTransition } from './queue-entry-actions.resource';
|
|
5
|
+
import QueueEntryConfirmActionModal from './queue-entry-confirm-action-modal.component';
|
|
6
|
+
|
|
7
|
+
interface UndoTransitionQueueEntryModalProps {
|
|
8
|
+
queueEntry: QueueEntry;
|
|
9
|
+
closeModal: () => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const UndoTransitionQueueEntryModal: React.FC<UndoTransitionQueueEntryModalProps> = ({ queueEntry, closeModal }) => {
|
|
13
|
+
const { t } = useTranslation();
|
|
14
|
+
const { previousQueueEntry, queueComingFrom } = queueEntry;
|
|
15
|
+
|
|
16
|
+
const previousEntrySameQueue = queueComingFrom.uuid == queueEntry.queue.uuid;
|
|
17
|
+
const modalInstruction = previousEntrySameQueue ? (
|
|
18
|
+
<p>
|
|
19
|
+
{t('confirmMoveBackStatus', 'Are you sure you want to move patient back to status "{{status}}"?', {
|
|
20
|
+
status: previousQueueEntry.status.display,
|
|
21
|
+
interpolation: { escapeValue: false },
|
|
22
|
+
})}
|
|
23
|
+
</p>
|
|
24
|
+
) : (
|
|
25
|
+
<p>
|
|
26
|
+
{t(
|
|
27
|
+
'confirmMoveBackQueueAndStatus',
|
|
28
|
+
'Are you sure you want to move patient back to queue "{{queue}}" with status "{{status}}"?',
|
|
29
|
+
{
|
|
30
|
+
queue: queueComingFrom.display,
|
|
31
|
+
status: previousQueueEntry.status.display,
|
|
32
|
+
interpolation: { escapeValue: false },
|
|
33
|
+
},
|
|
34
|
+
)}
|
|
35
|
+
</p>
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<QueueEntryConfirmActionModal
|
|
40
|
+
queueEntry={queueEntry}
|
|
41
|
+
closeModal={closeModal}
|
|
42
|
+
modalParams={{
|
|
43
|
+
modalTitle: t('undoTransition', 'Undo transition'),
|
|
44
|
+
modalInstruction,
|
|
45
|
+
submitButtonText: t('undoTransition', 'Undo transition'),
|
|
46
|
+
submitSuccessTitle: t('undoQueueEntryTransitionSuccess', 'Undo transition success'),
|
|
47
|
+
submitSuccessText: t('queueEntryTransitionUndoSuccessful', 'Queue entry transition undo success'),
|
|
48
|
+
submitFailureTitle: t('queueEntryTransitionUndoFailed', 'Error undoing transition'),
|
|
49
|
+
submitAction: (queueEntry) =>
|
|
50
|
+
undoTransition({
|
|
51
|
+
queueEntry: queueEntry.uuid,
|
|
52
|
+
}),
|
|
53
|
+
}}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default UndoTransitionQueueEntryModal;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { type QueueEntry } from '../../types';
|
|
4
|
+
import { voidQueueEntry } from './queue-entry-actions.resource';
|
|
5
|
+
import QueueEntryConfirmActionModal from './queue-entry-confirm-action-modal.component';
|
|
6
|
+
|
|
7
|
+
interface VoidQueueEntryModalProps {
|
|
8
|
+
queueEntry: QueueEntry;
|
|
9
|
+
closeModal: () => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const VoidQueueEntryModal: React.FC<VoidQueueEntryModalProps> = ({ queueEntry, closeModal }) => {
|
|
13
|
+
const { t } = useTranslation();
|
|
14
|
+
|
|
15
|
+
const modalInstruction = <p>{t('confirmDeleteQueueEntry', 'Are you sure you want to delete this queue entry?')}</p>;
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<QueueEntryConfirmActionModal
|
|
19
|
+
queueEntry={queueEntry}
|
|
20
|
+
closeModal={closeModal}
|
|
21
|
+
modalParams={{
|
|
22
|
+
modalTitle: t('deleteQueueEntry', 'Delete queue entry'),
|
|
23
|
+
modalInstruction,
|
|
24
|
+
submitButtonText: t('deleteQueueEntry', 'Delete queue entry'),
|
|
25
|
+
submitSuccessTitle: t('queueEntryDeleteSuccessful', 'Queue entry deleted successfully'),
|
|
26
|
+
submitSuccessText: t('queueEntryDeleteSuccessful', 'Queue entry deleted successfully'),
|
|
27
|
+
submitFailureTitle: t('queueEntryDeleteFailed', 'Error deleting queue entry'),
|
|
28
|
+
submitAction: (queueEntry) => voidQueueEntry(queueEntry.uuid),
|
|
29
|
+
}}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default VoidQueueEntryModal;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { SideNavMenu } from '@carbon/react';
|
|
2
|
+
import { ConfigurableLink } from '@openmrs/esm-framework';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { type Queue } from '../types';
|
|
6
|
+
import { useQueues } from '../hooks/useQueues';
|
|
7
|
+
import classNames from 'classnames';
|
|
8
|
+
import { BrowserRouter, useMatch, generatePath } from 'react-router-dom';
|
|
9
|
+
import styles from './queue-table-by-status-menu.scss';
|
|
10
|
+
|
|
11
|
+
// (Non-standard UI) A menu in the left nav to display a list of queues. Intended to be used
|
|
12
|
+
// by slotting into the left nav as an extension
|
|
13
|
+
export default function QueueTableByStatusMenu() {
|
|
14
|
+
const { t } = useTranslation();
|
|
15
|
+
const { queues } = useQueues();
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<SideNavMenu title={t('serviceQueues', 'Service queues')} className={styles.queueTableByStatusNavMenu}>
|
|
19
|
+
<BrowserRouter>
|
|
20
|
+
{queues.map((queue) => (
|
|
21
|
+
<QueueTableByStatusLink queue={queue} />
|
|
22
|
+
))}
|
|
23
|
+
</BrowserRouter>
|
|
24
|
+
</SideNavMenu>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function QueueTableByStatusLink({ queue }: { queue: Queue }) {
|
|
29
|
+
const path = `${window.spaBase}/home/service-queues/queue-table-by-status/:uuid`;
|
|
30
|
+
const matcher = useMatch({ path, end: false });
|
|
31
|
+
const uuid = matcher?.params?.uuid;
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<ConfigurableLink
|
|
35
|
+
className={classNames('cds--side-nav__link', {
|
|
36
|
+
'active-left-nav-link': queue.uuid == uuid,
|
|
37
|
+
})}
|
|
38
|
+
to={generatePath(path, { uuid: queue.uuid })}>
|
|
39
|
+
{queue.display}
|
|
40
|
+
</ConfigurableLink>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
.queueTableByStatusNavMenu {
|
|
2
|
+
// override `li` element styles from <SideNavMenu>
|
|
3
|
+
// (since none of the items in side nav is `li`)
|
|
4
|
+
line-height: 0px;
|
|
5
|
+
display: block;
|
|
6
|
+
|
|
7
|
+
:global(.active-left-nav-link) {
|
|
8
|
+
// override padding for sub-menu items
|
|
9
|
+
padding-left: 1.75rem !important;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { DataTableSkeleton, SkeletonText, Tab, TabList, TabPanel, TabPanels, Tabs } from '@carbon/react';
|
|
2
|
+
import { isDesktop, useLayoutType } from '@openmrs/esm-framework';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import styles from './queue-table.scss';
|
|
5
|
+
|
|
6
|
+
export const QueueTableByStatusSkeleton = () => {
|
|
7
|
+
const layout = useLayoutType();
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<div className={styles.container}>
|
|
11
|
+
<div className={styles.headerContainer}>
|
|
12
|
+
<div className={!isDesktop(layout) ? styles.tabletHeading : styles.desktopHeading}>
|
|
13
|
+
<h3>
|
|
14
|
+
<SkeletonText />
|
|
15
|
+
</h3>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
<Tabs selectedIndex={0}>
|
|
19
|
+
<TabList>
|
|
20
|
+
<Tab>
|
|
21
|
+
<SkeletonText />
|
|
22
|
+
</Tab>
|
|
23
|
+
</TabList>
|
|
24
|
+
</Tabs>
|
|
25
|
+
<TabPanels>
|
|
26
|
+
<TabPanel>
|
|
27
|
+
<DataTableSkeleton />
|
|
28
|
+
</TabPanel>
|
|
29
|
+
</TabPanels>
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { InlineNotification, Tab, TabList, TabPanel, TabPanels, Tabs } from '@carbon/react';
|
|
2
|
+
import { isDesktop, useLayoutType } from '@openmrs/esm-framework';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { useNavigate } from 'react-router-dom';
|
|
6
|
+
import styles from './queue-table.scss';
|
|
7
|
+
import { useQueueEntries } from '../hooks/useQueueEntries';
|
|
8
|
+
import { type Concept, type Queue, type QueueTableTabConfig } from '../types';
|
|
9
|
+
import { QueueTableByStatusSkeleton } from './queue-table-by-status-skeleton.component';
|
|
10
|
+
import QueueTable from './queue-table.component';
|
|
11
|
+
|
|
12
|
+
interface QueueTableByStatusProps {
|
|
13
|
+
selectedQueue: Queue; // the selected queue
|
|
14
|
+
selectedStatus: Concept; // the selected status
|
|
15
|
+
allStatusTabConfig?: QueueTableTabConfig; // If provided, we display an additional tab for *all* statuses with the given config
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// displays the queue entries of a given queue by
|
|
19
|
+
// showing a list of tabs (one tab per status), each showing
|
|
20
|
+
// queue entries within that status
|
|
21
|
+
const QueueTableByStatus: React.FC<QueueTableByStatusProps> = ({
|
|
22
|
+
selectedQueue,
|
|
23
|
+
selectedStatus,
|
|
24
|
+
allStatusTabConfig,
|
|
25
|
+
}) => {
|
|
26
|
+
const layout = useLayoutType();
|
|
27
|
+
const { t } = useTranslation();
|
|
28
|
+
const navigate = useNavigate();
|
|
29
|
+
|
|
30
|
+
const { queueEntries, isLoading, isValidating } = useQueueEntries({ queue: selectedQueue.uuid, isEnded: false });
|
|
31
|
+
const allowedStatuses = selectedQueue.allowedStatuses;
|
|
32
|
+
|
|
33
|
+
const currentStatusUuid = selectedStatus?.uuid ?? allowedStatuses?.[0]?.uuid;
|
|
34
|
+
const currentStatusIndex = allowedStatuses?.findIndex((s) => s.uuid == currentStatusUuid);
|
|
35
|
+
|
|
36
|
+
const noStatuses = !allowedStatuses?.length;
|
|
37
|
+
if (isLoading && !queueEntries.length) {
|
|
38
|
+
return <QueueTableByStatusSkeleton />;
|
|
39
|
+
} else if (noStatuses) {
|
|
40
|
+
return (
|
|
41
|
+
<InlineNotification
|
|
42
|
+
kind={'error'}
|
|
43
|
+
lowContrast
|
|
44
|
+
subtitle={t('configureStatus', 'Please configure status to continue.')}
|
|
45
|
+
title={t('noStatusConfigured', 'No status configured')}
|
|
46
|
+
/>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const queueEntriesForCurrentStatus = queueEntries?.filter((entry) => entry.status.uuid == currentStatusUuid);
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<div className={styles.container}>
|
|
54
|
+
<div className={styles.headerContainer}>
|
|
55
|
+
<div className={isDesktop(layout) ? styles.desktopHeading : styles.tabletHeading}>
|
|
56
|
+
<h3>{selectedQueue.display}</h3>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
<Tabs
|
|
60
|
+
selectedIndex={currentStatusIndex}
|
|
61
|
+
onChange={({ selectedIndex }) => {
|
|
62
|
+
const newStatusUuid = allowedStatuses[selectedIndex]?.uuid;
|
|
63
|
+
const url = `/queue-table-by-status/${selectedQueue.uuid}` + (newStatusUuid ? '/' + newStatusUuid : '');
|
|
64
|
+
navigate(url);
|
|
65
|
+
}}>
|
|
66
|
+
<TabList className={styles.tabList} aria-label={t('queueStatus', 'Queue status')} contained>
|
|
67
|
+
{allowedStatuses?.map((s) => <Tab key={s?.uuid}>{s?.display}</Tab>)}
|
|
68
|
+
{allStatusTabConfig && <Tab>{t('all', 'All')}</Tab>}
|
|
69
|
+
</TabList>
|
|
70
|
+
<TabPanels>
|
|
71
|
+
{allowedStatuses?.map((s) => (
|
|
72
|
+
<TabPanel key={s.uuid}>
|
|
73
|
+
<QueueTable
|
|
74
|
+
queueEntries={queueEntriesForCurrentStatus}
|
|
75
|
+
queueUuid={selectedQueue.uuid}
|
|
76
|
+
statusUuid={s.uuid}
|
|
77
|
+
/>
|
|
78
|
+
</TabPanel>
|
|
79
|
+
))}
|
|
80
|
+
{allStatusTabConfig && (
|
|
81
|
+
<TabPanel>
|
|
82
|
+
<QueueTable
|
|
83
|
+
queueEntries={queueEntriesForCurrentStatus}
|
|
84
|
+
isValidating={isValidating}
|
|
85
|
+
queueUuid={selectedQueue.uuid}
|
|
86
|
+
statusUuid={null}
|
|
87
|
+
/>
|
|
88
|
+
</TabPanel>
|
|
89
|
+
)}
|
|
90
|
+
</TabPanels>
|
|
91
|
+
</Tabs>
|
|
92
|
+
</div>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export default QueueTableByStatus;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React, { type FC } from 'react';
|
|
2
|
+
import { Tab, Tabs, TabPanels, TabPanel, TabList } from '@carbon/react';
|
|
3
|
+
|
|
4
|
+
import CurrentVisit from '../current-visit/current-visit-summary.component';
|
|
5
|
+
import PastVisit from '../past-visit/past-visit.component';
|
|
6
|
+
import { type QueueEntry } from '../types';
|
|
7
|
+
import { useTranslation } from 'react-i18next';
|
|
8
|
+
|
|
9
|
+
const QueueTableExpandedRow: FC<{ queueEntry: QueueEntry }> = ({ queueEntry }) => {
|
|
10
|
+
const { t } = useTranslation();
|
|
11
|
+
return (
|
|
12
|
+
<Tabs>
|
|
13
|
+
<TabList aria-label={t('visitTabs', 'Visit tabs')}>
|
|
14
|
+
<Tab>{t('currentVisit', 'Current visit')}</Tab>
|
|
15
|
+
<Tab>{t('previousVisit', 'Previous visit')} </Tab>
|
|
16
|
+
</TabList>
|
|
17
|
+
<TabPanels>
|
|
18
|
+
<TabPanel>
|
|
19
|
+
<CurrentVisit patientUuid={queueEntry.patient.uuid} visitUuid={queueEntry.visit.uuid} />
|
|
20
|
+
</TabPanel>
|
|
21
|
+
<TabPanel>
|
|
22
|
+
<PastVisit patientUuid={queueEntry.patient.uuid} />
|
|
23
|
+
</TabPanel>
|
|
24
|
+
</TabPanels>
|
|
25
|
+
</Tabs>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default QueueTableExpandedRow;
|