@ampath/esm-dispensing-app 1.10.0-next.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 (277) hide show
  1. package/.editorconfig +12 -0
  2. package/.eslintignore +2 -0
  3. package/.eslintrc +80 -0
  4. package/.husky/pre-commit +7 -0
  5. package/.husky/pre-push +6 -0
  6. package/.prettierignore +12 -0
  7. package/.tx/config +11 -0
  8. package/.yarn/versions/1c40b9b6.yml +0 -0
  9. package/.yarn/versions/ff162597.yml +0 -0
  10. package/LICENSE +401 -0
  11. package/README.md +124 -0
  12. package/__mocks__/react-i18next.js +51 -0
  13. package/dist/1043.js +1 -0
  14. package/dist/1043.js.map +1 -0
  15. package/dist/1119.js +1 -0
  16. package/dist/1197.js +1 -0
  17. package/dist/2146.js +1 -0
  18. package/dist/2177.js +2 -0
  19. package/dist/2177.js.LICENSE.txt +9 -0
  20. package/dist/2177.js.map +1 -0
  21. package/dist/2690.js +1 -0
  22. package/dist/2890.js +2 -0
  23. package/dist/2890.js.LICENSE.txt +14 -0
  24. package/dist/2890.js.map +1 -0
  25. package/dist/2898.js +1 -0
  26. package/dist/2898.js.map +1 -0
  27. package/dist/3041.js +1 -0
  28. package/dist/3041.js.map +1 -0
  29. package/dist/3099.js +1 -0
  30. package/dist/3184.js +2 -0
  31. package/dist/3184.js.LICENSE.txt +14 -0
  32. package/dist/3184.js.map +1 -0
  33. package/dist/3568.js +1 -0
  34. package/dist/3568.js.map +1 -0
  35. package/dist/3584.js +1 -0
  36. package/dist/4055.js +1 -0
  37. package/dist/4099.js +1 -0
  38. package/dist/4099.js.map +1 -0
  39. package/dist/4132.js +1 -0
  40. package/dist/4225.js +1 -0
  41. package/dist/4225.js.map +1 -0
  42. package/dist/4300.js +1 -0
  43. package/dist/4335.js +1 -0
  44. package/dist/4353.js +1 -0
  45. package/dist/4353.js.map +1 -0
  46. package/dist/439.js +1 -0
  47. package/dist/4618.js +1 -0
  48. package/dist/4652.js +1 -0
  49. package/dist/4944.js +1 -0
  50. package/dist/5173.js +1 -0
  51. package/dist/5241.js +1 -0
  52. package/dist/5422.js +1 -0
  53. package/dist/5422.js.map +1 -0
  54. package/dist/5442.js +1 -0
  55. package/dist/5661.js +1 -0
  56. package/dist/5897.js +1 -0
  57. package/dist/5897.js.map +1 -0
  58. package/dist/6022.js +1 -0
  59. package/dist/609.js +1 -0
  60. package/dist/609.js.map +1 -0
  61. package/dist/6468.js +1 -0
  62. package/dist/6540.js +2 -0
  63. package/dist/6540.js.LICENSE.txt +9 -0
  64. package/dist/6540.js.map +1 -0
  65. package/dist/6589.js +1 -0
  66. package/dist/6606.js +1 -0
  67. package/dist/6606.js.map +1 -0
  68. package/dist/6679.js +1 -0
  69. package/dist/6825.js +1 -0
  70. package/dist/6825.js.map +1 -0
  71. package/dist/6840.js +1 -0
  72. package/dist/6841.js +1 -0
  73. package/dist/6841.js.map +1 -0
  74. package/dist/6859.js +1 -0
  75. package/dist/7097.js +1 -0
  76. package/dist/7159.js +1 -0
  77. package/dist/723.js +1 -0
  78. package/dist/7240.js +1 -0
  79. package/dist/7240.js.map +1 -0
  80. package/dist/7255.js +1 -0
  81. package/dist/7255.js.map +1 -0
  82. package/dist/7617.js +1 -0
  83. package/dist/795.js +1 -0
  84. package/dist/8163.js +1 -0
  85. package/dist/8349.js +1 -0
  86. package/dist/8371.js +1 -0
  87. package/dist/8569.js +2 -0
  88. package/dist/8569.js.LICENSE.txt +41 -0
  89. package/dist/8569.js.map +1 -0
  90. package/dist/8600.js +1 -0
  91. package/dist/8600.js.map +1 -0
  92. package/dist/8618.js +1 -0
  93. package/dist/8885.js +1 -0
  94. package/dist/8885.js.map +1 -0
  95. package/dist/890.js +1 -0
  96. package/dist/9214.js +1 -0
  97. package/dist/9538.js +1 -0
  98. package/dist/9569.js +1 -0
  99. package/dist/961.js +2 -0
  100. package/dist/961.js.LICENSE.txt +19 -0
  101. package/dist/961.js.map +1 -0
  102. package/dist/963.js +1 -0
  103. package/dist/963.js.map +1 -0
  104. package/dist/986.js +1 -0
  105. package/dist/9879.js +1 -0
  106. package/dist/9895.js +1 -0
  107. package/dist/9900.js +1 -0
  108. package/dist/9913.js +1 -0
  109. package/dist/main.js +2 -0
  110. package/dist/main.js.LICENSE.txt +51 -0
  111. package/dist/main.js.map +1 -0
  112. package/dist/openmrs-esm-dispensing-app.js +1 -0
  113. package/dist/openmrs-esm-dispensing-app.js.buildmanifest.json +1645 -0
  114. package/dist/openmrs-esm-dispensing-app.js.map +1 -0
  115. package/dist/routes.json +1 -0
  116. package/e2e/README.md +119 -0
  117. package/e2e/commands/drug-order-operations.ts +43 -0
  118. package/e2e/commands/encounter-operations.ts +60 -0
  119. package/e2e/commands/index.ts +5 -0
  120. package/e2e/commands/patient-operations.ts +109 -0
  121. package/e2e/commands/provider-operations.ts +9 -0
  122. package/e2e/commands/types/index.ts +157 -0
  123. package/e2e/commands/visit-operations.ts +38 -0
  124. package/e2e/core/global-setup.ts +32 -0
  125. package/e2e/core/index.ts +1 -0
  126. package/e2e/core/test.ts +31 -0
  127. package/e2e/fixtures/api.ts +27 -0
  128. package/e2e/fixtures/index.ts +1 -0
  129. package/e2e/pages/dispensing-page.ts +9 -0
  130. package/e2e/pages/index.ts +1 -0
  131. package/e2e/specs/active-prescriptions.spec.ts +72 -0
  132. package/e2e/specs/close-prescription.spec.ts +71 -0
  133. package/e2e/specs/dispense-medication.spec.ts +71 -0
  134. package/e2e/specs/pause-prescription.spec.ts +72 -0
  135. package/e2e/support/github/Dockerfile +34 -0
  136. package/e2e/support/github/docker-compose.yml +24 -0
  137. package/e2e/support/github/run-e2e-docker-env.sh +42 -0
  138. package/e2e/types/index.ts +157 -0
  139. package/example.env +7 -0
  140. package/jest.config.js +24 -0
  141. package/package.json +110 -0
  142. package/playwright.config.ts +36 -0
  143. package/prettier.config.js +8 -0
  144. package/src/components/action-buttons.component.tsx +87 -0
  145. package/src/components/action-buttons.scss +16 -0
  146. package/src/components/action-buttons.test.tsx +217 -0
  147. package/src/components/medication-card.component.tsx +37 -0
  148. package/src/components/medication-card.scss +20 -0
  149. package/src/components/medication-card.test.tsx +36 -0
  150. package/src/components/medication-dispense-review.scss +108 -0
  151. package/src/components/medication-event.component.tsx +96 -0
  152. package/src/components/medication-event.scss +44 -0
  153. package/src/components/medication-event.test.tsx +212 -0
  154. package/src/components/prescription-actions/close-action-button.component.tsx +50 -0
  155. package/src/components/prescription-actions/dispense-action-button.component.tsx +57 -0
  156. package/src/components/prescription-actions/pause-action-button.component.tsx +49 -0
  157. package/src/conditions/conditions.component.tsx +118 -0
  158. package/src/conditions/conditions.resource.ts +100 -0
  159. package/src/conditions/conditions.scss +26 -0
  160. package/src/conditions/conditions.test.tsx +200 -0
  161. package/src/config-schema.ts +192 -0
  162. package/src/constants.ts +22 -0
  163. package/src/dashboard/dispensing-dashboard-link.component.tsx +36 -0
  164. package/src/dashboard/dispensing-dashboard.component.tsx +36 -0
  165. package/src/declarations.d.ts +2 -0
  166. package/src/diagnoses/diagnoses.component.tsx +111 -0
  167. package/src/diagnoses/diagnoses.resource.ts +30 -0
  168. package/src/diagnoses/diagnoses.scss +31 -0
  169. package/src/dispensing-link.component.tsx +9 -0
  170. package/src/dispensing-tiles/dispensing-tile.component.tsx +42 -0
  171. package/src/dispensing-tiles/dispensing-tile.scss +43 -0
  172. package/src/dispensing-tiles/dispensing-tiles.component.tsx +39 -0
  173. package/src/dispensing-tiles/dispensing-tiles.resource.tsx +30 -0
  174. package/src/dispensing-tiles/dispensing-tiles.scss +11 -0
  175. package/src/dispensing.component.tsx +31 -0
  176. package/src/dispensing.scss +5 -0
  177. package/src/dispensing.test.tsx +9 -0
  178. package/src/fill-prescription/fill-prescription-button.component.tsx +103 -0
  179. package/src/fill-prescription/fill-prescription-button.scss +8 -0
  180. package/src/fill-prescription/on-prescription-filled.modal.tsx +140 -0
  181. package/src/fill-prescription/on-prescription-filled.scss +7 -0
  182. package/src/forms/close-dispense-form.workspace.tsx +194 -0
  183. package/src/forms/dispense-form.workspace.test.tsx +334 -0
  184. package/src/forms/dispense-form.workspace.tsx +324 -0
  185. package/src/forms/forms.scss +152 -0
  186. package/src/forms/medication-dispense-review.component.tsx +649 -0
  187. package/src/forms/medication-dispense-review.test.tsx +158 -0
  188. package/src/forms/pause-dispense-form.workspace.tsx +196 -0
  189. package/src/forms/stock-dispense/stock-dispense.component.tsx +126 -0
  190. package/src/forms/stock-dispense/stock.resource.tsx +67 -0
  191. package/src/history/delete-confirm.modal.tsx +35 -0
  192. package/src/history/history-and-comments.component.tsx +338 -0
  193. package/src/history/history-and-comments.scss +54 -0
  194. package/src/index.ts +57 -0
  195. package/src/location/location.resource.test.tsx +108 -0
  196. package/src/location/location.resource.tsx +32 -0
  197. package/src/medication/medication.resource.test.tsx +156 -0
  198. package/src/medication/medication.resource.tsx +45 -0
  199. package/src/medication-dispense/medication-dispense.resource.test.tsx +243 -0
  200. package/src/medication-dispense/medication-dispense.resource.tsx +178 -0
  201. package/src/medication-request/medication-request.resource.test.tsx +1333 -0
  202. package/src/medication-request/medication-request.resource.tsx +257 -0
  203. package/src/patient/patient-info-cell.component.tsx +26 -0
  204. package/src/patient/patient.resources.ts +14 -0
  205. package/src/pharmacy-header/pharmacy-header.component.tsx +35 -0
  206. package/src/pharmacy-header/pharmacy-header.scss +55 -0
  207. package/src/pharmacy-header/pharmacy-illustration.component.tsx +30 -0
  208. package/src/prescriptions/patient-search-tab-panel.component.tsx +58 -0
  209. package/src/prescriptions/patient-search-tab-panel.scss +26 -0
  210. package/src/prescriptions/prescription-actions.component.tsx +24 -0
  211. package/src/prescriptions/prescription-actions.scss +14 -0
  212. package/src/prescriptions/prescription-details.component.tsx +152 -0
  213. package/src/prescriptions/prescription-details.scss +87 -0
  214. package/src/prescriptions/prescription-details.test.tsx +267 -0
  215. package/src/prescriptions/prescription-expanded.component.tsx +58 -0
  216. package/src/prescriptions/prescription-expanded.scss +56 -0
  217. package/src/prescriptions/prescription-tab-lists.component.tsx +70 -0
  218. package/src/prescriptions/prescription-tab-panel.component.tsx +83 -0
  219. package/src/prescriptions/prescriptions-table.component.tsx +189 -0
  220. package/src/prescriptions/prescriptions.scss +152 -0
  221. package/src/print-prescription/prescription-print-action.component.tsx +30 -0
  222. package/src/print-prescription/prescription-print-preview.modal.tsx +92 -0
  223. package/src/print-prescription/prescription-printout.component.tsx +154 -0
  224. package/src/print-prescription/print-prescription.scss +75 -0
  225. package/src/print-prescription/printable-prescriptions.component.tsx +57 -0
  226. package/src/routes.json +137 -0
  227. package/src/types.ts +530 -0
  228. package/src/utils.test.ts +2947 -0
  229. package/src/utils.ts +637 -0
  230. package/tools/i18next-parser.config.js +89 -0
  231. package/tools/setup-tests.ts +8 -0
  232. package/tools/update-openmrs-deps.mjs +42 -0
  233. package/translations/am.json +133 -0
  234. package/translations/ar.json +133 -0
  235. package/translations/ar_SY.json +133 -0
  236. package/translations/bn.json +133 -0
  237. package/translations/cs.json +133 -0
  238. package/translations/de.json +133 -0
  239. package/translations/en.json +133 -0
  240. package/translations/en_US.json +133 -0
  241. package/translations/es.json +133 -0
  242. package/translations/es_MX.json +133 -0
  243. package/translations/fr.json +133 -0
  244. package/translations/he.json +133 -0
  245. package/translations/hi.json +133 -0
  246. package/translations/hi_IN.json +133 -0
  247. package/translations/id.json +133 -0
  248. package/translations/it.json +133 -0
  249. package/translations/ka.json +133 -0
  250. package/translations/km.json +133 -0
  251. package/translations/ku.json +133 -0
  252. package/translations/ky.json +133 -0
  253. package/translations/lg.json +133 -0
  254. package/translations/ne.json +133 -0
  255. package/translations/pl.json +133 -0
  256. package/translations/pt.json +133 -0
  257. package/translations/pt_BR.json +133 -0
  258. package/translations/qu.json +133 -0
  259. package/translations/ro_RO.json +133 -0
  260. package/translations/ru_RU.json +133 -0
  261. package/translations/si.json +133 -0
  262. package/translations/sq.json +133 -0
  263. package/translations/sw.json +133 -0
  264. package/translations/sw_KE.json +133 -0
  265. package/translations/tr.json +133 -0
  266. package/translations/tr_TR.json +133 -0
  267. package/translations/uk.json +133 -0
  268. package/translations/uz.json +133 -0
  269. package/translations/uz@Latn.json +133 -0
  270. package/translations/uz_UZ.json +133 -0
  271. package/translations/vi.json +133 -0
  272. package/translations/zh.json +133 -0
  273. package/translations/zh_CN.json +133 -0
  274. package/translations/zh_TW.json +133 -0
  275. package/tsconfig.json +23 -0
  276. package/turbo.json +41 -0
  277. package/webpack.config.js +1 -0
