@kenyaemr/esm-imaging-orders-app 4.0.1-pre.1

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.
Files changed (110) hide show
  1. package/.turbo/turbo-build.log +188 -0
  2. package/README.md +8 -0
  3. package/dist/123.js +2 -0
  4. package/dist/123.js.LICENSE.txt +40 -0
  5. package/dist/123.js.map +1 -0
  6. package/dist/144.js +2 -0
  7. package/dist/144.js.LICENSE.txt +19 -0
  8. package/dist/144.js.map +1 -0
  9. package/dist/225.js +1 -0
  10. package/dist/225.js.map +1 -0
  11. package/dist/300.js +1 -0
  12. package/dist/364.js +1 -0
  13. package/dist/364.js.map +1 -0
  14. package/dist/372.js +1 -0
  15. package/dist/372.js.map +1 -0
  16. package/dist/41.js +2 -0
  17. package/dist/41.js.LICENSE.txt +9 -0
  18. package/dist/41.js.map +1 -0
  19. package/dist/495.js +1 -0
  20. package/dist/495.js.map +1 -0
  21. package/dist/606.js +1 -0
  22. package/dist/606.js.map +1 -0
  23. package/dist/831.js +2 -0
  24. package/dist/831.js.LICENSE.txt +5 -0
  25. package/dist/831.js.map +1 -0
  26. package/dist/876.js +2 -0
  27. package/dist/876.js.LICENSE.txt +9 -0
  28. package/dist/876.js.map +1 -0
  29. package/dist/913.js +2 -0
  30. package/dist/913.js.LICENSE.txt +32 -0
  31. package/dist/913.js.map +1 -0
  32. package/dist/kenyaemr-esm-imaging-orders-app.js +1 -0
  33. package/dist/kenyaemr-esm-imaging-orders-app.js.buildmanifest.json +401 -0
  34. package/dist/kenyaemr-esm-imaging-orders-app.js.map +1 -0
  35. package/dist/main.js +2 -0
  36. package/dist/main.js.LICENSE.txt +60 -0
  37. package/dist/main.js.map +1 -0
  38. package/dist/routes.json +1 -0
  39. package/jest.config.js +8 -0
  40. package/package.json +55 -0
  41. package/src/config-schema.ts +51 -0
  42. package/src/constants.ts +3 -0
  43. package/src/declarations.d.ts +6 -0
  44. package/src/form/imaging-orders/add-imaging-orders/add-imaging-order.scss +44 -0
  45. package/src/form/imaging-orders/add-imaging-orders/add-imaging-order.workspace.tsx +86 -0
  46. package/src/form/imaging-orders/add-imaging-orders/imaging-order-form.component.tsx +354 -0
  47. package/src/form/imaging-orders/add-imaging-orders/imaging-order-form.scss +79 -0
  48. package/src/form/imaging-orders/add-imaging-orders/imaging-order.ts +19 -0
  49. package/src/form/imaging-orders/add-imaging-orders/imaging-type-search.scss +115 -0
  50. package/src/form/imaging-orders/add-imaging-orders/imaging-type-search.tsx +235 -0
  51. package/src/form/imaging-orders/add-imaging-orders/useImagingTypes.ts +89 -0
  52. package/src/form/imaging-orders/api.ts +230 -0
  53. package/src/form/imaging-orders/imaging-order-basket-panel/imaging-icon.component.tsx +40 -0
  54. package/src/form/imaging-orders/imaging-order-basket-panel/imaging-order-basket-item-tile.component.tsx +96 -0
  55. package/src/form/imaging-orders/imaging-order-basket-panel/imaging-order-basket-item-tile.scss +72 -0
  56. package/src/form/imaging-orders/imaging-order-basket-panel/imaging-order-basket-panel.extension.tsx +191 -0
  57. package/src/form/imaging-orders/imaging-order-basket-panel/imaging-order-basket-panel.scss +74 -0
  58. package/src/form/imaging-orders/useOrderConfig.ts +48 -0
  59. package/src/form/imaging-report-form/imaging-report-form.component.tsx +161 -0
  60. package/src/form/imaging-report-form/imaging-report-form.scss +30 -0
  61. package/src/form/imaging-report-form/imaging.resource.ts +360 -0
  62. package/src/header/imagining-header.component.tsx +17 -0
  63. package/src/header/imagining-header.scss +5 -0
  64. package/src/hooks/useOrdersWorklist.ts +59 -0
  65. package/src/hooks/useSearchGroupedResults.ts +27 -0
  66. package/src/hooks/useSearchResults.ts +51 -0
  67. package/src/imaging-orders.component.tsx +14 -0
  68. package/src/imaging-tabs/approved/approved-orders.component.tsx +31 -0
  69. package/src/imaging-tabs/approved/approved-orders.scss +0 -0
  70. package/src/imaging-tabs/imaging-tabs.component.tsx +79 -0
  71. package/src/imaging-tabs/imaging-tabs.scss +5 -0
  72. package/src/imaging-tabs/orders-not-done/orders-not-done.component.tsx +42 -0
  73. package/src/imaging-tabs/referred-test/referred-ordered.component.tsx +26 -0
  74. package/src/imaging-tabs/referred-test/referred-ordered.scss +6 -0
  75. package/src/imaging-tabs/review-ordered/review-imaging-report-modal/review-imaging-report-dialog.component.tsx +138 -0
  76. package/src/imaging-tabs/review-ordered/review-imaging-report-modal/review-imaging-report-dialog.scss +5 -0
  77. package/src/imaging-tabs/review-ordered/review-ordered.component.tsx +28 -0
  78. package/src/imaging-tabs/review-ordered/review-ordered.scss +0 -0
  79. package/src/imaging-tabs/test-ordered/pick-imaging-order/add-to-worklist-dialog.component.tsx +94 -0
  80. package/src/imaging-tabs/test-ordered/pick-imaging-order/add-to-worklist-dialog.resource.ts +137 -0
  81. package/src/imaging-tabs/test-ordered/pick-imaging-order/add-to-worklist-dialog.scss +38 -0
  82. package/src/imaging-tabs/test-ordered/reject-order-dialog/radiology-reject-reason.component.tsx +40 -0
  83. package/src/imaging-tabs/test-ordered/reject-order-dialog/reject-order-dialog.component.tsx +95 -0
  84. package/src/imaging-tabs/test-ordered/reject-order-dialog/reject-order-dialog.scss +14 -0
  85. package/src/imaging-tabs/test-ordered/tests-ordered.component.tsx +35 -0
  86. package/src/imaging-tabs/test-ordered/tests-ordered.scss +13 -0
  87. package/src/imaging-tabs/test-ordered/transition-patient-new-queue/transition-latest-queue-entry-button.component.tsx +34 -0
  88. package/src/imaging-tabs/test-ordered/transition-patient-new-queue/transition-latest-queue-entry-button.scss +14 -0
  89. package/src/imaging-tabs/work-list/work-list.component.tsx +45 -0
  90. package/src/imaging-tabs/work-list/work-list.resource.ts +150 -0
  91. package/src/imaging-tabs/work-list/work-list.scss +207 -0
  92. package/src/index.ts +45 -0
  93. package/src/left-panel-link.tsx +42 -0
  94. package/src/root.component.tsx +19 -0
  95. package/src/routes.json +58 -0
  96. package/src/shared/imaging.resource.tsx +65 -0
  97. package/src/shared/ui/common/action-button/action-button.component.tsx +66 -0
  98. package/src/shared/ui/common/action-button/order-action-extension.component.tsx +21 -0
  99. package/src/shared/ui/common/grouped-imaging-types.ts +48 -0
  100. package/src/shared/ui/common/grouped-orders-table.component.tsx +154 -0
  101. package/src/shared/ui/common/grouped-orders-table.scss +13 -0
  102. package/src/shared/ui/common/list-order-details.component.tsx +72 -0
  103. package/src/shared/ui/common/list-order-details.scss +52 -0
  104. package/src/shared/ui/common/order-detail.component.tsx +14 -0
  105. package/src/shared/ui/common/order-detail.scss +14 -0
  106. package/src/types/index.ts +49 -0
  107. package/src/utils/functions.ts +238 -0
  108. package/translations/en.json +69 -0
  109. package/tsconfig.json +5 -0
  110. package/webpack.config.js +1 -0
