@kenyaemr/esm-patient-registration-app 4.3.0

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 (162) hide show
  1. package/README.md +7 -0
  2. package/__mocks__/autogenerationoptions.mock.ts +34 -0
  3. package/__mocks__/react-i18next.js +49 -0
  4. package/dist/144.js +2 -0
  5. package/dist/144.js.LICENSE.txt +27 -0
  6. package/dist/144.js.map +1 -0
  7. package/dist/207.js +1 -0
  8. package/dist/207.js.map +1 -0
  9. package/dist/317.js +2 -0
  10. package/dist/317.js.LICENSE.txt +6 -0
  11. package/dist/317.js.map +1 -0
  12. package/dist/330.js +1 -0
  13. package/dist/330.js.map +1 -0
  14. package/dist/574.js +1 -0
  15. package/dist/59.js +1 -0
  16. package/dist/59.js.map +1 -0
  17. package/dist/591.js +2 -0
  18. package/dist/591.js.LICENSE.txt +32 -0
  19. package/dist/591.js.map +1 -0
  20. package/dist/62.js +1 -0
  21. package/dist/62.js.map +1 -0
  22. package/dist/635.js +1 -0
  23. package/dist/635.js.map +1 -0
  24. package/dist/68.js +1 -0
  25. package/dist/68.js.map +1 -0
  26. package/dist/735.js +1 -0
  27. package/dist/735.js.map +1 -0
  28. package/dist/757.js +1 -0
  29. package/dist/784.js +2 -0
  30. package/dist/784.js.LICENSE.txt +9 -0
  31. package/dist/784.js.map +1 -0
  32. package/dist/805.js +1 -0
  33. package/dist/805.js.map +1 -0
  34. package/dist/807.js +1 -0
  35. package/dist/821.js +1 -0
  36. package/dist/821.js.map +1 -0
  37. package/dist/822.js +1 -0
  38. package/dist/822.js.map +1 -0
  39. package/dist/858.js +2 -0
  40. package/dist/858.js.LICENSE.txt +3 -0
  41. package/dist/858.js.map +1 -0
  42. package/dist/887.js +1 -0
  43. package/dist/887.js.map +1 -0
  44. package/dist/9.js +2 -0
  45. package/dist/9.js.LICENSE.txt +9 -0
  46. package/dist/9.js.map +1 -0
  47. package/dist/975.js +1 -0
  48. package/dist/975.js.map +1 -0
  49. package/dist/main.js +2 -0
  50. package/dist/main.js.LICENSE.txt +9 -0
  51. package/dist/main.js.map +1 -0
  52. package/dist/openmrs-esm-patient-registration-app.js +1 -0
  53. package/dist/openmrs-esm-patient-registration-app.js.buildmanifest.json +623 -0
  54. package/dist/openmrs-esm-patient-registration-app.js.map +1 -0
  55. package/dist/openmrs-esm-patient-registration-app.old +1 -0
  56. package/docs/images/patient-registration-hierarchy.png +0 -0
  57. package/package.json +55 -0
  58. package/src/add-patient-link.scss +3 -0
  59. package/src/add-patient-link.tsx +21 -0
  60. package/src/config-schema.ts +405 -0
  61. package/src/constants.ts +14 -0
  62. package/src/declarations.d.tsx +4 -0
  63. package/src/index.ts +131 -0
  64. package/src/nav-link.tsx +10 -0
  65. package/src/offline.resources.ts +109 -0
  66. package/src/offline.ts +90 -0
  67. package/src/patient-registration/before-save-prompt.tsx +72 -0
  68. package/src/patient-registration/date-util.ts +52 -0
  69. package/src/patient-registration/field/__mocks__/field.resource.ts +60 -0
  70. package/src/patient-registration/field/address/address-field.component.tsx +31 -0
  71. package/src/patient-registration/field/address/address-hierarchy.component.tsx +143 -0
  72. package/src/patient-registration/field/address/address-hierarchy.test.tsx +181 -0
  73. package/src/patient-registration/field/address/address-search.component.tsx +98 -0
  74. package/src/patient-registration/field/address/address-search.scss +53 -0
  75. package/src/patient-registration/field/custom-field.component.tsx +25 -0
  76. package/src/patient-registration/field/dob/dob.component.tsx +143 -0
  77. package/src/patient-registration/field/dob/dob.test.tsx +73 -0
  78. package/src/patient-registration/field/field.component.tsx +44 -0
  79. package/src/patient-registration/field/field.resource.ts +35 -0
  80. package/src/patient-registration/field/field.scss +127 -0
  81. package/src/patient-registration/field/gender/gender-field.component.tsx +49 -0
  82. package/src/patient-registration/field/gender/gender-field.test.tsx +66 -0
  83. package/src/patient-registration/field/id/id-field.component.tsx +142 -0
  84. package/src/patient-registration/field/id/identifier-selection-overlay.tsx +194 -0
  85. package/src/patient-registration/field/id/identifier-selection.scss +37 -0
  86. package/src/patient-registration/field/name/name-field.component.tsx +109 -0
  87. package/src/patient-registration/field/obs/obs-field.component.tsx +185 -0
  88. package/src/patient-registration/field/obs/obs-field.test.tsx +127 -0
  89. package/src/patient-registration/field/person-attributes/coded-attributes.component.tsx +59 -0
  90. package/src/patient-registration/field/person-attributes/coded-person-attribute-field.component.tsx +68 -0
  91. package/src/patient-registration/field/person-attributes/person-attribute-field.component.tsx +81 -0
  92. package/src/patient-registration/field/person-attributes/person-attributes.resource.tsx +20 -0
  93. package/src/patient-registration/field/person-attributes/text-person-attribute-field.component.tsx +57 -0
  94. package/src/patient-registration/form-manager.test.ts +68 -0
  95. package/src/patient-registration/form-manager.ts +413 -0
  96. package/src/patient-registration/input/basic-input/input/input.component.tsx +59 -0
  97. package/src/patient-registration/input/basic-input/input/input.test.tsx +170 -0
  98. package/src/patient-registration/input/basic-input/select/select-input.component.tsx +32 -0
  99. package/src/patient-registration/input/basic-input/select/select-input.test.tsx +32 -0
  100. package/src/patient-registration/input/combo-input/combo-input.component.tsx +76 -0
  101. package/src/patient-registration/input/combo-input/combo-input.test.tsx +43 -0
  102. package/src/patient-registration/input/custom-input/autosuggest/autosuggest.component.tsx +84 -0
  103. package/src/patient-registration/input/custom-input/autosuggest/autosuggest.scss +53 -0
  104. package/src/patient-registration/input/custom-input/autosuggest/autosuggest.test.tsx +109 -0
  105. package/src/patient-registration/input/custom-input/estimated-age/estimated-age-input.component.tsx +32 -0
  106. package/src/patient-registration/input/custom-input/estimated-age/estimated-age-input.test.tsx +36 -0
  107. package/src/patient-registration/input/custom-input/identifier/identifier-input.component.tsx +156 -0
  108. package/src/patient-registration/input/custom-input/identifier/identifier-input.test.tsx +110 -0
  109. package/src/patient-registration/input/custom-input/identifier/utils.ts +19 -0
  110. package/src/patient-registration/input/custom-input/unidentified-patient/unidentified-patient-input.component.tsx +24 -0
  111. package/src/patient-registration/input/custom-input/unidentified-patient/unidentified-patient-input.test.tsx +39 -0
  112. package/src/patient-registration/input/dummy-data/dummy-data-input.component.tsx +53 -0
  113. package/src/patient-registration/input/dummy-data/dummy-data-input.test.tsx +43 -0
  114. package/src/patient-registration/input/input.scss +108 -0
  115. package/src/patient-registration/patient-registration-context.ts +24 -0
  116. package/src/patient-registration/patient-registration-hooks.ts +320 -0
  117. package/src/patient-registration/patient-registration-types.tsx +271 -0
  118. package/src/patient-registration/patient-registration-utils.ts +219 -0
  119. package/src/patient-registration/patient-registration.component.tsx +250 -0
  120. package/src/patient-registration/patient-registration.resource.test.tsx +26 -0
  121. package/src/patient-registration/patient-registration.resource.tsx +296 -0
  122. package/src/patient-registration/patient-registration.scss +94 -0
  123. package/src/patient-registration/patient-registration.test.tsx +436 -0
  124. package/src/patient-registration/section/death-info/death-info-section.component.tsx +30 -0
  125. package/src/patient-registration/section/death-info/death-info-section.test.tsx +73 -0
  126. package/src/patient-registration/section/demographics/demographics-section.component.tsx +30 -0
  127. package/src/patient-registration/section/demographics/demographics-section.test.tsx +84 -0
  128. package/src/patient-registration/section/generic-section.component.tsx +17 -0
  129. package/src/patient-registration/section/patient-relationships/relationships-section.component.tsx +226 -0
  130. package/src/patient-registration/section/patient-relationships/relationships.resource.tsx +78 -0
  131. package/src/patient-registration/section/patient-relationships/relationships.scss +35 -0
  132. package/src/patient-registration/section/section-wrapper.component.tsx +40 -0
  133. package/src/patient-registration/section/section.component.tsx +23 -0
  134. package/src/patient-registration/section/section.scss +1 -0
  135. package/src/patient-registration/ui-components/overlay/index.tsx +51 -0
  136. package/src/patient-registration/ui-components/overlay/overlay.scss +63 -0
  137. package/src/patient-registration/validation/patient-registration-validation.test.tsx +129 -0
  138. package/src/patient-registration/validation/patient-registration-validation.tsx +46 -0
  139. package/src/patient-verification/assets/counties.json +236 -0
  140. package/src/patient-verification/assets/verification-assets.ts +11 -0
  141. package/src/patient-verification/patient-verification-hook.tsx +156 -0
  142. package/src/patient-verification/patient-verification-utils.ts +173 -0
  143. package/src/patient-verification/patient-verification.component.tsx +118 -0
  144. package/src/patient-verification/patient-verification.scss +30 -0
  145. package/src/patient-verification/verification-modal/confirm-prompt.component.tsx +69 -0
  146. package/src/patient-verification/verification-modal/empty-prompt.component.tsx +35 -0
  147. package/src/patient-verification/verification-types.ts +50 -0
  148. package/src/resource.ts +12 -0
  149. package/src/root.component.tsx +66 -0
  150. package/src/root.scss +7 -0
  151. package/src/root.test.tsx +32 -0
  152. package/src/widgets/cancel-patient-edit.component.tsx +37 -0
  153. package/src/widgets/delete-identifier-confirmation-modal.tsx +41 -0
  154. package/src/widgets/delete-identifier-modal.scss +34 -0
  155. package/src/widgets/display-photo.component.tsx +30 -0
  156. package/src/widgets/edit-patient-details-button.component.tsx +34 -0
  157. package/src/widgets/edit-patient-details-button.scss +3 -0
  158. package/translations/en.json +108 -0
  159. package/translations/fr.json +89 -0
  160. package/translations/km.json +89 -0
  161. package/tsconfig.json +5 -0
  162. package/webpack.config.js +1 -0
