@ampath/esm-patient-registration-app 6.0.1-pre.96 → 9.2.0-next.12

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 (288) hide show
  1. package/dist/1119.js +1 -0
  2. package/dist/1197.js +1 -0
  3. package/dist/21.js +1 -0
  4. package/dist/21.js.map +1 -0
  5. package/dist/2146.js +1 -0
  6. package/dist/2372.js +1 -0
  7. package/dist/2372.js.map +1 -0
  8. package/dist/2470.js +1 -0
  9. package/dist/2470.js.map +1 -0
  10. package/dist/2690.js +1 -0
  11. package/dist/2913.js +2 -0
  12. package/dist/{913.js.LICENSE.txt → 2913.js.LICENSE.txt} +3 -23
  13. package/dist/2913.js.map +1 -0
  14. package/dist/3093.js +1 -0
  15. package/dist/3093.js.map +1 -0
  16. package/dist/3099.js +1 -0
  17. package/dist/3144.js +2 -0
  18. package/dist/3144.js.LICENSE.txt +19 -0
  19. package/dist/3144.js.map +1 -0
  20. package/dist/320.js +2 -0
  21. package/dist/{876.js.LICENSE.txt → 320.js.LICENSE.txt} +2 -3
  22. package/dist/320.js.map +1 -0
  23. package/dist/3464.js +1 -0
  24. package/dist/3464.js.map +1 -0
  25. package/dist/3474.js +2 -0
  26. package/dist/3474.js.LICENSE.txt +8 -0
  27. package/dist/3474.js.map +1 -0
  28. package/dist/3584.js +1 -0
  29. package/dist/4041.js +2 -0
  30. package/dist/4041.js.map +1 -0
  31. package/dist/4055.js +1 -0
  32. package/dist/4132.js +1 -0
  33. package/dist/4300.js +1 -0
  34. package/dist/4335.js +1 -0
  35. package/dist/4463.js +1 -0
  36. package/dist/4463.js.map +1 -0
  37. package/dist/4618.js +1 -0
  38. package/dist/4652.js +1 -0
  39. package/dist/4944.js +1 -0
  40. package/dist/5173.js +1 -0
  41. package/dist/5220.js +2 -0
  42. package/dist/5220.js.LICENSE.txt +29 -0
  43. package/dist/5220.js.map +1 -0
  44. package/dist/5241.js +1 -0
  45. package/dist/5442.js +1 -0
  46. package/dist/5661.js +1 -0
  47. package/dist/6022.js +1 -0
  48. package/dist/6078.js +2 -0
  49. package/dist/6078.js.LICENSE.txt +9 -0
  50. package/dist/6078.js.map +1 -0
  51. package/dist/627.js +1 -0
  52. package/dist/627.js.map +1 -0
  53. package/dist/6276.js +1 -0
  54. package/dist/6276.js.map +1 -0
  55. package/dist/6468.js +1 -0
  56. package/dist/6679.js +1 -0
  57. package/dist/6737.js +2 -0
  58. package/dist/6737.js.LICENSE.txt +9 -0
  59. package/dist/6737.js.map +1 -0
  60. package/dist/6840.js +1 -0
  61. package/dist/6859.js +1 -0
  62. package/dist/7092.js +1 -0
  63. package/dist/7092.js.map +1 -0
  64. package/dist/7097.js +1 -0
  65. package/dist/7159.js +1 -0
  66. package/dist/723.js +1 -0
  67. package/dist/7495.js +2 -0
  68. package/dist/7495.js.LICENSE.txt +9 -0
  69. package/dist/7495.js.map +1 -0
  70. package/dist/7617.js +1 -0
  71. package/dist/795.js +1 -0
  72. package/dist/8163.js +1 -0
  73. package/dist/8349.js +1 -0
  74. package/dist/8404.js +2 -0
  75. package/dist/{629.js.LICENSE.txt → 8404.js.LICENSE.txt} +9 -3
  76. package/dist/8404.js.map +1 -0
  77. package/dist/8434.js +1 -0
  78. package/dist/8434.js.map +1 -0
  79. package/dist/8618.js +1 -0
  80. package/dist/89.js +2 -0
  81. package/dist/89.js.LICENSE.txt +9 -0
  82. package/dist/89.js.map +1 -0
  83. package/dist/890.js +1 -0
  84. package/dist/9214.js +1 -0
  85. package/dist/9538.js +1 -0
  86. package/dist/9569.js +1 -0
  87. package/dist/986.js +1 -0
  88. package/dist/9876.js +1 -0
  89. package/dist/9876.js.map +1 -0
  90. package/dist/9879.js +1 -0
  91. package/dist/9895.js +1 -0
  92. package/dist/9900.js +1 -0
  93. package/dist/9913.js +1 -0
  94. package/dist/main.js +1 -1
  95. package/dist/main.js.LICENSE.txt +36 -1
  96. package/dist/main.js.map +1 -1
  97. package/dist/openmrs-esm-patient-registration-app.js +1 -0
  98. package/dist/openmrs-esm-patient-registration-app.js.buildmanifest.json +1576 -0
  99. package/dist/openmrs-esm-patient-registration-app.js.map +1 -0
  100. package/dist/routes.json +1 -1
  101. package/package.json +16 -15
  102. package/src/{add-patient-link.tsx → add-patient-link.extension.tsx} +4 -2
  103. package/src/add-patient-link.test.tsx +6 -10
  104. package/src/config-schema.ts +109 -55
  105. package/src/constants.ts +1 -1
  106. package/src/declarations.d.ts +5 -4
  107. package/src/index.ts +10 -29
  108. package/src/nav-link.test.tsx +3 -3
  109. package/src/offline.resources.ts +26 -18
  110. package/src/patient-photo.extension.tsx +3 -1
  111. package/src/patient-registration/field/address/address-field.component.tsx +58 -37
  112. package/src/patient-registration/field/address/address-hierarchy-levels.component.tsx +16 -18
  113. package/src/patient-registration/field/address/address-hierarchy.resource.tsx +3 -3
  114. package/src/patient-registration/field/address/address-hierarchy.test.tsx +290 -0
  115. package/src/patient-registration/field/address/address-search.component.tsx +7 -5
  116. package/src/patient-registration/field/address/address-search.scss +5 -5
  117. package/src/patient-registration/field/address/address-search.test.tsx +140 -0
  118. package/src/patient-registration/field/cause-of-death/cause-of-death.component.tsx +98 -0
  119. package/src/patient-registration/field/custom-field.component.tsx +3 -9
  120. package/src/patient-registration/field/date-and-time-of-death/date-and-time-of-death.component.tsx +84 -0
  121. package/src/patient-registration/field/dob/dob.component.tsx +55 -50
  122. package/src/patient-registration/field/dob/dob.test.tsx +90 -0
  123. package/src/patient-registration/field/field.component.tsx +12 -6
  124. package/src/patient-registration/field/field.resource.ts +11 -4
  125. package/src/patient-registration/field/field.scss +69 -25
  126. package/src/patient-registration/field/field.test.tsx +329 -0
  127. package/src/patient-registration/field/gender/gender-field.component.tsx +14 -9
  128. package/src/patient-registration/field/gender/gender-field.test.tsx +73 -33
  129. package/src/patient-registration/field/id/id-field.component.tsx +24 -23
  130. package/src/patient-registration/field/id/id-field.test.tsx +147 -0
  131. package/src/patient-registration/field/id/identifier-selection-overlay.component.tsx +12 -10
  132. package/src/patient-registration/field/id/identifier-selection.scss +12 -8
  133. package/src/patient-registration/field/name/name-field.component.tsx +10 -5
  134. package/src/patient-registration/field/obs/obs-field.component.tsx +59 -2
  135. package/src/patient-registration/field/obs/obs-field.test.tsx +133 -39
  136. package/src/patient-registration/field/person-attributes/coded-person-attribute-field.component.tsx +3 -3
  137. package/src/patient-registration/field/person-attributes/coded-person-attribute-field.test.tsx +141 -0
  138. package/src/patient-registration/field/person-attributes/location-person-attribute-field.component.tsx +105 -0
  139. package/src/patient-registration/field/person-attributes/location-person-attribute-field.resource.tsx +48 -0
  140. package/src/patient-registration/field/person-attributes/person-attribute-field.component.tsx +19 -22
  141. package/src/patient-registration/field/person-attributes/person-attribute-field.test.tsx +193 -0
  142. package/src/patient-registration/field/person-attributes/text-person-attribute-field.test.tsx +90 -0
  143. package/src/patient-registration/form-manager.test.ts +91 -0
  144. package/src/patient-registration/form-manager.ts +49 -23
  145. package/src/patient-registration/input/basic-input/input/input.component.tsx +6 -2
  146. package/src/patient-registration/input/basic-input/select/select-input.test.tsx +49 -0
  147. package/src/patient-registration/input/custom-input/autosuggest/autosuggest.scss +5 -5
  148. package/src/patient-registration/input/custom-input/autosuggest/autosuggest.test.tsx +164 -0
  149. package/src/patient-registration/input/custom-input/identifier/identifier-input.component.tsx +73 -36
  150. package/src/patient-registration/input/custom-input/identifier/identifier-input.test.tsx +335 -0
  151. package/src/patient-registration/input/dummy-data/dummy-data-input.component.tsx +3 -0
  152. package/src/patient-registration/input/dummy-data/dummy-data-input.test.tsx +2 -11
  153. package/src/patient-registration/input/input.scss +17 -13
  154. package/src/patient-registration/patient-registration-context.ts +22 -11
  155. package/src/patient-registration/patient-registration-hooks.ts +158 -193
  156. package/src/patient-registration/patient-registration-utils.test.ts +33 -0
  157. package/src/patient-registration/patient-registration-utils.ts +11 -13
  158. package/src/patient-registration/patient-registration.component.tsx +87 -103
  159. package/src/patient-registration/{patient-registration.resource.testt.tsx → patient-registration.resource.test.tsx} +0 -4
  160. package/src/patient-registration/patient-registration.resource.ts +27 -3
  161. package/src/patient-registration/patient-registration.scss +27 -38
  162. package/src/patient-registration/patient-registration.test.tsx +579 -0
  163. package/src/patient-registration/patient-registration.types.ts +23 -25
  164. package/src/patient-registration/section/death-info/death-info-section.component.tsx +22 -17
  165. package/src/patient-registration/section/death-info/death-info-section.test.tsx +47 -0
  166. package/src/patient-registration/section/demographics/demographics-section.component.tsx +5 -5
  167. package/src/patient-registration/section/demographics/demographics-section.test.tsx +98 -0
  168. package/src/patient-registration/section/patient-relationships/relationships-section.component.tsx +8 -7
  169. package/src/patient-registration/section/patient-relationships/relationships-section.test.tsx +113 -0
  170. package/src/patient-registration/section/patient-relationships/relationships.resource.tsx +28 -28
  171. package/src/patient-registration/section/patient-relationships/relationships.scss +4 -4
  172. package/src/patient-registration/section/section-wrapper.component.tsx +1 -1
  173. package/src/patient-registration/section/section.component.tsx +1 -1
  174. package/src/patient-registration/section/section.scss +21 -1
  175. package/src/patient-registration/ui-components/overlay/overlay.scss +8 -8
  176. package/src/patient-registration/validation/{patient-registration-validation.test.tsx → patient-registration-validation.test.ts} +71 -23
  177. package/src/patient-registration/validation/patient-registration-validation.ts +123 -0
  178. package/src/resources-context.ts +14 -0
  179. package/src/root.component.tsx +3 -3
  180. package/src/routes.json +10 -24
  181. package/src/widgets/cancel-patient-edit.modal.tsx +33 -0
  182. package/src/widgets/cancel-patient-edit.test.tsx +22 -0
  183. package/src/widgets/delete-identifier-confirmation.modal.tsx +48 -0
  184. package/src/widgets/{delete-identifier-confirmation-modal.testt.tsx → delete-identifier-confirmation.test.tsx} +5 -7
  185. package/src/widgets/edit-patient-details-button.component.tsx +0 -1
  186. package/src/widgets/edit-patient-details-button.test.tsx +35 -0
  187. package/translations/am.json +43 -35
  188. package/translations/ar.json +41 -33
  189. package/translations/ar_SY.json +119 -0
  190. package/translations/bn.json +119 -0
  191. package/translations/de.json +119 -0
  192. package/translations/en.json +44 -42
  193. package/translations/en_US.json +119 -0
  194. package/translations/es.json +69 -57
  195. package/translations/es_MX.json +119 -0
  196. package/translations/fr.json +74 -58
  197. package/translations/he.json +44 -40
  198. package/translations/hi.json +119 -0
  199. package/translations/hi_IN.json +119 -0
  200. package/translations/id.json +119 -0
  201. package/translations/it.json +119 -0
  202. package/translations/ka.json +119 -0
  203. package/translations/km.json +44 -40
  204. package/translations/ku.json +119 -0
  205. package/translations/ky.json +119 -0
  206. package/translations/lg.json +119 -0
  207. package/translations/ne.json +119 -0
  208. package/translations/pl.json +119 -0
  209. package/translations/pt.json +119 -0
  210. package/translations/pt_BR.json +119 -0
  211. package/translations/qu.json +119 -0
  212. package/translations/ro_RO.json +119 -0
  213. package/translations/ru_RU.json +119 -0
  214. package/translations/si.json +119 -0
  215. package/translations/sw.json +119 -0
  216. package/translations/sw_KE.json +119 -0
  217. package/translations/tr.json +119 -0
  218. package/translations/tr_TR.json +119 -0
  219. package/translations/uk.json +119 -0
  220. package/translations/uz.json +119 -0
  221. package/translations/uz@Latn.json +119 -0
  222. package/translations/uz_UZ.json +119 -0
  223. package/translations/vi.json +119 -0
  224. package/translations/zh.json +45 -23
  225. package/translations/zh_CN.json +39 -17
  226. package/.turbo/turbo-build.log +0 -40
  227. package/dist/132.js +0 -1
  228. package/dist/197.js +0 -1
  229. package/dist/236.js +0 -1
  230. package/dist/236.js.map +0 -1
  231. package/dist/300.js +0 -1
  232. package/dist/335.js +0 -1
  233. package/dist/372.js +0 -1
  234. package/dist/372.js.map +0 -1
  235. package/dist/41.js +0 -2
  236. package/dist/41.js.map +0 -1
  237. package/dist/449.js +0 -1
  238. package/dist/449.js.map +0 -1
  239. package/dist/464.js +0 -1
  240. package/dist/464.js.map +0 -1
  241. package/dist/495.js +0 -1
  242. package/dist/495.js.map +0 -1
  243. package/dist/55.js +0 -1
  244. package/dist/56.js +0 -1
  245. package/dist/56.js.map +0 -1
  246. package/dist/621.js +0 -1
  247. package/dist/621.js.map +0 -1
  248. package/dist/629.js +0 -2
  249. package/dist/629.js.map +0 -1
  250. package/dist/652.js +0 -1
  251. package/dist/661.js +0 -1
  252. package/dist/757.js +0 -1
  253. package/dist/757.js.map +0 -1
  254. package/dist/828.js +0 -1
  255. package/dist/828.js.map +0 -1
  256. package/dist/830.js +0 -1
  257. package/dist/830.js.map +0 -1
  258. package/dist/831.js +0 -2
  259. package/dist/831.js.LICENSE.txt +0 -3
  260. package/dist/831.js.map +0 -1
  261. package/dist/876.js +0 -2
  262. package/dist/876.js.map +0 -1
  263. package/dist/879.js +0 -1
  264. package/dist/913.js +0 -2
  265. package/dist/913.js.map +0 -1
  266. package/dist/927.js +0 -1
  267. package/dist/927.js.map +0 -1
  268. package/dist/99.js +0 -1
  269. package/dist/ampath-esm-patient-registration-app.js +0 -1
  270. package/dist/ampath-esm-patient-registration-app.js.buildmanifest.json +0 -694
  271. package/dist/ampath-esm-patient-registration-app.js.map +0 -1
  272. package/src/patient-registration/date-util.ts +0 -52
  273. package/src/patient-registration/field/person-attributes/custom-person-attribute-field.component.tsx +0 -56
  274. package/src/patient-registration/validation/patient-registration-validation.tsx +0 -60
  275. package/src/patient-verification/assets/counties.json +0 -236
  276. package/src/patient-verification/assets/verification-assets.ts +0 -11
  277. package/src/patient-verification/patient-verification-hook.tsx +0 -176
  278. package/src/patient-verification/patient-verification-utils.ts +0 -179
  279. package/src/patient-verification/patient-verification.component.tsx +0 -124
  280. package/src/patient-verification/patient-verification.scss +0 -25
  281. package/src/patient-verification/verification-modal/confirm-prompt.component.tsx +0 -72
  282. package/src/patient-verification/verification-modal/empty-prompt.component.tsx +0 -35
  283. package/src/patient-verification/verification-types.ts +0 -50
  284. package/src/widgets/cancel-patient-edit.component.tsx +0 -37
  285. package/src/widgets/delete-identifier-confirmation-modal.tsx +0 -41
  286. package/src/widgets/delete-identifier-modal.scss +0 -34
  287. /package/dist/{41.js.LICENSE.txt → 4041.js.LICENSE.txt} +0 -0
  288. /package/src/patient-registration/input/custom-input/identifier/{utils.testt.ts → utils.test.ts} +0 -0