@@ -0,0 +1,51 @@
1
+ import { formatDate, parseDate } from '@openmrs/esm-framework';
2
+ import { useMemo } from 'react';
3
+ import { Result } from '../imaging-tabs/work-list/work-list.resource';
4
+
5
+ /**
6
+ * A custom hook that processes and filters imaging order results based on a search string.
7
+ *
8
+ * @param {Result[]} data - An array of imaging order results to be processed and searched.
9
+ * @param {string} searchString - The string to search for within the data.
10
+ * @returns {Array} An array of processed and filtered imaging order results.
11
+ */
12
+ export function useSearchResults(data: Result[], searchString: string) {
13
+ /**
14
+ * Flattens and transforms the input data for easier searching and display.
15
+ */
16
+ const flattenedData = data.map((eachObject) => {
17
+ return {
18
+ ...eachObject,
19
+ id: eachObject.uuid,
20
+ date: formatDate(parseDate(eachObject.dateActivated)),
21
+ patient: eachObject.patient.display.split('-')[1],
22
+ orderNumber: eachObject.orderNumber,
23
+ procedure: eachObject.concept.display,
24
+ action: eachObject.action,
25
+ status: eachObject.fulfillerStatus ?? '--',
26
+ orderer: eachObject.orderer.display,
27
+ urgency: eachObject.urgency,
28
+ };
29
+ });
30
+
31
+ /**
32
+ * Memoized search results based on the flattened data and search string.
33
+ */
34
+ const searchResults = useMemo(() => {
35
+ if (searchString && searchString.trim() !== '') {
36
+ const search = searchString.toLowerCase();
37
+ return flattenedData.filter((eachDataRow) =>
38
+ Object.entries(eachDataRow).some(([header, value]) => {
39
+ if (header === 'patientUuid') {
40
+ return false;
41
+ }
42
+ return `${value}`.toLowerCase().includes(search);
43
+ }),
44
+ );
45
+ }
46
+
47
+ return flattenedData;
48
+ }, [searchString, flattenedData]);
49
+
50
+ return searchResults;
51
+ }
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import { ImagingPageHeader } from './header/imagining-header.component';
3
+ import { ImagingTabs } from './imaging-tabs/imaging-tabs.component';
4
+
5
+ const ImagingOrders: React.FC = () => {
6
+ return (
7
+ <div>
8
+ <ImagingPageHeader />
9
+ <ImagingTabs />
10
+ </div>
11
+ );
12
+ };
13
+
14
+ export default ImagingOrders;
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { DataTableSkeleton } from '@carbon/react';
4
+ import { useOrdersWorkList } from '../../hooks/useOrdersWorklist';
5
+ import GroupedOrdersTable from '../../shared/ui/common/grouped-orders-table.component';
6
+
7
+ export const ApprovedOrders: React.FC = () => {
8
+ const { t } = useTranslation();
9
+ const { workListEntries, isLoading } = useOrdersWorkList('', 'COMPLETED');
10
+ const approved = workListEntries.filter((item) =>
11
+ item.procedures?.some((procedure) => procedure.outcome === 'SUCCESSFUL'),
12
+ );
13
+
14
+ if (isLoading) {
15
+ return <DataTableSkeleton />;
16
+ }
17
+
18
+ return (
19
+ <div>
20
+ <GroupedOrdersTable
21
+ orders={approved}
22
+ showStatus={false}
23
+ showStartButton={false}
24
+ showActions={false}
25
+ showOrderType={true}
26
+ actions={[]}
27
+ title={t('approvedOrders', 'Approved Orders')}
28
+ />
29
+ </div>
30
+ );
31
+ };
File without changes
@@ -0,0 +1,79 @@
1
+ import React from 'react';
2
+ import { TabPanels, TabList, Tabs, Tab, TabPanel } from '@carbon/react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { useImagingOrderStats } from '../shared/imaging.resource';
5
+ import { useOrdersWorkList } from '../hooks/useOrdersWorklist';
6
+ import { TestsOrdered } from './test-ordered/tests-ordered.component';
7
+ import WorkList from './work-list/work-list.component';
8
+ import { ReferredTests } from './referred-test/referred-ordered.component';
9
+ import { Review } from './review-ordered/review-ordered.component';
10
+ import { ApprovedOrders } from './approved/approved-orders.component';
11
+ import { OrdersNotDone } from './orders-not-done/orders-not-done.component';
12
+ import styles from './imaging-tabs.scss';
13
+
14
+ export const ImagingTabs: React.FC = () => {
15
+ const { t } = useTranslation();
16
+ const { activeOrdersCount, workListCount, referredTestsCount, ordersNotDoneCount } = useOrderCounts();
17
+ const { pendingReviewCount, approvedOrdersCount } = useCompletedOrders();
18
+
19
+ const tabsData = [
20
+ { label: 'pendingOrders', text: 'Active Orders', count: activeOrdersCount, component: <TestsOrdered /> },
21
+ {
22
+ label: 'workList',
23
+ text: 'WorkList',
24
+ count: workListCount,
25
+ component: <WorkList fulfillerStatus="IN_PROGRESS" />,
26
+ },
27
+ { label: 'referredProcedures', text: 'Referred Out', count: referredTestsCount, component: <ReferredTests /> },
28
+ { label: 'review', text: 'Pending Review', count: pendingReviewCount, component: <Review /> },
29
+ { label: 'approved', text: 'Approved', count: approvedOrdersCount, component: <ApprovedOrders /> },
30
+ {
31
+ label: 'notDone',
32
+ text: 'Not Done',
33
+ count: ordersNotDoneCount,
34
+ component: <OrdersNotDone fulfillerStatus="DECLINED" />,
35
+ },
36
+ ];
37
+
38
+ return (
39
+ <div className={styles.imagingTabsContainer}>
40
+ <Tabs>
41
+ <TabList aria-label="List of tabs" contained style={{ marginLeft: '1rem' }}>
42
+ {tabsData.map(({ label, text, count }) => (
43
+ <Tab key={label}>
44
+ {t(label, text)} ({count})
45
+ </Tab>
46
+ ))}
47
+ </TabList>
48
+ <TabPanels>
49
+ {tabsData.map(({ label, component }) => (
50
+ <TabPanel key={label}>{component}</TabPanel>
51
+ ))}
52
+ </TabPanels>
53
+ </Tabs>
54
+ </div>
55
+ );
56
+ };
57
+
58
+ const useOrderCounts = () => {
59
+ const { count: activeOrdersCount } = useImagingOrderStats('');
60
+ const { count: workListCount } = useImagingOrderStats('IN_PROGRESS');
61
+ const { count: referredTestsCount } = useImagingOrderStats('EXCEPTION');
62
+ const { count: ordersNotDoneCount } = useImagingOrderStats('DECLINED');
63
+
64
+ return { activeOrdersCount, workListCount, referredTestsCount, ordersNotDoneCount };
65
+ };
66
+
67
+ const useCompletedOrders = () => {
68
+ const { workListEntries } = useOrdersWorkList('', 'COMPLETED');
69
+ const pendingReview = workListEntries.filter((item) =>
70
+ item.procedures?.some((procedure) => procedure.outcome !== 'SUCCESSFUL'),
71
+ );
72
+ const pendingReviewCount = pendingReview?.length ?? 0;
73
+ const approved = workListEntries.filter((item) =>
74
+ item.procedures?.some((procedure) => procedure.outcome === 'SUCCESSFUL'),
75
+ );
76
+ const approvedOrdersCount = approved?.length ?? 0;
77
+
78
+ return { pendingReviewCount, approvedOrdersCount };
79
+ };
@@ -0,0 +1,5 @@
1
+ @use '@carbon/layout';
2
+
3
+ .imagingTabsContainer {
4
+ margin-top: layout.$spacing-05;
5
+ }
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { DataTableSkeleton } from '@carbon/react';
4
+ import { useOrdersWorkList } from '../../hooks/useOrdersWorklist';
5
+ import { FulfillerStatus } from '../../shared/ui/common/grouped-imaging-types';
6
+ import GroupedOrdersTable from '../../shared/ui/common/grouped-orders-table.component';
7
+ import styles from '../test-ordered/tests-ordered.scss';
8
+ interface NotDoneProps {
9
+ fulfillerStatus: FulfillerStatus;
10
+ }
11
+ export const OrdersNotDone: React.FC<NotDoneProps> = ({ fulfillerStatus }) => {
12
+ const { t } = useTranslation();
13
+ const { workListEntries, isLoading } = useOrdersWorkList('', fulfillerStatus);
14
+
15
+ if (isLoading) {
16
+ return <DataTableSkeleton role="progressbar" />;
17
+ }
18
+ if (workListEntries?.length >= 0) {
19
+ return (
20
+ <>
21
+ <div>
22
+ <div className={styles.headerBtnContainer}></div>
23
+ <GroupedOrdersTable
24
+ orders={workListEntries}
25
+ showStatus={true}
26
+ showStartButton={false}
27
+ showActions={true}
28
+ showOrderType={false}
29
+ actions={[
30
+ {
31
+ actionName: 'reject-imaging-order-modal',
32
+ order: 1,
33
+ },
34
+ ]}
35
+ title={t('ordersNotDone', 'Orders Not Done')}
36
+ />
37
+ </div>
38
+ </>
39
+ );
40
+ }
41
+ };
42
+ export default OrdersNotDone;
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { DataTableSkeleton } from '@carbon/react';
4
+ import { useOrdersWorkList } from '../../hooks/useOrdersWorklist';
5
+ import GroupedOrdersTable from '../../shared/ui/common/grouped-orders-table.component';
6
+
7
+ export const ReferredTests: React.FC = () => {
8
+ const { t } = useTranslation();
9
+ const { workListEntries, isLoading } = useOrdersWorkList('', 'EXCEPTION');
10
+
11
+ return isLoading ? (
12
+ <DataTableSkeleton />
13
+ ) : (
14
+ <div>
15
+ <GroupedOrdersTable
16
+ orders={workListEntries}
17
+ showStatus={false}
18
+ showStartButton={false}
19
+ showActions={false}
20
+ showOrderType={false}
21
+ actions={[]}
22
+ title={t('referredTests', 'Referred Tests')}
23
+ />
24
+ </div>
25
+ );
26
+ };
@@ -0,0 +1,6 @@
1
+ @use '@carbon/colors';
2
+ @import '~@openmrs/esm-styleguide/src/vars';
3
+
4
+ .single-line-display {
5
+ white-space: nowrap;
6
+ }
@@ -0,0 +1,138 @@
1
+ import React, { useState } from 'react';
2
+
3
+ import {
4
+ Button,
5
+ Form,
6
+ ModalBody,
7
+ ModalFooter,
8
+ ModalHeader,
9
+ TextArea,
10
+ Accordion,
11
+ AccordionItem,
12
+ Table,
13
+ TableBody,
14
+ TableRow,
15
+ TableCell,
16
+ } from '@carbon/react';
17
+ import { useTranslation } from 'react-i18next';
18
+ import styles from './review-imaging-report-dialog.scss';
19
+ import { Result } from '../../work-list/work-list.resource';
20
+ import { showNotification, showSnackbar } from '@openmrs/esm-framework';
21
+ import { updateImagingProcedure } from '../../test-ordered/pick-imaging-order/add-to-worklist-dialog.resource';
22
+ import { mutate } from 'swr';
23
+ interface ReviewOrderDialogProps {
24
+ order: Result;
25
+ closeModal: () => void;
26
+ }
27
+
28
+ const ReviewImagingReportModal: React.FC<ReviewOrderDialogProps> = ({ order, closeModal }) => {
29
+ const { t } = useTranslation();
30
+
31
+ const [notes, setNotes] = useState('');
32
+ const tableData = [
33
+ { key: 'Order Urgency', value: order.urgency },
34
+ {
35
+ key: 'Schedule date',
36
+ value: order.scheduledDate || new Date().toLocaleDateString(),
37
+ },
38
+ { key: 'Body Site', value: order.display },
39
+ { key: 'Laterality', value: order.laterality },
40
+ { key: 'Number of repeats', value: order.numberOfRepeats },
41
+ { key: 'Frequency', value: order.frequency?.display },
42
+ ];
43
+ const procedureTableData = [{ key: 'Lab Results: ', value: order?.procedures[0]?.procedureReport }];
44
+
45
+ const updateProcedures = async (event) => {
46
+ event.preventDefault();
47
+ const body = {
48
+ outcome: 'SUCCESSFUL',
49
+ };
50
+ updateImagingProcedure(order?.procedures[0].uuid, body)
51
+ .then(() => {
52
+ showSnackbar({
53
+ isLowContrast: true,
54
+ title: t('createResponse', 'Create Review'),
55
+ kind: 'success',
56
+ subtitle: t('pickSuccessfully', 'You have successfully created a review'),
57
+ });
58
+ closeModal();
59
+ mutate((key) => typeof key === 'string' && key.startsWith('/ws/rest/v1/procedure'), undefined, {
60
+ revalidate: true,
61
+ });
62
+
63
+ mutate((key) => typeof key === 'string' && key.startsWith('/ws/rest/v1/order'), undefined, {
64
+ revalidate: true,
65
+ });
66
+ })
67
+ .catch((error) => {
68
+ showNotification({
69
+ title: t(`errorPicking', 'Error Creating Review`),
70
+ kind: 'error',
71
+ critical: true,
72
+ description: error?.message,
73
+ });
74
+ });
75
+ };
76
+
77
+ return (
78
+ <div>
79
+ <Form onSubmit={updateProcedures}>
80
+ <ModalHeader closeModal={closeModal} title={t('reviewImagingReport', 'Review Imaging Report')} />
81
+ <ModalBody>
82
+ <div className={styles.modalBody}>
83
+ <section className={styles.infoSection}>
84
+ <Accordion>
85
+ <AccordionItem title={t('imagingProcedureInstructions', 'Imaging Procedure Instructions')}>
86
+ <p>
87
+ <Table size="lg" useZebraStyles={false} aria-label="sample table">
88
+ <TableBody>
89
+ {tableData.map((row, index) => (
90
+ <TableRow key={index}>
91
+ <TableCell>{row.key}</TableCell>
92
+ <TableCell>{row.value}</TableCell>
93
+ </TableRow>
94
+ ))}
95
+ </TableBody>
96
+ </Table>
97
+ </p>
98
+ </AccordionItem>
99
+ <AccordionItem title={t('imagingReport', 'Imaging Report')}>
100
+ <p>
101
+ <Table size="lg" useZebraStyles={false} aria-label="sample table">
102
+ <TableBody>
103
+ {procedureTableData.map((row, index) => (
104
+ <TableRow key={index}>
105
+ <TableCell>{row.key}</TableCell>
106
+ <TableCell>{row.value}</TableCell>
107
+ </TableRow>
108
+ ))}
109
+ </TableBody>
110
+ </Table>
111
+ </p>
112
+ </AccordionItem>
113
+ </Accordion>
114
+ </section>
115
+ <section className={styles.textAreaInput}>
116
+ <TextArea
117
+ labelText={t('nextNotes', "Reviewer's notes ")}
118
+ id="nextNotes"
119
+ name="nextNotes"
120
+ onChange={(e) => setNotes(e.target.value)}
121
+ />
122
+ </section>
123
+ </div>
124
+ </ModalBody>
125
+ <ModalFooter>
126
+ <Button kind="danger" onClick={closeModal}>
127
+ {t('cancel', 'Cancel')}
128
+ </Button>
129
+ <Button kind="primary" type="submit">
130
+ {t('approve', 'Approve')}
131
+ </Button>
132
+ </ModalFooter>
133
+ </Form>
134
+ </div>
135
+ );
136
+ };
137
+
138
+ export default ReviewImagingReportModal;
@@ -0,0 +1,5 @@
1
+ @use '@carbon/layout';
2
+
3
+ .infoSection {
4
+ margin-bottom: layout.$spacing-07;
5
+ }
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import { useOrdersWorkList } from '../../hooks/useOrdersWorklist';
3
+ import GroupedOrdersTable from '../../shared/ui/common/grouped-orders-table.component';
4
+ import { DataTableSkeleton } from '@carbon/react';
5
+ import { useTranslation } from 'react-i18next';
6
+
7
+ export const Review: React.FC = () => {
8
+ const { t } = useTranslation();
9
+ const { workListEntries, isLoading } = useOrdersWorkList('', 'COMPLETED');
10
+ const pendingReview = workListEntries.filter((item) =>
11
+ item.procedures?.some((procedure) => procedure.outcome !== 'SUCCESSFUL'),
12
+ );
13
+ return isLoading ? (
14
+ <DataTableSkeleton />
15
+ ) : (
16
+ <div>
17
+ <GroupedOrdersTable
18
+ orders={pendingReview}
19
+ showStatus={false}
20
+ showStartButton={false}
21
+ showActions={true}
22
+ showOrderType={true}
23
+ actions={[{ actionName: 'review-imaging-report-modal', order: 1 }]}
24
+ title={t('reviewOrdered', 'Review Ordered')}
25
+ />
26
+ </div>
27
+ );
28
+ };
@@ -0,0 +1,94 @@
1
+ import React, { useState } from 'react';
2
+ import { Button, Form, ModalBody, ModalFooter, ModalHeader, Checkbox, TextInput } from '@carbon/react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import styles from './add-to-worklist-dialog.scss';
5
+ import { restBaseUrl, showNotification, showSnackbar } from '@openmrs/esm-framework';
6
+ import { updateOrder } from './add-to-worklist-dialog.resource';
7
+ import { Result } from '../../work-list/work-list.resource';
8
+ import { mutate } from 'swr';
9
+
10
+ interface AddImagingToWorkListModalProps {
11
+ queueId;
12
+ order: Result;
13
+ closeModal: () => void;
14
+ }
15
+
16
+ const AddImagingToWorkListModal: React.FC<AddImagingToWorkListModalProps> = ({ order, closeModal }) => {
17
+ const { t } = useTranslation();
18
+
19
+ const [isReferredChecked, setIsReferredChecked] = useState(false);
20
+ const [referredLocation, setReferredLocation] = useState('');
21
+
22
+ const pickImagingOrder = async (event) => {
23
+ event.preventDefault();
24
+
25
+ const body = {
26
+ fulfillerComment: '',
27
+ fulfillerStatus: isReferredChecked ? 'EXCEPTION' : 'IN_PROGRESS',
28
+ };
29
+
30
+ try {
31
+ const response = await updateOrder(order.uuid, body);
32
+ if (response.ok) {
33
+ showSnackbar({
34
+ isLowContrast: true,
35
+ title: t('pickedAnOrder', 'Picked an order'),
36
+ kind: 'success',
37
+ subtitle: t('pickSuccessfully', 'You have successfully picked an Order'),
38
+ });
39
+
40
+ closeModal();
41
+ }
42
+ } catch (error) {
43
+ showNotification({
44
+ title: t(`errorPicking an order', 'Error Picking an Order`),
45
+ kind: 'error',
46
+ critical: true,
47
+ description: error?.message,
48
+ });
49
+ }
50
+ };
51
+
52
+ const handleCheckboxChange = () => {
53
+ setIsReferredChecked(!isReferredChecked);
54
+ };
55
+
56
+ return (
57
+ <div>
58
+ <Form onSubmit={pickImagingOrder}>
59
+ <ModalHeader closeModal={closeModal} title={t('pickRequest', 'Pick Request')} />
60
+ <ModalBody>
61
+ <div className={styles.modalBody}>
62
+ <section className={styles.section}>
63
+ <Checkbox
64
+ checked={isReferredChecked}
65
+ onChange={handleCheckboxChange}
66
+ labelText={'Referred'}
67
+ id="test-referred"
68
+ />
69
+ {isReferredChecked && (
70
+ <TextInput
71
+ type="text"
72
+ id="referredLocation"
73
+ labelText={'Enter Referred Location'}
74
+ value={referredLocation}
75
+ onChange={(e) => setReferredLocation(e.target.value)}
76
+ />
77
+ )}
78
+ </section>
79
+ </div>
80
+ </ModalBody>
81
+ <ModalFooter>
82
+ <Button kind="secondary" onClick={closeModal}>
83
+ {t('cancel', 'Cancel')}
84
+ </Button>
85
+ <Button type="submit" onClick={pickImagingOrder}>
86
+ {t('pickRequest', 'Pick Request')}
87
+ </Button>
88
+ </ModalFooter>
89
+ </Form>
90
+ </div>
91
+ );
92
+ };
93
+
94
+ export default AddImagingToWorkListModal;
@@ -0,0 +1,137 @@
1
+ import { FetchResponse, openmrsFetch, restBaseUrl, useConfig } from '@openmrs/esm-framework';
2
+ import { useMemo } from 'react';
3
+ import useSWR from 'swr';
4
+ import useSWRImmutable from 'swr/immutable';
5
+
6
+ export interface QueueRoomsResponse {
7
+ uuid: string;
8
+ display: string;
9
+ name: string;
10
+ description: string;
11
+ address1: string;
12
+ address2: string;
13
+ cityvillage: string;
14
+ stateprovince: string;
15
+ country: string;
16
+ postalcode: string;
17
+ latitude: string;
18
+ longitude: string;
19
+ countydistrict: string;
20
+ address3: string;
21
+ address4: string;
22
+ address5: string;
23
+ address6: string;
24
+ parentLocation: ParentLocation;
25
+ childLocations: string[];
26
+ retired: boolean;
27
+ attributes: string[];
28
+ address7: string;
29
+ address8: string;
30
+ address9: string;
31
+ address10: string;
32
+ address11: string;
33
+ address12: string;
34
+ address13: string;
35
+ address14: string;
36
+ address15: string;
37
+ resourceVersion: string;
38
+ }
39
+
40
+ export interface ParentLocation {
41
+ uuid: string;
42
+ display: string;
43
+ name: string;
44
+ description: string;
45
+ address1: string;
46
+ address2: string;
47
+ cityVillage: string;
48
+ stateProvince: string;
49
+ country: string;
50
+ postalcode: string;
51
+ latitude: string;
52
+ longitude: string;
53
+ countydistrict: string;
54
+ address3: string;
55
+ address4: string;
56
+ address5: string;
57
+ address6: string;
58
+ parentLocation: ParentLocation;
59
+ childLocations: ChildLocations[];
60
+ retired: boolean;
61
+ attributes: string[];
62
+ address7: string;
63
+ address8: string;
64
+ address9: string;
65
+ address10: string;
66
+ address11: string;
67
+ address12: string;
68
+ address13: string;
69
+ address14: string;
70
+ address15: string;
71
+ resourceversion: string;
72
+ }
73
+
74
+ export interface ChildLocations {
75
+ uuid: string;
76
+ display: string;
77
+ }
78
+
79
+ export interface ParentLocation {
80
+ uuid: string;
81
+ display: string;
82
+ }
83
+
84
+ // get queue rooms
85
+ export function useQueueRoomLocations(currentQueueLocation: string) {
86
+ const apiUrl = `${restBaseUrl}/location/${currentQueueLocation}?v=full`;
87
+ const { data, error, isLoading } = useSWR<{ data: QueueRoomsResponse }>(apiUrl, openmrsFetch);
88
+
89
+ const queueRoomLocations = useMemo(
90
+ () => data?.data?.parentLocation?.childLocations?.map((response) => response) ?? [],
91
+ [data?.data?.parentLocation?.childLocations],
92
+ );
93
+ return {
94
+ queueRoomLocations: queueRoomLocations ? queueRoomLocations : [],
95
+ isLoading,
96
+ error,
97
+ };
98
+ }
99
+
100
+ // get referral locations
101
+ export function useReferralLocations() {
102
+ const config = useConfig();
103
+ const { laboratoryReferalDestinationUuid } = config;
104
+ const apiUrl = `${restBaseUrl}/concept/${laboratoryReferalDestinationUuid}`;
105
+ const { data, isLoading } = useSWRImmutable<FetchResponse>(apiUrl, openmrsFetch);
106
+
107
+ return {
108
+ referrals: data ? data?.data?.answers : [],
109
+ isLoading,
110
+ };
111
+ }
112
+
113
+ // update Order
114
+ export async function updateOrder(uuid: string, body: any) {
115
+ const abortController = new AbortController();
116
+ return openmrsFetch(`${restBaseUrl}/order/${uuid}/fulfillerdetails`, {
117
+ method: 'POST',
118
+ headers: {
119
+ 'Content-Type': 'application/json',
120
+ },
121
+ signal: abortController.signal,
122
+ body: body,
123
+ });
124
+ }
125
+
126
+ // update Procedure
127
+ export async function updateImagingProcedure(uuid: string, body: any) {
128
+ const abortController = new AbortController();
129
+ return openmrsFetch(`${restBaseUrl}/procedure/${uuid}`, {
130
+ method: 'POST',
131
+ headers: {
132
+ 'Content-Type': 'application/json',
133
+ },
134
+ signal: abortController.signal,
135
+ body: body,
136
+ });
137
+ }