@@ -0,0 +1,194 @@
1
+ import React, { useEffect, useMemo, useState } from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { Button, ComboBox, Form, InlineLoading } from '@carbon/react';
4
+ import {
5
+ ExtensionSlot,
6
+ getCoreTranslation,
7
+ ResponsiveWrapper,
8
+ showSnackbar,
9
+ useConfig,
10
+ usePatient,
11
+ Workspace2,
12
+ type Workspace2DefinitionProps,
13
+ } from '@openmrs/esm-framework';
14
+ import { saveMedicationDispense, useReasonForCloseValueSet } from '../medication-dispense/medication-dispense.resource';
15
+ import { updateMedicationRequestFulfillerStatus } from '../medication-request/medication-request.resource';
16
+ import { type MedicationDispense, MedicationDispenseStatus, MedicationRequestFulfillerStatus } from '../types';
17
+ import { type PharmacyConfig } from '../config-schema';
18
+ import { getUuidFromReference, markEncounterAsStale, revalidate } from '../utils';
19
+ import styles from './forms.scss';
20
+
21
+ type CloseDispenseFormProps = {
22
+ medicationDispense: MedicationDispense;
23
+ mode: 'enter' | 'edit';
24
+ patientUuid?: string;
25
+ encounterUuid: string;
26
+ customWorkspaceTitle?: string;
27
+ };
28
+
29
+ const CloseDispenseForm: React.FC<Workspace2DefinitionProps<CloseDispenseFormProps, {}, {}>> = ({
30
+ workspaceProps: { medicationDispense, mode, patientUuid, encounterUuid, customWorkspaceTitle },
31
+ closeWorkspace,
32
+ }) => {
33
+ const { t } = useTranslation();
34
+ const config = useConfig<PharmacyConfig>();
35
+ const { patient, isLoading } = usePatient(patientUuid);
36
+
37
+ // Keep track of medication dispense payload
38
+ const [medicationDispensePayload, setMedicationDispensePayload] = useState<MedicationDispense>();
39
+
40
+ // whether or not the form is valid and ready to submit
41
+ const [isValid, setIsValid] = useState(false);
42
+
43
+ // to prevent duplicate submits
44
+ const [isSubmitting, setIsSubmitting] = useState(false);
45
+ const [reasonsForClose, setReasonsForClose] = useState([]);
46
+ const { reasonForCloseValueSet } = useReasonForCloseValueSet(config.valueSets.reasonForClose.uuid);
47
+
48
+ useEffect(() => {
49
+ const reasonForCloseOptions = [];
50
+
51
+ if (reasonForCloseValueSet?.compose?.include) {
52
+ const uuidValueSet = reasonForCloseValueSet.compose.include.find((include) => !include.system);
53
+ if (uuidValueSet) {
54
+ uuidValueSet.concept?.forEach((concept) =>
55
+ reasonForCloseOptions.push({
56
+ id: concept.code,
57
+ text: concept.display,
58
+ }),
59
+ );
60
+ reasonForCloseOptions.sort((a, b) => a.text.localeCompare(b.text));
61
+ }
62
+ }
63
+ setReasonsForClose(reasonForCloseOptions);
64
+ }, [reasonForCloseValueSet]);
65
+
66
+ const handleSubmit = () => {
67
+ if (!isSubmitting) {
68
+ setIsSubmitting(true);
69
+ const abortController = new AbortController();
70
+ markEncounterAsStale(encounterUuid);
71
+ saveMedicationDispense(medicationDispensePayload, MedicationDispenseStatus.declined, abortController)
72
+ .then((response) => {
73
+ // only update request status when added a new dispense event, not updating
74
+ if (response.ok && !medicationDispense.id) {
75
+ return updateMedicationRequestFulfillerStatus(
76
+ getUuidFromReference(
77
+ medicationDispensePayload.authorizingPrescription[0].reference, // assumes authorizing prescription exist
78
+ ),
79
+ MedicationRequestFulfillerStatus.declined,
80
+ );
81
+ } else {
82
+ return response;
83
+ }
84
+ })
85
+ .then((response) => {
86
+ if (response.ok) {
87
+ revalidate(encounterUuid);
88
+ showSnackbar({
89
+ kind: 'success',
90
+ title: t(
91
+ mode === 'enter' ? 'medicationDispenseClosed' : 'medicationDispenseUpdated',
92
+ mode === 'enter' ? 'Medication dispense closed.' : 'Dispense record successfully updated.',
93
+ ),
94
+ });
95
+ closeWorkspace({ discardUnsavedChanges: true });
96
+ }
97
+ })
98
+ .catch((error) => {
99
+ showSnackbar({
100
+ title: t(
101
+ mode === 'enter' ? 'medicationDispenseCloseError' : 'medicationDispenseUpdatedError',
102
+ mode === 'enter' ? 'Error closing medication dispense.' : 'Error updating dispense record',
103
+ ),
104
+ kind: 'error',
105
+ subtitle: error?.message,
106
+ });
107
+ setIsSubmitting(false);
108
+ });
109
+ }
110
+ };
111
+
112
+ const checkIsValid = () => {
113
+ if (medicationDispensePayload && medicationDispensePayload.statusReasonCodeableConcept?.coding[0].code) {
114
+ setIsValid(true);
115
+ } else {
116
+ setIsValid(false);
117
+ }
118
+ };
119
+
120
+ // initialize the internal dispense payload with the dispenses passed in as props
121
+ useEffect(() => setMedicationDispensePayload(medicationDispense), [medicationDispense]);
122
+
123
+ // check is valid on any changes
124
+ useEffect(checkIsValid, [medicationDispensePayload]);
125
+
126
+ const bannerState = useMemo(() => {
127
+ if (patient) {
128
+ return {
129
+ patient,
130
+ patientUuid,
131
+ hideActionsOverflow: true,
132
+ };
133
+ }
134
+ }, [patient, patientUuid]);
135
+
136
+ return (
137
+ <Workspace2 title={customWorkspaceTitle ?? t('closePrescription', 'Close prescription')}>
138
+ <Form className={styles.formWrapper}>
139
+ <div>
140
+ {isLoading && (
141
+ <InlineLoading
142
+ className={styles.bannerLoading}
143
+ iconDescription="Loading"
144
+ description="Loading banner"
145
+ status="active"
146
+ />
147
+ )}
148
+ {patient && <ExtensionSlot name="patient-header-slot" state={bannerState} />}
149
+ <section className={styles.formGroup}>
150
+ <ResponsiveWrapper>
151
+ <ComboBox
152
+ id="reasonForPause"
153
+ items={reasonsForClose}
154
+ titleText={t('reasonForClose', 'Reason for close')}
155
+ itemToString={(item) => item?.text}
156
+ initialSelectedItem={{
157
+ id: medicationDispense.statusReasonCodeableConcept?.coding[0]?.code,
158
+ text: medicationDispense.statusReasonCodeableConcept?.text,
159
+ }}
160
+ onChange={({ selectedItem }) => {
161
+ setMedicationDispensePayload({
162
+ ...medicationDispensePayload,
163
+ statusReasonCodeableConcept: {
164
+ coding: [
165
+ {
166
+ code: selectedItem?.id,
167
+ },
168
+ ],
169
+ },
170
+ });
171
+ }}
172
+ />
173
+ </ResponsiveWrapper>
174
+ </section>
175
+ </div>
176
+ <section className={styles.buttonGroup}>
177
+ <Button
178
+ disabled={isSubmitting}
179
+ onClick={() => {
180
+ closeWorkspace();
181
+ }}
182
+ kind="secondary">
183
+ {getCoreTranslation('cancel', 'Cancel')}
184
+ </Button>
185
+ <Button disabled={!isValid || isSubmitting} onClick={handleSubmit}>
186
+ {t(mode === 'enter' ? 'close' : 'saveChanges', mode === 'enter' ? 'Close' : 'Save changes')}
187
+ </Button>
188
+ </section>
189
+ </Form>
190
+ </Workspace2>
191
+ );
192
+ };
193
+
194
+ export default CloseDispenseForm;
@@ -0,0 +1,334 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { useConfig, usePatient } from '@openmrs/esm-framework';
5
+ import { type MedicationDispense, type MedicationRequestBundle, MedicationDispenseStatus } from '../types';
6
+ import DispenseForm from './dispense-form.workspace';
7
+
8
+ const mockUseConfig = jest.mocked(useConfig);
9
+ const mockUsePatient = jest.mocked(usePatient);
10
+ const mockCloseWorkspace = jest.fn();
11
+ const mockLaunchChildWorkspace = jest.fn();
12
+
13
+ // Mock workspace props required by Workspace2DefinitionProps
14
+ const mockWorkspaceProps = {
15
+ launchChildWorkspace: mockLaunchChildWorkspace,
16
+ windowProps: {},
17
+ groupProps: {},
18
+ workspaceName: 'dispense-form',
19
+ windowName: 'dispense-form-window',
20
+ isRootWorkspace: true,
21
+ promptBeforeClosing: jest.fn(),
22
+ setTitle: jest.fn(),
23
+ showActionMenu: true,
24
+ };
25
+
26
+ // Mock the child components
27
+ jest.mock('./medication-dispense-review.component', () => ({
28
+ __esModule: true,
29
+ default: () => <div>Medication Dispense Review</div>,
30
+ }));
31
+
32
+ jest.mock('./stock-dispense/stock-dispense.component', () => ({
33
+ __esModule: true,
34
+ default: () => <div>Stock Dispense</div>,
35
+ }));
36
+
37
+ const mockPatient = {
38
+ uuid: 'patient-uuid',
39
+ display: 'Test Patient',
40
+ identifiers: [],
41
+ person: {
42
+ age: 30,
43
+ attributes: [],
44
+ birthDate: '1990-01-01',
45
+ gender: 'M',
46
+ display: 'Test Patient',
47
+ preferredAddress: {},
48
+ uuid: 'patient-uuid',
49
+ },
50
+ };
51
+
52
+ const createMockMedicationDispense = (): MedicationDispense => ({
53
+ resourceType: 'MedicationDispense',
54
+ status: MedicationDispenseStatus.completed,
55
+ medicationReference: {
56
+ reference: 'Medication/med-uuid',
57
+ display: 'Test Medication',
58
+ },
59
+ subject: {
60
+ reference: 'Patient/patient-uuid',
61
+ display: 'Test Patient',
62
+ },
63
+ performer: [
64
+ {
65
+ actor: {
66
+ reference: 'Practitioner/prac-uuid',
67
+ display: 'Test Practitioner',
68
+ },
69
+ },
70
+ ],
71
+ location: {
72
+ reference: 'Location/loc-uuid',
73
+ display: 'Test Location',
74
+ },
75
+ quantity: {
76
+ value: 30,
77
+ code: '385055001',
78
+ },
79
+ dosageInstruction: [
80
+ {
81
+ timing: {
82
+ code: {
83
+ coding: [
84
+ {
85
+ code: 'timing-code',
86
+ display: 'Once daily',
87
+ },
88
+ ],
89
+ },
90
+ },
91
+ asNeededBoolean: false,
92
+ route: {
93
+ coding: [
94
+ {
95
+ code: 'route-code',
96
+ display: 'Oral',
97
+ },
98
+ ],
99
+ },
100
+ doseAndRate: [
101
+ {
102
+ doseQuantity: {
103
+ value: 1,
104
+ code: '385055001',
105
+ },
106
+ },
107
+ ],
108
+ },
109
+ ],
110
+ substitution: {
111
+ wasSubstituted: false,
112
+ },
113
+ });
114
+
115
+ const createMockMedicationRequestBundle = (numberOfRepeatsAllowed: number | null): MedicationRequestBundle => ({
116
+ request: {
117
+ resourceType: 'MedicationRequest',
118
+ id: 'request-uuid',
119
+ meta: {
120
+ lastUpdated: '2023-01-01T00:00:00.000Z',
121
+ },
122
+ status: 'active' as any,
123
+ intent: 'order',
124
+ priority: 'routine',
125
+ medicationReference: {
126
+ reference: 'Medication/med-uuid',
127
+ display: 'Test Medication',
128
+ },
129
+ subject: {
130
+ reference: 'Patient/patient-uuid',
131
+ display: 'Test Patient',
132
+ },
133
+ encounter: {
134
+ reference: 'Encounter/enc-uuid',
135
+ type: 'Encounter',
136
+ },
137
+ requester: {
138
+ reference: 'Practitioner/prac-uuid',
139
+ type: 'Practitioner',
140
+ identifier: {
141
+ value: 'PRAC123',
142
+ },
143
+ display: 'Test Practitioner',
144
+ },
145
+ dosageInstruction: [
146
+ {
147
+ timing: {
148
+ code: {
149
+ coding: [
150
+ {
151
+ code: 'timing-code',
152
+ display: 'Once daily',
153
+ },
154
+ ],
155
+ },
156
+ },
157
+ asNeededBoolean: false,
158
+ route: {
159
+ coding: [
160
+ {
161
+ code: 'route-code',
162
+ display: 'Oral',
163
+ },
164
+ ],
165
+ },
166
+ doseAndRate: [
167
+ {
168
+ doseQuantity: {
169
+ value: 1,
170
+ code: '385055001',
171
+ },
172
+ },
173
+ ],
174
+ },
175
+ ],
176
+ dispenseRequest: {
177
+ numberOfRepeatsAllowed: numberOfRepeatsAllowed,
178
+ quantity: {
179
+ value: 30,
180
+ code: '385055001',
181
+ },
182
+ validityPeriod: {
183
+ start: '2023-01-01',
184
+ },
185
+ },
186
+ },
187
+ dispenses: [],
188
+ });
189
+
190
+ beforeEach(() => {
191
+ mockUseConfig.mockReturnValue({
192
+ dispenseBehavior: {
193
+ allowModifyingPrescription: false,
194
+ restrictTotalQuantityDispensed: false,
195
+ },
196
+ completeOrderWithThisDispense: true,
197
+ enableStockDispense: false,
198
+ });
199
+ mockUsePatient.mockReturnValue({
200
+ patient: mockPatient,
201
+ isLoading: false,
202
+ error: null,
203
+ patientUuid: 'patient-uuid',
204
+ } as any);
205
+ });
206
+
207
+ describe('DispenseForm - Complete Order Checkbox Auto-Default', () => {
208
+ test('should default checkbox to true when numberOfRepeatsAllowed is 0', () => {
209
+ const medicationDispense = createMockMedicationDispense();
210
+ const medicationRequestBundle = createMockMedicationRequestBundle(0);
211
+
212
+ render(
213
+ <DispenseForm
214
+ {...mockWorkspaceProps}
215
+ workspaceProps={{
216
+ medicationDispense,
217
+ medicationRequestBundle,
218
+ mode: 'enter',
219
+ patientUuid: 'patient-uuid',
220
+ encounterUuid: 'encounter-uuid',
221
+ quantityRemaining: 30,
222
+ quantityDispensed: 0,
223
+ }}
224
+ closeWorkspace={mockCloseWorkspace}
225
+ />,
226
+ );
227
+
228
+ const checkbox = screen.getByRole('checkbox', { name: /complete order with this dispense/i });
229
+ expect(checkbox).toBeChecked();
230
+ });
231
+
232
+ test('should default checkbox to true when numberOfRepeatsAllowed is null', () => {
233
+ const medicationDispense = createMockMedicationDispense();
234
+ const medicationRequestBundle = createMockMedicationRequestBundle(null);
235
+
236
+ render(
237
+ <DispenseForm
238
+ {...mockWorkspaceProps}
239
+ workspaceProps={{
240
+ medicationDispense,
241
+ medicationRequestBundle,
242
+ mode: 'enter',
243
+ patientUuid: 'patient-uuid',
244
+ encounterUuid: 'encounter-uuid',
245
+ quantityRemaining: 30,
246
+ quantityDispensed: 0,
247
+ }}
248
+ closeWorkspace={mockCloseWorkspace}
249
+ />,
250
+ );
251
+
252
+ const checkbox = screen.getByRole('checkbox', { name: /complete order with this dispense/i });
253
+ expect(checkbox).toBeChecked();
254
+ });
255
+
256
+ test('should default checkbox to false when numberOfRepeatsAllowed is greater than 0', () => {
257
+ const medicationDispense = createMockMedicationDispense();
258
+ const medicationRequestBundle = createMockMedicationRequestBundle(2);
259
+
260
+ render(
261
+ <DispenseForm
262
+ {...mockWorkspaceProps}
263
+ workspaceProps={{
264
+ medicationDispense,
265
+ medicationRequestBundle,
266
+ mode: 'enter',
267
+ patientUuid: 'patient-uuid',
268
+ encounterUuid: 'encounter-uuid',
269
+ quantityRemaining: 30,
270
+ quantityDispensed: 0,
271
+ }}
272
+ closeWorkspace={mockCloseWorkspace}
273
+ />,
274
+ );
275
+
276
+ const checkbox = screen.getByRole('checkbox', { name: /complete order with this dispense/i });
277
+ expect(checkbox).not.toBeChecked();
278
+ });
279
+
280
+ test('should allow user to manually uncheck the checkbox even when auto-defaulted to true', async () => {
281
+ const user = userEvent.setup();
282
+ const medicationDispense = createMockMedicationDispense();
283
+ const medicationRequestBundle = createMockMedicationRequestBundle(0);
284
+
285
+ render(
286
+ <DispenseForm
287
+ {...mockWorkspaceProps}
288
+ workspaceProps={{
289
+ medicationDispense,
290
+ medicationRequestBundle,
291
+ mode: 'enter',
292
+ patientUuid: 'patient-uuid',
293
+ encounterUuid: 'encounter-uuid',
294
+ quantityRemaining: 30,
295
+ quantityDispensed: 0,
296
+ }}
297
+ closeWorkspace={mockCloseWorkspace}
298
+ />,
299
+ );
300
+
301
+ const checkbox = screen.getByRole('checkbox', { name: /complete order with this dispense/i });
302
+ expect(checkbox).toBeChecked();
303
+
304
+ // User manually unchecks the checkbox
305
+ await user.click(checkbox);
306
+ expect(checkbox).not.toBeChecked();
307
+ });
308
+
309
+ test('should not auto-default checkbox in edit mode', () => {
310
+ const medicationDispense = createMockMedicationDispense();
311
+ medicationDispense.id = 'existing-dispense-id'; // Existing dispense
312
+ const medicationRequestBundle = createMockMedicationRequestBundle(0);
313
+
314
+ render(
315
+ <DispenseForm
316
+ {...mockWorkspaceProps}
317
+ workspaceProps={{
318
+ medicationDispense,
319
+ medicationRequestBundle,
320
+ mode: 'edit',
321
+ patientUuid: 'patient-uuid',
322
+ encounterUuid: 'encounter-uuid',
323
+ quantityRemaining: 30,
324
+ quantityDispensed: 30,
325
+ }}
326
+ closeWorkspace={mockCloseWorkspace}
327
+ />,
328
+ );
329
+
330
+ // In edit mode, the checkbox should not be rendered at all
331
+ const checkbox = screen.queryByRole('checkbox', { name: /complete order with this dispense/i });
332
+ expect(checkbox).not.toBeInTheDocument();
333
+ });
334
+ });