@@ -0,0 +1,296 @@
1
+ import { useMemo } from 'react';
2
+ import useSWR from 'swr';
3
+ import useSWRImmutable from 'swr/immutable';
4
+ import { FetchResponse, openmrsFetch, useConfig } from '@openmrs/esm-framework';
5
+ import { Patient, Relationship, PatientIdentifier, Encounter } from './patient-registration-types';
6
+
7
+ export const uuidIdentifier = '05a29f94-c0ed-11e2-94be-8c13b969e334';
8
+ export const uuidTelephoneNumber = '14d4f066-15f5-102d-96e4-000c29c2a5d7';
9
+
10
+ function dataURItoFile(dataURI: string) {
11
+ const byteString = atob(dataURI.split(',')[1]);
12
+ const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
13
+ // write the bytes of the string to a typed array
14
+ const buffer = new Uint8Array(byteString.length);
15
+
16
+ for (let i = 0; i < byteString.length; i++) {
17
+ buffer[i] = byteString.charCodeAt(i);
18
+ }
19
+
20
+ const blob = new Blob([buffer], { type: mimeString });
21
+ return new File([blob], 'patient-photo.png');
22
+ }
23
+
24
+ export function savePatient(patient: Patient | null, updatePatientUuid?: string) {
25
+ const abortController = new AbortController();
26
+
27
+ return openmrsFetch(`/ws/rest/v1/patient/${updatePatientUuid || ''}`, {
28
+ headers: {
29
+ 'Content-Type': 'application/json',
30
+ },
31
+ method: 'POST',
32
+ body: patient,
33
+ signal: abortController.signal,
34
+ });
35
+ }
36
+
37
+ export function saveEncounter(encounter: Encounter) {
38
+ const abortController = new AbortController();
39
+
40
+ return openmrsFetch(`/ws/rest/v1/encounter`, {
41
+ headers: {
42
+ 'Content-Type': 'application/json',
43
+ },
44
+ method: 'POST',
45
+ body: encounter,
46
+ signal: abortController.signal,
47
+ });
48
+ }
49
+
50
+ export function generateIdentifier(source: string) {
51
+ const abortController = new AbortController();
52
+
53
+ return openmrsFetch(`/ws/rest/v1/idgen/identifiersource/${source}/identifier`, {
54
+ headers: {
55
+ 'Content-Type': 'application/json',
56
+ },
57
+ method: 'POST',
58
+ body: {},
59
+ signal: abortController.signal,
60
+ });
61
+ }
62
+
63
+ export function deletePersonName(nameUuid: string, personUuid: string) {
64
+ const abortController = new AbortController();
65
+
66
+ return openmrsFetch(`/ws/rest/v1/person/${personUuid}/name/${nameUuid}`, {
67
+ method: 'DELETE',
68
+ signal: abortController.signal,
69
+ });
70
+ }
71
+
72
+ export function saveRelationship(relationship: Relationship) {
73
+ const abortController = new AbortController();
74
+
75
+ return openmrsFetch('/ws/rest/v1/relationship', {
76
+ headers: {
77
+ 'Content-Type': 'application/json',
78
+ },
79
+ method: 'POST',
80
+ body: relationship,
81
+ signal: abortController.signal,
82
+ });
83
+ }
84
+
85
+ export function updateRelationship(relationshipUuid, relationship: { relationshipType: string }) {
86
+ const abortController = new AbortController();
87
+
88
+ return openmrsFetch(`/ws/rest/v1/relationship/${relationshipUuid}`, {
89
+ headers: {
90
+ 'Content-Type': 'application/json',
91
+ },
92
+ method: 'POST',
93
+ body: { relationshipType: relationship.relationshipType },
94
+ signal: abortController.signal,
95
+ });
96
+ }
97
+
98
+ export function deleteRelationship(relationshipUuid) {
99
+ const abortController = new AbortController();
100
+
101
+ return openmrsFetch(`/ws/rest/v1/relationship/${relationshipUuid}`, {
102
+ headers: {
103
+ 'Content-Type': 'application/json',
104
+ },
105
+ method: 'DELETE',
106
+ signal: abortController.signal,
107
+ });
108
+ }
109
+
110
+ export async function savePatientPhoto(
111
+ patientUuid: string,
112
+ content: string,
113
+ url: string,
114
+ date: string,
115
+ conceptUuid: string,
116
+ ) {
117
+ const abortController = new AbortController();
118
+
119
+ const formData = new FormData();
120
+ formData.append('patient', patientUuid);
121
+ formData.append('file', dataURItoFile(content));
122
+ formData.append(
123
+ 'json',
124
+ JSON.stringify({
125
+ person: patientUuid,
126
+ concept: conceptUuid,
127
+ groupMembers: [],
128
+ obsDatetime: date,
129
+ }),
130
+ );
131
+
132
+ return openmrsFetch(url, {
133
+ method: 'POST',
134
+ signal: abortController.signal,
135
+ body: formData,
136
+ });
137
+ }
138
+
139
+ interface ObsFetchResponse {
140
+ results: Array<PhotoObs>;
141
+ }
142
+
143
+ interface PhotoObs {
144
+ display: string;
145
+ obsDatetime: string;
146
+ uuid: string;
147
+ value: {
148
+ display: string;
149
+ links: {
150
+ rel: string;
151
+ uri: string;
152
+ };
153
+ };
154
+ }
155
+
156
+ interface UsePatientPhotoResult {
157
+ data: { dateTime: string; imageSrc: string } | null;
158
+ isError: Error;
159
+ isLoading: boolean;
160
+ }
161
+
162
+ export function usePatientPhoto(patientUuid: string): UsePatientPhotoResult {
163
+ const {
164
+ concepts: { patientPhotoUuid },
165
+ } = useConfig();
166
+ const url = `/ws/rest/v1/obs?patient=${patientUuid}&concept=${patientPhotoUuid}&v=full`;
167
+
168
+ const { data, error, isLoading } = useSWR<{ data: ObsFetchResponse }, Error>(patientUuid ? url : null, openmrsFetch);
169
+
170
+ const item = data?.data?.results[0];
171
+
172
+ return {
173
+ data: item
174
+ ? {
175
+ dateTime: item?.obsDatetime,
176
+ imageSrc: item?.value?.links?.uri,
177
+ }
178
+ : null,
179
+ isError: error,
180
+ isLoading,
181
+ };
182
+ }
183
+
184
+ export async function fetchPerson(query: string) {
185
+ const abortController = new AbortController();
186
+
187
+ return openmrsFetch(`/ws/rest/v1/person?q=${query}`, {
188
+ signal: abortController.signal,
189
+ });
190
+ }
191
+
192
+ export async function addPatientIdentifier(patientUuid: string, patientIdentifier: PatientIdentifier) {
193
+ const abortController = new AbortController();
194
+ return openmrsFetch(`/ws/rest/v1/patient/${patientUuid}/identifier/`, {
195
+ method: 'POST',
196
+ headers: {
197
+ 'Content-Type': 'application/json',
198
+ },
199
+ signal: abortController.signal,
200
+ body: patientIdentifier,
201
+ });
202
+ }
203
+
204
+ export async function updatePatientIdentifier(patientUuid: string, identifierUuid: string, identifier: string) {
205
+ const abortController = new AbortController();
206
+ return openmrsFetch(`/ws/rest/v1/patient/${patientUuid}/identifier/${identifierUuid}`, {
207
+ method: 'POST',
208
+ headers: {
209
+ 'Content-Type': 'application/json',
210
+ },
211
+ signal: abortController.signal,
212
+ body: { identifier },
213
+ });
214
+ }
215
+
216
+ export async function deletePatientIdentifier(patientUuid: string, patientIdentifierUuid: string) {
217
+ const abortController = new AbortController();
218
+ return openmrsFetch(`/ws/rest/v1/patient/${patientUuid}/identifier/${patientIdentifierUuid}?purge`, {
219
+ method: 'DELETE',
220
+ headers: {
221
+ 'Content-Type': 'application/json',
222
+ },
223
+ signal: abortController.signal,
224
+ });
225
+ }
226
+
227
+ export function useAddressHierarchy(
228
+ searchString,
229
+ separator,
230
+ ): {
231
+ addresses: Array<string>;
232
+ isLoading: boolean;
233
+ error: Error;
234
+ } {
235
+ const { data, error, isLoading } = useSWRImmutable<
236
+ FetchResponse<
237
+ Array<{
238
+ address: string;
239
+ }>
240
+ >,
241
+ Error
242
+ >(
243
+ searchString
244
+ ? `/module/addresshierarchy/ajax/getPossibleFullAddresses.form?separator=${separator}&searchString=${searchString}`
245
+ : null,
246
+ openmrsFetch,
247
+ );
248
+
249
+ const results = useMemo(
250
+ () => ({
251
+ addresses: data?.data?.map((address) => address.address) ?? [],
252
+ error,
253
+ isLoading,
254
+ }),
255
+ [data?.data, error, isLoading],
256
+ );
257
+ return results;
258
+ }
259
+
260
+ export function useAdressHierarchyWithParentSearch(
261
+ addressField,
262
+ parentid,
263
+ query,
264
+ ): {
265
+ error: Error;
266
+ isLoading: boolean;
267
+ addresses: Array<{
268
+ uuid: string;
269
+ name: string;
270
+ }>;
271
+ } {
272
+ const { data, error, isLoading } = useSWRImmutable<
273
+ FetchResponse<
274
+ Array<{
275
+ uuid: string;
276
+ name: string;
277
+ }>
278
+ >
279
+ >(
280
+ query
281
+ ? `/module/addresshierarchy/ajax/getPossibleAddressHierarchyEntriesWithParents.form?addressField=${addressField}&limit=20&searchString=${query}&parentUuid=${parentid}`
282
+ : null,
283
+ openmrsFetch,
284
+ );
285
+
286
+ const results = useMemo(
287
+ () => ({
288
+ error: error,
289
+ isLoading,
290
+ addresses: data?.data ?? [],
291
+ }),
292
+ [data?.data, error, isLoading],
293
+ );
294
+
295
+ return results;
296
+ }
@@ -0,0 +1,94 @@
1
+ @use '@carbon/styles/scss/spacing';
2
+ @use '@carbon/styles/scss/type';
3
+ @import '~@openmrs/esm-styleguide/src/vars';
4
+
5
+ .title {
6
+ color: var(--omrs-color-brand-teal);
7
+ }
8
+
9
+ .submit {
10
+ width: 250px;
11
+ }
12
+
13
+ .submit:hover {
14
+ cursor: pointer;
15
+ }
16
+
17
+ .cancelButton {
18
+ width: 11.688rem;
19
+ }
20
+
21
+ .submitButton {
22
+ margin-bottom: spacing.$spacing-05;
23
+ width: 11.688rem;
24
+ display: block;
25
+ }
26
+
27
+ .infoGrid {
28
+ width: 100%;
29
+ padding-left: spacing.$spacing-07;
30
+ margin-bottom: 40vh;
31
+ margin-top: spacing.$spacing-05;
32
+ max-width: 50rem;
33
+ }
34
+
35
+ .label01 {
36
+ @include type.type-style('label-01');
37
+ margin-top: spacing.$spacing-05;
38
+ margin-bottom: spacing.$spacing-05;
39
+ color: $ui-04;
40
+ }
41
+
42
+ .productiveHeading02 {
43
+ @include type.type-style('heading-compact-02');
44
+ color: $ui-04;
45
+ cursor: pointer;
46
+ }
47
+
48
+ .space05 {
49
+ margin: spacing.$spacing-05 0 spacing.$spacing-05 0;
50
+ }
51
+
52
+ .formContainer {
53
+ display: flex;
54
+ width: 100%;
55
+ }
56
+
57
+ .stickyColumn {
58
+ position: sticky;
59
+ margin-top: spacing.$spacing-05;
60
+ // 3rem for the nav height and 1rem for top margin
61
+ top: 4rem;
62
+ }
63
+
64
+ .touchTarget a:active {
65
+ color: $color-gray-100;
66
+ }
67
+
68
+ .linkName {
69
+ color: $color-gray-70;
70
+ line-height: 1.38;
71
+ font-size: spacing.$spacing-05;
72
+ font-weight: 600;
73
+
74
+ &:active {
75
+ text-decoration: none;
76
+ color: $color-gray-100;
77
+ }
78
+
79
+ &:hover {
80
+ text-decoration: none;
81
+ color: $color-gray-100;
82
+ cursor: pointer;
83
+ }
84
+ }
85
+
86
+ .main {
87
+ background-color: white;
88
+ }
89
+
90
+ :global(.omrs-breakpoint-lt-desktop) {
91
+ .infoGrid {
92
+ max-width: unset;
93
+ }
94
+ }