@@ -1,7 +1,4 @@
1
- import React from 'react';
2
- import find from 'lodash-es/find';
3
- import camelCase from 'lodash-es/camelCase';
4
- import escapeRegExp from 'lodash-es/escapeRegExp';
1
+ import { camelCase, escapeRegExp, find } from 'lodash-es';
5
2
  import { getConfig, messageOmrsServiceWorker, openmrsFetch, restBaseUrl, type Session } from '@openmrs/esm-framework';
6
3
  import type {
7
4
  PatientIdentifierType,
@@ -17,8 +14,6 @@ export interface Resources {
17
14
  identifierTypes: Array<PatientIdentifierType>;
18
15
  }
19
16
 
20
- export const ResourcesContext = React.createContext<Resources>(null);
21
-
22
17
  export async function fetchCurrentSession(): Promise<Session> {
23
18
  const { data } = await cacheAndFetch<Session>(`${restBaseUrl}/session`);
24
19
  return data;
@@ -75,17 +70,21 @@ export async function fetchPatientIdentifierTypesWithSources(): Promise<Array<Pa
75
70
  // @ts-ignore Reason: The required props of the type are generated below.
76
71
  const identifierTypes: Array<PatientIdentifierType> = patientIdentifierTypes.filter(Boolean);
77
72
 
78
- const [autoGenOptions, ...allIdentifierSources] = await Promise.all([
73
+ const [autoGenOptions, identifierSourcesResponse] = await Promise.all([
79
74
  fetchAutoGenerationOptions(),
80
- ...identifierTypes.map((identifierType) => fetchIdentifierSources(identifierType.uuid)),
75
+ fetchIdentifierSources(),
81
76
  ]);
82
77
 
78
+ const allIdentifierSources = identifierSourcesResponse.data.results;
79
+
83
80
  for (let i = 0; i < identifierTypes?.length; i++) {
84
- identifierTypes[i].identifierSources = allIdentifierSources[i].data.results.map((source) => {
85
- const option = find(autoGenOptions.data.results, { source: { uuid: source.uuid } });
86
- source.autoGenerationOption = option;
87
- return source;
88
- });
81
+ identifierTypes[i].identifierSources = allIdentifierSources
82
+ .filter((source) => source.identifierType.uuid === identifierTypes[i].uuid)
83
+ .map((source) => {
84
+ const option = find(autoGenOptions.data.results, { source: { uuid: source.uuid } });
85
+ source.autoGenerationOption = option;
86
+ return source;
87
+ });
89
88
  }
90
89
 
91
90
  return identifierTypes;
@@ -94,7 +93,7 @@ export async function fetchPatientIdentifierTypesWithSources(): Promise<Array<Pa
94
93
  async function fetchPatientIdentifierTypes(): Promise<Array<FetchedPatientIdentifierType>> {
95
94
  const [patientIdentifierTypesResponse, primaryIdentifierTypeResponse] = await Promise.all([
96
95
  cacheAndFetch(
97
- `${restBaseUrl}/patientidentifiertype?v=custom:(display,uuid,name,format,required,uniquenessBehavior)`,
96
+ `${restBaseUrl}/patientidentifiertype?v=custom:(display,uuid,name,format,formatDescription,required,uniquenessBehavior)`,
98
97
  ),
99
98
  cacheAndFetch(`${restBaseUrl}/metadatamapping/termmapping?v=full&code=emr.primaryIdentifierType`),
100
99
  ]);
@@ -103,9 +102,17 @@ async function fetchPatientIdentifierTypes(): Promise<Array<FetchedPatientIdenti
103
102
  // Primary identifier type is to be kept at the top of the list.
104
103
  const patientIdentifierTypes = patientIdentifierTypesResponse?.data?.results;
105
104
 
106
- const primaryIdentifierTypeUuid = primaryIdentifierTypeResponse?.data?.results?.[0]?.metadataUuid;
105
+ // const primaryIdentifierTypeUuid = primaryIdentifierTypeResponse?.data?.results?.[0]?.metadataUuid;
106
+ const primaryIdentifierTypeUuid = '58a4732e-1359-11df-a1f1-0026b9348838';
107
107
 
108
- let identifierTypes = [];
108
+ let identifierTypes = primaryIdentifierTypeResponse?.ok
109
+ ? [
110
+ mapPatientIdentifierType(
111
+ patientIdentifierTypes?.find((type) => type.uuid === primaryIdentifierTypeUuid),
112
+ true,
113
+ ),
114
+ ]
115
+ : [];
109
116
 
110
117
  patientIdentifierTypes.forEach((type) => {
111
118
  if (type.uuid !== primaryIdentifierTypeUuid) {
@@ -118,8 +125,8 @@ async function fetchPatientIdentifierTypes(): Promise<Array<FetchedPatientIdenti
118
125
  return [];
119
126
  }
120
127
 
121
- async function fetchIdentifierSources(identifierType: string) {
122
- return await cacheAndFetch(`${restBaseUrl}/idgen/identifiersource?v=default&identifierType=${identifierType}`);
128
+ async function fetchIdentifierSources() {
129
+ return await cacheAndFetch(`${restBaseUrl}/idgen/identifiersource?v=default`);
123
130
  }
124
131
 
125
132
  async function fetchAutoGenerationOptions(abortController?: AbortController) {
@@ -144,6 +151,7 @@ function mapPatientIdentifierType(patientIdentifierType, isPrimary) {
144
151
  required: patientIdentifierType.required,
145
152
  uuid: patientIdentifierType.uuid,
146
153
  format: patientIdentifierType.format,
154
+ formatDescription: patientIdentifierType.formatDescription,
147
155
  isPrimary,
148
156
  uniquenessBehavior: patientIdentifierType.uniquenessBehavior,
149
157
  };
@@ -1,9 +1,11 @@
1
1
  import React from 'react';
2
2
  import { PatientPhoto, type PatientPhotoProps } from '@openmrs/esm-framework';
3
3
 
4
- export function PatientPhotoExtension(props: PatientPhotoProps) {
4
+ function PatientPhotoExtension(props: PatientPhotoProps) {
5
5
  console.warn(
6
6
  'Using the patient-photo extension (or patient-photo-slot slot) is deprecated. Please use the PatientPhoto component from @openmrs/esm-framework.',
7
7
  );
8
8
  return <PatientPhoto {...props} />;
9
9
  }
10
+
11
+ export default PatientPhotoExtension;
@@ -1,23 +1,36 @@
1
- import React, { useEffect, useState, useContext, useMemo } from 'react';
1
+ import React, { useEffect, useState, useMemo } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
- import { ResourcesContext } from '../../../offline.resources';
4
3
  import { SkeletonText, InlineNotification } from '@carbon/react';
5
- import { Input } from '../../input/basic-input/input/input.component';
6
- import { useConfig, useConnectivity } from '@openmrs/esm-framework';
7
- import { PatientRegistrationContext } from '../../patient-registration-context';
4
+ import { type Session, useConfig, useConnectivity } from '@openmrs/esm-framework';
8
5
  import { useOrderedAddressHierarchyLevels } from './address-hierarchy.resource';
6
+ import {
7
+ type PatientRegistrationContextProps,
8
+ PatientRegistrationContextProvider,
9
+ usePatientRegistrationContext,
10
+ } from '../../patient-registration-context';
11
+ import { ResourcesContextProvider, useResourcesContext } from '../../../resources-context';
12
+ import { Input } from '../../input/basic-input/input/input.component';
9
13
  import AddressHierarchyLevels from './address-hierarchy-levels.component';
10
14
  import AddressSearchComponent from './address-search.component';
11
15
  import styles from '../field.scss';
12
-
13
- function parseString(xmlDockAsString: string) {
14
- const parser = new DOMParser();
15
- return parser.parseFromString(xmlDockAsString, 'text/xml');
16
- }
16
+ import { type AddressTemplate } from '../../patient-registration.types';
17
17
 
18
18
  export const AddressComponent: React.FC = () => {
19
- const [selected, setSelected] = useState('');
20
- const { addressTemplate } = useContext(ResourcesContext);
19
+ const config = useConfig();
20
+ const { t } = useTranslation();
21
+ const { setFieldValue } = usePatientRegistrationContext();
22
+ const { orderedFields, isLoadingFieldOrder, errorFetchingFieldOrder } = useOrderedAddressHierarchyLevels();
23
+
24
+ const isOnline = useConnectivity();
25
+ const {
26
+ fieldConfigurations: {
27
+ address: {
28
+ useAddressHierarchy: { enabled: addressHierarchyEnabled, useQuickSearch, searchAddressByLevel },
29
+ },
30
+ },
31
+ } = config;
32
+
33
+ const { addressTemplate } = useResourcesContext();
21
34
  const addressLayout = useMemo(() => {
22
35
  if (!addressTemplate?.lines) {
23
36
  return [];
@@ -36,19 +49,7 @@ export const AddressComponent: React.FC = () => {
36
49
  });
37
50
  }, [addressTemplate]);
38
51
 
39
- const { t } = useTranslation();
40
- const config = useConfig();
41
- const isOnline = useConnectivity();
42
- const {
43
- fieldConfigurations: {
44
- address: {
45
- useAddressHierarchy: { enabled: addressHierarchyEnabled, useQuickSearch, searchAddressByLevel },
46
- },
47
- },
48
- } = config;
49
-
50
- const { setFieldValue } = useContext(PatientRegistrationContext);
51
- const { orderedFields, isLoadingFieldOrder, errorFetchingFieldOrder } = useOrderedAddressHierarchyLevels();
52
+ const [selected, setSelected] = useState('');
52
53
 
53
54
  useEffect(() => {
54
55
  if (addressTemplate?.elementDefaults) {
@@ -70,10 +71,10 @@ export const AddressComponent: React.FC = () => {
70
71
  );
71
72
  }, [isLoadingFieldOrder, errorFetchingFieldOrder, orderedFields, addressLayout]);
72
73
 
73
- if (!addressTemplate) {
74
+ if (addressTemplate && !Object.keys(addressTemplate)?.length) {
74
75
  return (
75
76
  <AddressComponentContainer>
76
- <SkeletonText />
77
+ <SkeletonText role="progressbar" />
77
78
  </AddressComponentContainer>
78
79
  );
79
80
  }
@@ -110,7 +111,7 @@ export const AddressComponent: React.FC = () => {
110
111
  style={{ margin: '0', minWidth: '100%' }}
111
112
  kind="error"
112
113
  lowContrast={true}
113
- title={t('errorFetchingOrderedFields', 'Error occured fetching ordered fields for address hierarchy')}
114
+ title={t('errorFetchingOrderedFields', 'Error occurred fetching ordered fields for address hierarchy')}
114
115
  />
115
116
  </AddressComponentContainer>
116
117
  );
@@ -139,15 +140,35 @@ export const AddressComponent: React.FC = () => {
139
140
 
140
141
  const AddressComponentContainer = ({ children }) => {
141
142
  const { t } = useTranslation();
143
+ const contextValue = useMemo(
144
+ () =>
145
+ ({
146
+ fieldConfigurations: {},
147
+ setFieldValue: () => {},
148
+ values: {},
149
+ }) as unknown as PatientRegistrationContextProps,
150
+ [],
151
+ );
152
+
142
153
  return (
143
- <div>
144
- <h4 className={styles.productiveHeading02Light}>{t('addressHeader', 'Address')}</h4>
145
- <div
146
- style={{
147
- paddingBottom: '5%',
148
- }}>
149
- {children}
150
- </div>
151
- </div>
154
+ <ResourcesContextProvider
155
+ value={{
156
+ addressTemplate: {} as AddressTemplate,
157
+ currentSession: {} as Session,
158
+ identifierTypes: [],
159
+ relationshipTypes: [],
160
+ }}>
161
+ <PatientRegistrationContextProvider value={contextValue}>
162
+ <div>
163
+ <h4 className={styles.productiveHeading02Light}>{t('addressHeader', 'Address')}</h4>
164
+ <div
165
+ style={{
166
+ paddingBottom: '5%',
167
+ }}>
168
+ {children}
169
+ </div>
170
+ </div>
171
+ </PatientRegistrationContextProvider>
172
+ </ResourcesContextProvider>
152
173
  );
153
174
  };
@@ -4,24 +4,6 @@ import { useAddressEntries, useAddressEntryFetchConfig } from './address-hierarc
4
4
  import { useField } from 'formik';
5
5
  import ComboInput from '../../input/combo-input/combo-input.component';
6
6
 
7
- interface AddressHierarchyLevelsProps {
8
- orderedAddressFields: Array<any>;
9
- }
10
-
11
- const AddressHierarchyLevels: React.FC<AddressHierarchyLevelsProps> = ({ orderedAddressFields }) => {
12
- const { t } = useTranslation();
13
-
14
- return (
15
- <>
16
- {orderedAddressFields.map((attribute) => (
17
- <AddressComboBox key={attribute.id} attribute={attribute} />
18
- ))}
19
- </>
20
- );
21
- };
22
-
23
- export default AddressHierarchyLevels;
24
-
25
7
  interface AddressComboBoxProps {
26
8
  attribute: {
27
9
  id: string;
@@ -32,6 +14,10 @@ interface AddressComboBoxProps {
32
14
  };
33
15
  }
34
16
 
17
+ interface AddressHierarchyLevelsProps {
18
+ orderedAddressFields: Array<any>;
19
+ }
20
+
35
21
  const AddressComboBox: React.FC<AddressComboBoxProps> = ({ attribute }) => {
36
22
  const { t } = useTranslation();
37
23
  const [field, meta, { setValue }] = useField(`address.${attribute.name}`);
@@ -71,3 +57,15 @@ const AddressComboBox: React.FC<AddressComboBoxProps> = ({ attribute }) => {
71
57
  />
72
58
  );
73
59
  };
60
+
61
+ const AddressHierarchyLevels: React.FC<AddressHierarchyLevelsProps> = ({ orderedAddressFields }) => {
62
+ return (
63
+ <>
64
+ {orderedAddressFields.map((attribute) => (
65
+ <AddressComboBox key={attribute.id} attribute={attribute} />
66
+ ))}
67
+ </>
68
+ );
69
+ };
70
+
71
+ export default AddressHierarchyLevels;
@@ -1,8 +1,8 @@
1
- import { useCallback, useContext, useEffect, useMemo } from 'react';
1
+ import { useCallback, useEffect, useMemo } from 'react';
2
2
  import { useField } from 'formik';
3
3
  import useSWRImmutable from 'swr/immutable';
4
4
  import { type FetchResponse, openmrsFetch } from '@openmrs/esm-framework';
5
- import { PatientRegistrationContext } from '../../patient-registration-context';
5
+ import { usePatientRegistrationContext } from '../../patient-registration-context';
6
6
 
7
7
  interface AddressFields {
8
8
  addressField: string;
@@ -57,7 +57,7 @@ export function useAddressEntries(fetchResults, searchString) {
57
57
  */
58
58
  export function useAddressEntryFetchConfig(addressField: string) {
59
59
  const { orderedFields, isLoadingFieldOrder } = useOrderedAddressHierarchyLevels();
60
- const { setFieldValue } = useContext(PatientRegistrationContext);
60
+ const { setFieldValue } = usePatientRegistrationContext();
61
61
  const [, { value: addressValues }] = useField('address');
62
62
 
63
63
  const index = useMemo(
@@ -0,0 +1,290 @@
1
+ import React from 'react';
2
+ import { screen } from '@testing-library/react';
3
+ import { Formik, Form } from 'formik';
4
+ import { getDefaultsFromConfigSchema, useConfig } from '@openmrs/esm-framework';
5
+ import { mockedAddressTemplate, mockedOrderedFields, mockOpenmrsId, mockPatient, mockSession } from '__mocks__';
6
+ import { renderWithContext } from 'tools';
7
+ import { type AddressTemplate } from '../../patient-registration.types';
8
+ import { type RegistrationConfig, esmPatientRegistrationSchema } from '../../../config-schema';
9
+ import { type Resources } from '../../../offline.resources';
10
+ import {
11
+ PatientRegistrationContextProvider,
12
+ type PatientRegistrationContextProps,
13
+ } from '../../patient-registration-context';
14
+ import { useOrderedAddressHierarchyLevels } from './address-hierarchy.resource';
15
+ import { ResourcesContextProvider } from '../../../resources-context';
16
+ import { AddressComponent } from './address-field.component';
17
+
18
+ const mockUseConfig = jest.mocked(useConfig<RegistrationConfig>);
19
+ const mockUseOrderedAddressHierarchyLevels = jest.mocked(useOrderedAddressHierarchyLevels);
20
+
21
+ const mockResourcesContextValue = {
22
+ addressTemplate: {} as AddressTemplate,
23
+ currentSession: mockSession.data,
24
+ identifierTypes: [],
25
+ relationshipTypes: [],
26
+ } as Resources;
27
+
28
+ const mockInitialFormValues = {
29
+ additionalFamilyName: '',
30
+ additionalGivenName: '',
31
+ additionalMiddleName: '',
32
+ addNameInLocalLanguage: false,
33
+ address: {},
34
+ birthdate: '',
35
+ birthdateEstimated: false,
36
+ deathCause: '',
37
+ deathDate: '',
38
+ deathTime: '',
39
+ deathTimeFormat: 'AM' as 'AM' | 'PM',
40
+ nonCodedCauseOfDeath: '',
41
+ familyName: 'Doe',
42
+ gender: 'male',
43
+ givenName: 'John',
44
+ identifiers: mockOpenmrsId,
45
+ isDead: false,
46
+ middleName: 'Test',
47
+ monthsEstimated: 0,
48
+ patientUuid: mockPatient.uuid,
49
+ relationships: [],
50
+ telephoneNumber: '',
51
+ yearsEstimated: 0,
52
+ };
53
+
54
+ const initialContextValues: PatientRegistrationContextProps = {
55
+ currentPhoto: '',
56
+ inEditMode: false,
57
+ identifierTypes: [],
58
+ initialFormValues: mockInitialFormValues,
59
+ isOffline: false,
60
+ setCapturePhotoProps: jest.fn(),
61
+ setFieldValue: jest.fn(),
62
+ setFieldTouched: jest.fn(),
63
+ setInitialFormValues: jest.fn(),
64
+ validationSchema: null,
65
+ values: mockInitialFormValues,
66
+ };
67
+
68
+ jest.mock('./address-hierarchy.resource', () => ({
69
+ ...jest.requireActual('./address-hierarchy.resource'),
70
+ useOrderedAddressHierarchyLevels: jest.fn(),
71
+ }));
72
+
73
+ async function renderAddressHierarchy(contextValues: PatientRegistrationContextProps) {
74
+ await renderWithContext(
75
+ <PatientRegistrationContextProvider value={contextValues}>
76
+ <Formik initialValues={mockInitialFormValues} onSubmit={null}>
77
+ <Form>
78
+ <AddressComponent />
79
+ </Form>
80
+ </Formik>
81
+ </PatientRegistrationContextProvider>,
82
+ ResourcesContextProvider,
83
+ mockResourcesContextValue,
84
+ );
85
+ }
86
+
87
+ describe('Address hierarchy', () => {
88
+ it('renders a loading skeleton when the address template is loading', () => {
89
+ mockUseConfig.mockReturnValue({
90
+ ...getDefaultsFromConfigSchema(esmPatientRegistrationSchema),
91
+ fieldConfigurations: {
92
+ address: {
93
+ useAddressHierarchy: {
94
+ enabled: false,
95
+ useQuickSearch: false,
96
+ searchAddressByLevel: false,
97
+ },
98
+ },
99
+ } as RegistrationConfig['fieldConfigurations'],
100
+ });
101
+
102
+ mockUseOrderedAddressHierarchyLevels.mockReturnValue({
103
+ orderedFields: [],
104
+ isLoadingFieldOrder: false,
105
+ errorFetchingFieldOrder: undefined,
106
+ });
107
+
108
+ renderAddressHierarchy(initialContextValues);
109
+ expect(screen.getByRole('progressbar')).toBeInTheDocument();
110
+ });
111
+
112
+ it('renders a loading skeleton when the address hierarchy feature is enabled and address hierarchy order levels are loading', () => {
113
+ mockUseConfig.mockReturnValue({
114
+ ...getDefaultsFromConfigSchema(esmPatientRegistrationSchema),
115
+ fieldConfigurations: {
116
+ address: {
117
+ useAddressHierarchy: {
118
+ enabled: true,
119
+ useQuickSearch: false,
120
+ searchAddressByLevel: false,
121
+ },
122
+ },
123
+ } as RegistrationConfig['fieldConfigurations'],
124
+ });
125
+
126
+ mockUseOrderedAddressHierarchyLevels.mockReturnValue({
127
+ orderedFields: [],
128
+ isLoadingFieldOrder: true,
129
+ errorFetchingFieldOrder: undefined,
130
+ });
131
+
132
+ renderAddressHierarchy(initialContextValues);
133
+ expect(screen.getByRole('progressbar')).toBeInTheDocument();
134
+ });
135
+
136
+ it('renders a loading skeleton when the address hierarchy feature is enabled and address hierarchy order levels are loading', () => {
137
+ mockUseConfig.mockReturnValue({
138
+ ...getDefaultsFromConfigSchema(esmPatientRegistrationSchema),
139
+ fieldConfigurations: {
140
+ address: {
141
+ useAddressHierarchy: {
142
+ enabled: true,
143
+ useQuickSearch: false,
144
+ searchAddressByLevel: false,
145
+ },
146
+ },
147
+ } as RegistrationConfig['fieldConfigurations'],
148
+ });
149
+
150
+ mockUseOrderedAddressHierarchyLevels.mockReturnValue({
151
+ orderedFields: [],
152
+ isLoadingFieldOrder: false,
153
+ errorFetchingFieldOrder: undefined,
154
+ });
155
+
156
+ renderAddressHierarchy(initialContextValues);
157
+ expect(screen.getByRole('progressbar')).toBeInTheDocument();
158
+ });
159
+
160
+ it('renders the address component with address hierarchy disabled', () => {
161
+ mockUseConfig.mockReturnValue({
162
+ ...getDefaultsFromConfigSchema(esmPatientRegistrationSchema),
163
+ fieldConfigurations: {
164
+ address: {
165
+ useAddressHierarchy: {
166
+ enabled: false,
167
+ useQuickSearch: false,
168
+ searchAddressByLevel: false,
169
+ },
170
+ },
171
+ } as RegistrationConfig['fieldConfigurations'],
172
+ });
173
+
174
+ mockUseOrderedAddressHierarchyLevels.mockReturnValue({
175
+ orderedFields: [],
176
+ isLoadingFieldOrder: false,
177
+ errorFetchingFieldOrder: undefined,
178
+ });
179
+
180
+ mockResourcesContextValue.addressTemplate = mockedAddressTemplate;
181
+
182
+ renderAddressHierarchy(initialContextValues);
183
+
184
+ const allFields = mockedAddressTemplate.lines.flat().filter(({ isToken }) => isToken === 'IS_ADDR_TOKEN');
185
+ allFields.forEach((field) => {
186
+ const textFieldInput = screen.getByLabelText(`${field.displayText} (optional)`);
187
+ expect(textFieldInput).toBeInTheDocument();
188
+ });
189
+ });
190
+
191
+ it('renders the address hierarchy fields in order if the address hierarchy feature is enabled', () => {
192
+ mockUseConfig.mockReturnValue({
193
+ ...getDefaultsFromConfigSchema(esmPatientRegistrationSchema),
194
+ fieldConfigurations: {
195
+ address: {
196
+ useAddressHierarchy: {
197
+ enabled: true,
198
+ useQuickSearch: false,
199
+ searchAddressByLevel: false,
200
+ },
201
+ },
202
+ } as RegistrationConfig['fieldConfigurations'],
203
+ });
204
+
205
+ mockUseOrderedAddressHierarchyLevels.mockReturnValue({
206
+ orderedFields: [],
207
+ isLoadingFieldOrder: false,
208
+ errorFetchingFieldOrder: undefined,
209
+ });
210
+
211
+ mockResourcesContextValue.addressTemplate = mockedAddressTemplate;
212
+
213
+ renderAddressHierarchy(initialContextValues);
214
+
215
+ const allFields = mockedAddressTemplate.lines.flat().filter(({ isToken }) => isToken === 'IS_ADDR_TOKEN');
216
+ const orderMap = Object.fromEntries(mockedOrderedFields.map((field, indx) => [field, indx]));
217
+ allFields.sort(
218
+ (existingField1, existingField2) =>
219
+ orderMap[existingField1.codeName ?? 0] - orderMap[existingField2.codeName ?? 0],
220
+ );
221
+ allFields.forEach((field) => {
222
+ const textFieldInput = screen.getByLabelText(`${field.displayText} (optional)`);
223
+ expect(textFieldInput).toBeInTheDocument();
224
+ });
225
+ });
226
+
227
+ it('renders the quick search bar above the address hierarchy fields when the address hierarchy feature is enabled and useQuickSearch is set to true', () => {
228
+ mockUseConfig.mockReturnValue({
229
+ ...getDefaultsFromConfigSchema(esmPatientRegistrationSchema),
230
+ fieldConfigurations: {
231
+ address: {
232
+ useAddressHierarchy: {
233
+ enabled: true,
234
+ useQuickSearch: true,
235
+ searchAddressByLevel: false,
236
+ },
237
+ },
238
+ } as RegistrationConfig['fieldConfigurations'],
239
+ });
240
+
241
+ mockUseOrderedAddressHierarchyLevels.mockReturnValue({
242
+ orderedFields: [],
243
+ isLoadingFieldOrder: false,
244
+ errorFetchingFieldOrder: undefined,
245
+ });
246
+
247
+ mockResourcesContextValue.addressTemplate = mockedAddressTemplate;
248
+
249
+ renderAddressHierarchy(initialContextValues);
250
+
251
+ const searchbox = screen.getByRole('searchbox', { name: /search address/i });
252
+ expect(searchbox).toBeInTheDocument();
253
+ });
254
+
255
+ it('renders combobox fields when address hierarchy is enabled and searchAddressByLevel is set to true', () => {
256
+ mockUseConfig.mockReturnValue({
257
+ ...getDefaultsFromConfigSchema(esmPatientRegistrationSchema),
258
+ fieldConfigurations: {
259
+ address: {
260
+ useAddressHierarchy: {
261
+ enabled: true,
262
+ useQuickSearch: false,
263
+ searchAddressByLevel: true,
264
+ },
265
+ },
266
+ } as RegistrationConfig['fieldConfigurations'],
267
+ });
268
+
269
+ mockUseOrderedAddressHierarchyLevels.mockReturnValue({
270
+ orderedFields: [],
271
+ isLoadingFieldOrder: false,
272
+ errorFetchingFieldOrder: undefined,
273
+ });
274
+
275
+ mockResourcesContextValue.addressTemplate = mockedAddressTemplate;
276
+
277
+ renderAddressHierarchy(initialContextValues);
278
+
279
+ const allFields = mockedAddressTemplate.lines.flat().filter(({ isToken }) => isToken === 'IS_ADDR_TOKEN');
280
+ const orderMap = Object.fromEntries(mockedOrderedFields.map((field, indx) => [field, indx]));
281
+ allFields.sort(
282
+ (existingField1, existingField2) =>
283
+ orderMap[existingField1.codeName ?? 0] - orderMap[existingField2.codeName ?? 0],
284
+ );
285
+ allFields.forEach((field) => {
286
+ const textFieldInput = screen.getByLabelText(`${field.displayText} (optional)`);
287
+ expect(textFieldInput).toBeInTheDocument();
288
+ });
289
+ });
290
+ });
@@ -1,8 +1,8 @@
1
1
  import React, { useState, useRef, useEffect, useMemo } from 'react';
2
- import { useAddressHierarchy } from './address-hierarchy.resource';
3
- import { Search } from '@carbon/react';
4
- import { useTranslation } from 'react-i18next';
5
2
  import { useFormikContext } from 'formik';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { Search } from '@carbon/react';
5
+ import { useAddressHierarchy } from './address-hierarchy.resource';
6
6
  import styles from './address-search.scss';
7
7
 
8
8
  interface AddressSearchComponentProps {
@@ -14,8 +14,10 @@ const AddressSearchComponent: React.FC<AddressSearchComponentProps> = ({ address
14
14
  const separator = ' > ';
15
15
  const searchBox = useRef(null);
16
16
  const wrapper = useRef(null);
17
- const [searchString, setSearchString] = useState<string>('');
18
- const { addresses, isLoading, error } = useAddressHierarchy(searchString, separator);
17
+ const [searchString, setSearchString] = useState('');
18
+
19
+ const { addresses } = useAddressHierarchy(searchString, separator);
20
+
19
21
  const addressOptions: Array<string> = useMemo(() => {
20
22
  const options: Set<string> = new Set();
21
23
  addresses.forEach((address) => {
@@ -1,6 +1,6 @@
1
- @use '@carbon/styles/scss/spacing';
2
- @use '@carbon/styles/scss/type';
3
- @import '~@openmrs/esm-styleguide/src/vars';
1
+ @use '@carbon/layout';
2
+ @use '@carbon/type';
3
+ @use '@openmrs/esm-styleguide/src/vars' as *;
4
4
 
5
5
  .label01 {
6
6
  @include type.type-style('label-01');
@@ -17,13 +17,13 @@
17
17
  position: absolute;
18
18
  left: 0;
19
19
  background-color: #fff;
20
- margin-bottom: 20px;
20
+ margin-bottom: 1.25rem;
21
21
  z-index: 99;
22
22
  border: 1px solid $ui-03;
23
23
  }
24
24
 
25
25
  .suggestions li {
26
- padding: spacing.$spacing-05;
26
+ padding: layout.$spacing-05;
27
27
  line-height: 1.29;
28
28
  color: #525252;
29
29
  border-bottom: 1px solid #8d8d8d;