@openmrs/esm-patient-chart-app 11.3.0 → 11.3.1-patch.9310

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 (231) hide show
  1. package/.turbo/turbo-build.log +27 -24
  2. package/dist/1119.js +1 -1
  3. package/dist/1197.js +1 -1
  4. package/dist/1815.js +2 -0
  5. package/dist/1815.js.map +1 -0
  6. package/dist/2146.js +1 -1
  7. package/dist/2690.js +1 -1
  8. package/dist/2761.js +1 -1
  9. package/dist/2761.js.map +1 -1
  10. package/dist/2859.js +1 -1
  11. package/dist/2859.js.map +1 -1
  12. package/dist/3099.js +1 -1
  13. package/dist/3584.js +1 -1
  14. package/dist/3697.js +1 -0
  15. package/dist/3697.js.map +1 -0
  16. package/dist/4055.js +1 -1
  17. package/dist/4132.js +1 -1
  18. package/dist/4300.js +1 -1
  19. package/dist/4335.js +1 -1
  20. package/dist/4618.js +1 -1
  21. package/dist/4632.js +1 -1
  22. package/dist/4632.js.map +1 -1
  23. package/dist/4652.js +1 -1
  24. package/dist/4718.js +1 -1
  25. package/dist/4754.js +1 -1
  26. package/dist/4944.js +1 -1
  27. package/dist/5173.js +1 -1
  28. package/dist/5205.js +1 -1
  29. package/dist/5241.js +1 -1
  30. package/dist/5442.js +1 -1
  31. package/dist/5661.js +1 -1
  32. package/dist/5670.js +1 -0
  33. package/dist/5670.js.map +1 -0
  34. package/dist/5827.js +1 -0
  35. package/dist/5827.js.map +1 -0
  36. package/dist/6022.js +1 -1
  37. package/dist/6336.js +1 -0
  38. package/dist/6336.js.map +1 -0
  39. package/dist/6411.js +1 -1
  40. package/dist/6411.js.map +1 -1
  41. package/dist/6468.js +1 -1
  42. package/dist/6529.js +1 -1
  43. package/dist/6568.js +1 -0
  44. package/dist/6568.js.map +1 -0
  45. package/dist/6679.js +1 -1
  46. package/dist/68.js +2 -0
  47. package/dist/68.js.map +1 -0
  48. package/dist/6840.js +1 -1
  49. package/dist/6859.js +1 -1
  50. package/dist/6924.js +1 -0
  51. package/dist/6924.js.map +1 -0
  52. package/dist/7097.js +1 -1
  53. package/dist/7159.js +1 -1
  54. package/dist/723.js +1 -1
  55. package/dist/7617.js +1 -1
  56. package/dist/7816.js +2 -0
  57. package/dist/7816.js.map +1 -0
  58. package/dist/7818.js +1 -0
  59. package/dist/7818.js.map +1 -0
  60. package/dist/7822.js +1 -0
  61. package/dist/7822.js.map +1 -0
  62. package/dist/795.js +1 -1
  63. package/dist/8163.js +1 -1
  64. package/dist/8260.js +1 -0
  65. package/dist/8260.js.map +1 -0
  66. package/dist/8278.js +1 -0
  67. package/dist/8278.js.map +1 -0
  68. package/dist/8349.js +1 -1
  69. package/dist/8454.js +1 -1
  70. package/dist/8454.js.map +1 -1
  71. package/dist/8618.js +1 -1
  72. package/dist/8709.js +1 -1
  73. package/dist/8709.js.map +1 -1
  74. package/dist/890.js +1 -1
  75. package/dist/9007.js +1 -1
  76. package/dist/9007.js.map +1 -1
  77. package/dist/9214.js +1 -1
  78. package/dist/{4727.js → 9294.js} +1 -1
  79. package/dist/9294.js.map +1 -0
  80. package/dist/9329.js +1 -0
  81. package/dist/9329.js.map +1 -0
  82. package/dist/9538.js +1 -1
  83. package/dist/9569.js +1 -1
  84. package/dist/986.js +1 -1
  85. package/dist/9879.js +1 -1
  86. package/dist/9895.js +1 -1
  87. package/dist/9900.js +1 -1
  88. package/dist/9913.js +1 -1
  89. package/dist/main.js +1 -1
  90. package/dist/main.js.map +1 -1
  91. package/dist/openmrs-esm-patient-chart-app.js +1 -1
  92. package/dist/openmrs-esm-patient-chart-app.js.buildmanifest.json +457 -453
  93. package/dist/openmrs-esm-patient-chart-app.js.map +1 -1
  94. package/dist/routes.json +1 -1
  95. package/package.json +5 -4
  96. package/src/actions-buttons/delete-visit.component.tsx +8 -3
  97. package/src/actions-buttons/mark-patient-deceased.component.tsx +2 -2
  98. package/src/actions-buttons/start-visit.component.tsx +10 -5
  99. package/src/actions-buttons/start-visit.test.tsx +9 -5
  100. package/src/actions-buttons/stop-visit.component.tsx +1 -1
  101. package/src/clinical-views/encounter-list/{encounter-list-tabs.component.tsx → encounter-list-tabs.extension.tsx} +10 -6
  102. package/src/clinical-views/encounter-list/tag.component.test.tsx +306 -0
  103. package/src/clinical-views/encounter-list/tag.component.tsx +27 -28
  104. package/src/clinical-views/encounter-tile/encounter-tile.component.tsx +7 -6
  105. package/src/clinical-views/encounter-tile/tile.scss +0 -1
  106. package/src/clinical-views/hooks/useEncountersByVisit.ts +13 -0
  107. package/src/clinical-views/hooks/useLastEncounter.ts +1 -1
  108. package/src/clinical-views/types.ts +2 -1
  109. package/src/clinical-views/utils/concept-utils.ts +24 -0
  110. package/src/clinical-views/utils/helpers.ts +2 -2
  111. package/src/clinical-views/utils/index.ts +4 -1
  112. package/src/config-schema.ts +42 -9
  113. package/src/dashboard.meta.ts +4 -2
  114. package/src/index.ts +21 -22
  115. package/src/mark-patient-deceased/mark-patient-deceased-form.test.tsx +22 -11
  116. package/src/mark-patient-deceased/mark-patient-deceased-form.workspace.tsx +147 -138
  117. package/src/patient-banner-tags/{visit-attribute-tags.component.tsx → visit-attribute-tags.extension.tsx} +9 -4
  118. package/src/patient-chart/chart-review/dashboard-view.component.tsx +2 -2
  119. package/src/patient-chart/patient-chart.component.tsx +19 -36
  120. package/src/patient-chart/patient-chart.resources.ts +150 -0
  121. package/src/routes.json +17 -6
  122. package/src/visit/hooks/useDeleteVisit.test.tsx +39 -42
  123. package/src/visit/hooks/useDeleteVisit.tsx +33 -17
  124. package/src/visit/start-visit-button.component.tsx +2 -2
  125. package/src/visit/start-visit-button.test.tsx +2 -2
  126. package/src/visit/visit-action-items/edit-visit-details.component.tsx +29 -8
  127. package/src/visit/visit-form/base-visit-type.component.tsx +2 -2
  128. package/src/visit/visit-form/exported-visit-form.workspace.tsx +697 -0
  129. package/src/visit/visit-form/visit-attribute-type.component.tsx +2 -1
  130. package/src/visit/visit-form/visit-form.resource.ts +2 -1
  131. package/src/visit/visit-form/visit-form.test.tsx +28 -25
  132. package/src/visit/visit-form/visit-form.workspace.tsx +63 -643
  133. package/src/visit/visit-history-table/visit-actions-cell.component.tsx +3 -2
  134. package/src/visit/visit-history-table/visit-date-cell.component.tsx +1 -0
  135. package/src/visit/visit-history-table/visit-diagnoses-cell.component.tsx +1 -0
  136. package/src/visit/visit-history-table/visit-history-table.component.tsx +3 -2
  137. package/src/visit/visit-history-table/visit-type-cell.component.tsx +1 -0
  138. package/src/visit/visit-prompt/{delete-visit-dialog.component.tsx → delete-visit-dialog.modal.tsx} +10 -4
  139. package/src/visit/visit-prompt/delete-visit-dialog.test.tsx +21 -3
  140. package/src/visit/visit-prompt/{end-visit-dialog.component.tsx → end-visit-dialog.modal.tsx} +7 -1
  141. package/src/visit/visit-prompt/end-visit-dialog.test.tsx +20 -1
  142. package/src/visit/visit-prompt/{start-visit-dialog.component.tsx → start-visit-dialog.modal.tsx} +10 -4
  143. package/src/visit/visit-prompt/start-visit-dialog.test.tsx +3 -3
  144. package/src/visit/visits-widget/active-visit-buttons/active-visit-buttons.tsx +7 -6
  145. package/src/visit/visits-widget/current-visit-summary.extension.tsx +48 -0
  146. package/src/visit/visits-widget/current-visit-summary.test.tsx +45 -25
  147. package/src/visit/visits-widget/past-visits-components/encounters-table/encounters-table.component.tsx +15 -37
  148. package/src/visit/visits-widget/past-visits-components/encounters-table/encounters-table.resource.ts +0 -1
  149. package/src/visit/visits-widget/past-visits-components/medications-summary.component.tsx +2 -3
  150. package/src/visit/visits-widget/past-visits-components/visit-summary.component.tsx +8 -1
  151. package/src/visit/visits-widget/past-visits-components/visit-summary.scss +1 -1
  152. package/src/visit/visits-widget/single-visit-details/visit-timeline/visit-timeline.component.tsx +94 -0
  153. package/src/visit/visits-widget/single-visit-details/visit-timeline/visit-timeline.scss +60 -0
  154. package/src/visit/visits-widget/visit-context/retrospective-data-date-time-picker/retrospective-date-time-picker.component.tsx +6 -7
  155. package/src/visit/visits-widget/visit-context/{visit-context-header.component.tsx → visit-context-header.extension.tsx} +17 -15
  156. package/src/visit/visits-widget/visit-context/visit-context-header.test.tsx +35 -29
  157. package/src/visit/visits-widget/visit-context/visit-context-switcher.modal.tsx +15 -13
  158. package/src/visit/visits-widget/visit-context/visit-context-switcher.test.tsx +31 -9
  159. package/src/visit/visits-widget/visit-detail-overview.component.tsx +3 -2
  160. package/src/visit/visits-widget/visit-detail-overview.test.tsx +4 -4
  161. package/src/visit/visits-widget/visit.resource.tsx +1 -1
  162. package/translations/am.json +6 -0
  163. package/translations/ar.json +6 -0
  164. package/translations/ar_SY.json +6 -0
  165. package/translations/bn.json +6 -0
  166. package/translations/de.json +6 -0
  167. package/translations/en.json +7 -2
  168. package/translations/en_US.json +6 -0
  169. package/translations/es.json +6 -0
  170. package/translations/es_MX.json +6 -0
  171. package/translations/fr.json +15 -9
  172. package/translations/he.json +6 -0
  173. package/translations/hi.json +6 -0
  174. package/translations/hi_IN.json +6 -0
  175. package/translations/id.json +6 -0
  176. package/translations/it.json +24 -18
  177. package/translations/ka.json +6 -0
  178. package/translations/km.json +6 -0
  179. package/translations/ku.json +6 -0
  180. package/translations/ky.json +6 -0
  181. package/translations/lg.json +6 -0
  182. package/translations/ne.json +6 -0
  183. package/translations/pl.json +6 -0
  184. package/translations/pt.json +6 -0
  185. package/translations/pt_BR.json +6 -0
  186. package/translations/qu.json +6 -0
  187. package/translations/ro_RO.json +6 -0
  188. package/translations/ru_RU.json +6 -0
  189. package/translations/si.json +6 -0
  190. package/translations/sw.json +6 -0
  191. package/translations/sw_KE.json +6 -0
  192. package/translations/tr.json +6 -0
  193. package/translations/tr_TR.json +6 -0
  194. package/translations/uk.json +6 -0
  195. package/translations/uz.json +6 -0
  196. package/translations/uz@Latn.json +6 -0
  197. package/translations/uz_UZ.json +6 -0
  198. package/translations/vi.json +6 -0
  199. package/translations/zh.json +6 -0
  200. package/translations/zh_CN.json +6 -0
  201. package/dist/2537.js +0 -1
  202. package/dist/2537.js.map +0 -1
  203. package/dist/2735.js +0 -2
  204. package/dist/2735.js.map +0 -1
  205. package/dist/276.js +0 -1
  206. package/dist/276.js.map +0 -1
  207. package/dist/3042.js +0 -1
  208. package/dist/3042.js.map +0 -1
  209. package/dist/3119.js +0 -1
  210. package/dist/3119.js.map +0 -1
  211. package/dist/3184.js +0 -1
  212. package/dist/3184.js.map +0 -1
  213. package/dist/385.js +0 -2
  214. package/dist/385.js.map +0 -1
  215. package/dist/3905.js +0 -1
  216. package/dist/3905.js.map +0 -1
  217. package/dist/4713.js +0 -1
  218. package/dist/4713.js.map +0 -1
  219. package/dist/4727.js.map +0 -1
  220. package/dist/717.js +0 -1
  221. package/dist/717.js.map +0 -1
  222. package/dist/9162.js +0 -2
  223. package/dist/9162.js.map +0 -1
  224. package/dist/9206.js +0 -1
  225. package/dist/9206.js.map +0 -1
  226. package/dist/9615.js +0 -1
  227. package/dist/9615.js.map +0 -1
  228. package/src/visit/visits-widget/current-visit-summary.component.tsx +0 -55
  229. /package/dist/{9162.js.LICENSE.txt → 1815.js.LICENSE.txt} +0 -0
  230. /package/dist/{385.js.LICENSE.txt → 68.js.LICENSE.txt} +0 -0
  231. /package/dist/{2735.js.LICENSE.txt → 7816.js.LICENSE.txt} +0 -0
@@ -9,36 +9,35 @@ export const renderTag = (
9
9
  statusColorMappings: Record<string, string>,
10
10
  config: ConfigConcepts,
11
11
  ) => {
12
- const columnStatus = getObsFromEncounter({ encounter: encounter, obsConcept: concept, config: config });
12
+ const columnStatus = getObsFromEncounter({ encounter, obsConcept: concept, config });
13
13
  const columnStatusObs = findObs(encounter, concept);
14
14
 
15
- if (columnStatus == '--') {
15
+ if (columnStatus === '--') {
16
16
  return '--';
17
- } else {
18
- return (
19
- <Tag
20
- type={
21
- typeof columnStatusObs?.value === 'object' && 'uuid' in columnStatusObs.value
22
- ? (statusColorMappings[columnStatusObs.value.uuid] as
23
- | 'red'
24
- | 'magenta'
25
- | 'purple'
26
- | 'blue'
27
- | 'cyan'
28
- | 'teal'
29
- | 'green'
30
- | 'gray'
31
- | 'cool-gray'
32
- | 'warm-gray'
33
- | 'high-contrast'
34
- | 'outline')
35
- : undefined
36
- }
37
- title={typeof columnStatus === 'string' ? columnStatus : ''}
38
- style={{ minWidth: '80px' }}
39
- >
40
- {typeof columnStatus === 'string' ? columnStatus : ''}
41
- </Tag>
42
- );
43
17
  }
18
+
19
+ return (
20
+ <Tag
21
+ type={
22
+ typeof columnStatusObs?.value === 'object' && 'uuid' in columnStatusObs.value
23
+ ? (statusColorMappings[columnStatusObs.value.uuid] as
24
+ | 'red'
25
+ | 'magenta'
26
+ | 'purple'
27
+ | 'blue'
28
+ | 'cyan'
29
+ | 'teal'
30
+ | 'green'
31
+ | 'gray'
32
+ | 'cool-gray'
33
+ | 'warm-gray'
34
+ | 'high-contrast'
35
+ | 'outline')
36
+ : undefined
37
+ }
38
+ style={{ minWidth: '80px' }}
39
+ >
40
+ {typeof columnStatus === 'string' ? columnStatus : ''}
41
+ </Tag>
42
+ );
44
43
  };
@@ -5,6 +5,7 @@ import { isNil } from 'lodash-es';
5
5
  import { useLayoutType } from '@openmrs/esm-framework';
6
6
  import { useLastEncounter } from '../hooks';
7
7
  import type { EncounterTileColumn, EncounterTileProps } from '../types';
8
+ import { withUnit, getConceptUnitsFromEncounter } from '../utils/concept-utils';
8
9
  import styles from './tile.scss';
9
10
 
10
11
  export const EncounterTile = memo(({ patientUuid, columns, headerTitle }: EncounterTileProps) => {
@@ -41,6 +42,10 @@ const EncounterData: React.FC<{
41
42
  }> = ({ patientUuid, column }) => {
42
43
  const { t } = useTranslation();
43
44
  const { lastEncounter, isLoading, error, isValidating } = useLastEncounter(patientUuid, column.encounterTypeUuid);
45
+ const units = getConceptUnitsFromEncounter(lastEncounter, column.concept);
46
+ const summaryUnits = column.summaryConcept?.primaryConcept
47
+ ? getConceptUnitsFromEncounter(lastEncounter, column.summaryConcept.primaryConcept)
48
+ : null;
44
49
  const obsValue = column.getObsValue(lastEncounter);
45
50
  const summaryValue =
46
51
  column.hasSummary === true && column.getSummaryObsValue && typeof column.getSummaryObsValue === 'function'
@@ -64,15 +69,11 @@ const EncounterData: React.FC<{
64
69
  <>
65
70
  <span className={styles.tileTitle}>{t(column.header)}</span>
66
71
  {!(obsValue === '--' && summaryValue !== '--' && !isNil(summaryValue)) && (
67
- <span className={styles.tileValue}>
68
- <p>{obsValue}</p>
69
- </span>
72
+ <div className={styles.tileValue}>{withUnit(obsValue, units)}</div>
70
73
  )}
71
74
 
72
75
  {!isNil(summaryValue) && summaryValue !== '--' && (
73
- <span className={styles.tileValue}>
74
- <p>{summaryValue}</p>
75
- </span>
76
+ <div className={styles.tileValue}>{withUnit(summaryValue, summaryUnits)}</div>
76
77
  )}
77
78
  </>
78
79
  );
@@ -22,7 +22,6 @@
22
22
  }
23
23
 
24
24
  .tileValue {
25
- @include type.type-style('label-01');
26
25
  margin: layout.$spacing-04 0 layout.$spacing-04;
27
26
  display: block;
28
27
  }
@@ -0,0 +1,13 @@
1
+ import { type Encounter, restBaseUrl, useOpenmrsFetchAll } from '@openmrs/esm-framework';
2
+
3
+ export function useEncountersByVisit(patientUuid: string, visitUuid: string) {
4
+ const customRepresentation =
5
+ 'custom:(uuid,encounterType:(uuid,display),encounterProviders:(provider:(person:(display))),encounterDatetime,visit:(uuid))';
6
+ const url = `${restBaseUrl}/encounter?patient=${patientUuid}&order=desc&visit=${visitUuid}&v=${customRepresentation}`;
7
+ const { data: encounters, ...rest } = useOpenmrsFetchAll<Encounter>(url);
8
+
9
+ return {
10
+ encounters,
11
+ ...rest,
12
+ };
13
+ }
@@ -5,7 +5,7 @@ import useSWR from 'swr';
5
5
  const encounterRepresentation =
6
6
  'custom:(uuid,encounterDatetime,encounterType,location:(uuid,name),' +
7
7
  'patient:(uuid,display,age,identifiers,person),encounterProviders:(uuid,provider:(uuid,name)),' +
8
- 'obs:(uuid,obsDatetime,voided,groupMembers,concept:(uuid,display,name:(uuid,name)),value:(uuid,name:(uuid,name,display),' +
8
+ 'obs:(uuid,obsDatetime,voided,groupMembers,concept:(uuid,display,units,name:(uuid,name)),value:(uuid,name:(uuid,name,display),' +
9
9
  'names:(uuid,conceptNameType,name,display))),form:(uuid,name))';
10
10
 
11
11
  export function useLastEncounter(patientUuid: string, encounterType: string) {
@@ -38,7 +38,7 @@ export interface Encounter extends OpenmrsResource {
38
38
 
39
39
  export interface Observation {
40
40
  uuid: string;
41
- concept: { uuid: string; name: string };
41
+ concept: { uuid: string; name: string; units?: string };
42
42
  value:
43
43
  | {
44
44
  uuid: string;
@@ -245,6 +245,7 @@ export interface EncounterTileColumn {
245
245
  getSummaryObsValue?: (encounter: Encounter) => string;
246
246
  encounter?: Encounter;
247
247
  hasSummary?: boolean;
248
+ summaryConcept?: SummaryConcept;
248
249
  }
249
250
  export interface EncounterTileProps {
250
251
  patientUuid: string;
@@ -0,0 +1,24 @@
1
+ import type { Encounter } from '../types';
2
+
3
+ /**
4
+ * Helper function to extract units from an encounter for a specific concept
5
+ * @param encounter The encounter containing observations
6
+ * @param conceptUuid The concept UUID to find
7
+ * @returns The units string if found
8
+ */
9
+ export function getConceptUnitsFromEncounter(encounter: Encounter | null, conceptUuid: string): string {
10
+ if (!encounter || !encounter.obs || !conceptUuid) {
11
+ return '';
12
+ }
13
+
14
+ // Find the observation for this concept
15
+ const obs = encounter.obs.find((o) => o.concept?.uuid === conceptUuid);
16
+
17
+ // Return the units if found
18
+ return obs?.concept?.units || '';
19
+ }
20
+
21
+ export const withUnit = (value: string | number, unit: string | null | undefined) => {
22
+ if (!value || value === '--') return value;
23
+ return unit ? `${value} ${unit}` : value;
24
+ };
@@ -1,4 +1,4 @@
1
- import { age, formatDate, launchWorkspace, parseDate, type Visit } from '@openmrs/esm-framework';
1
+ import { age, formatDate, launchWorkspace2, parseDate, type Visit } from '@openmrs/esm-framework';
2
2
  import { launchStartVisitPrompt } from '@openmrs/esm-patient-common-lib';
3
3
  import type {
4
4
  ConfigConcepts,
@@ -25,7 +25,7 @@ export function launchEncounterForm(
25
25
  if (!visit && requireActiveVisitForEncounterTile) {
26
26
  launchStartVisitPrompt();
27
27
  } else
28
- launchWorkspace('patient-form-entry-workspace', {
28
+ launchWorkspace2('patient-form-entry-workspace', {
29
29
  workspaceTitle: form?.display ?? form?.name,
30
30
  mutateForm: onFormSave,
31
31
  formInfo: {
@@ -13,6 +13,7 @@ export const getEncounterTileColumns = (tileDefinition: MenuCardProps, config: C
13
13
  concept: column.concept,
14
14
  encounterTypeUuid: column.encounterType,
15
15
  hasSummary: column.hasSummary || false,
16
+ summaryConcept: column.summaryConcept,
16
17
  getObsValue: (encounter: Encounter) => {
17
18
  let obsValue;
18
19
  if (column.conceptMappings) {
@@ -35,7 +36,9 @@ export const getEncounterTileColumns = (tileDefinition: MenuCardProps, config: C
35
36
  config: config,
36
37
  });
37
38
  }
38
- return typeof obsValue === 'string' || (typeof obsValue === 'number' && !isNaN(obsValue)) ? obsValue : obsValue?.name?.name ?? '--';
39
+ return typeof obsValue === 'string' || (typeof obsValue === 'number' && !isNaN(obsValue))
40
+ ? obsValue
41
+ : obsValue?.name?.name ?? '--';
39
42
  },
40
43
  getSummaryObsValue: column.hasSummary
41
44
  ? (encounter: Encounter) => {
@@ -19,7 +19,8 @@ export const esmPatientChartSchema = {
19
19
  encounterEditableDuration: {
20
20
  _type: Type.Number,
21
21
  _default: 0,
22
- _description: 'The number of minutes an encounter is editable after it is created. 0 means the encounter is editable forever.',
22
+ _description:
23
+ 'The number of minutes an encounter is editable after it is created. 0 means the encounter is editable forever.',
23
24
  },
24
25
  encounterEditableDurationOverridePrivileges: {
25
26
  _type: Type.Array,
@@ -27,7 +28,8 @@ export const esmPatientChartSchema = {
27
28
  _type: Type.String,
28
29
  },
29
30
  _default: [],
30
- _description: 'The privileges that allow users to edit encounters even after the editable duration (set by `encounterEditableDuration`) has expired. Any privilege in the list is sufficient to edit the encounter.',
31
+ _description:
32
+ 'The privileges that allow users to edit encounters even after the editable duration (set by `encounterEditableDuration`) has expired. Any privilege in the list is sufficient to edit the encounter.',
31
33
  },
32
34
  freeTextFieldConceptUuid: {
33
35
  _type: Type.ConceptUuid,
@@ -82,12 +84,6 @@ export const esmPatientChartSchema = {
82
84
  _description: 'Shows the All Encounters Tab of Patient Visits section in Patient Chart',
83
85
  _default: true,
84
86
  },
85
- showExtraVisitAttributesSlot: {
86
- _type: Type.Boolean,
87
- _description:
88
- 'Whether on start visit form should handle submission of the extra visit attributes from the extra visit attributes slot',
89
- _default: false,
90
- },
91
87
  showRecommendedVisitTypeTab: {
92
88
  _type: Type.Boolean,
93
89
  _description: 'Whether start visit form should display recommended visit type tab. Requires `visitTypeResourceUrl`',
@@ -160,11 +156,39 @@ export const esmPatientChartSchema = {
160
156
  _description: 'Default concept uuid for other in forms',
161
157
  _default: '5622AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
162
158
  },
159
+ tileDefinitions: {
160
+ _type: Type.Array,
161
+ _default: [
162
+ {
163
+ title: 'Weight and Height',
164
+ columns: [
165
+ {
166
+ title: 'Weight',
167
+ concept: '5089AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
168
+ encounterType: '67a71486-1a54-468f-ac3e-7091a9a79584',
169
+ hasSummary: true,
170
+ },
171
+ {
172
+ title: 'Height',
173
+ concept: '5090AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
174
+ encounterType: '67a71486-1a54-468f-ac3e-7091a9a79584',
175
+ hasSummary: true,
176
+ },
177
+ ],
178
+ },
179
+ ],
180
+ _description: 'Definitions for clinical summary tiles with their concepts and encounter types',
181
+ },
163
182
  requireActiveVisitForEncounterTile: {
164
183
  _type: Type.Boolean,
165
184
  _description: 'Whether to require an active visit for the encounter tile',
166
185
  _default: true,
167
186
  },
187
+ drugOrderTypeUUID: {
188
+ _type: Type.UUID,
189
+ _description: "UUID for the 'Drug' order type to fetch medications",
190
+ _default: '131168f4-15f5-102d-96e4-000c29c2a5d7',
191
+ },
168
192
  };
169
193
 
170
194
  export interface ChartConfig {
@@ -183,7 +207,6 @@ export interface ChartConfig {
183
207
  offlineVisitTypeUuid: string;
184
208
  restrictByVisitLocationTag: boolean;
185
209
  showAllEncountersTab: boolean;
186
- showExtraVisitAttributesSlot: boolean;
187
210
  showRecommendedVisitTypeTab: boolean;
188
211
  showServiceQueueFields: boolean; // used by extension from esm-service-queues-app
189
212
  showUpcomingAppointments: boolean; // used by extension from esm-appointments-app
@@ -198,5 +221,15 @@ export interface ChartConfig {
198
221
  requireActiveVisitForEncounterTile: boolean;
199
222
  trueConceptUuid: string;
200
223
  falseConceptUuid: string;
224
+ tileDefinitions: Array<{
225
+ title: string;
226
+ columns: Array<{
227
+ title: string;
228
+ concept: string;
229
+ encounterType: string;
230
+ hasSummary?: boolean;
231
+ }>;
232
+ }>;
201
233
  otherConceptUuid: string;
234
+ drugOrderTypeUUID: string;
202
235
  }
@@ -1,11 +1,13 @@
1
- export const summaryDashboardMeta = {
1
+ import { type DashboardLinkConfig } from '@openmrs/esm-patient-common-lib';
2
+
3
+ export const summaryDashboardMeta: DashboardLinkConfig & { slot: string } = {
2
4
  slot: 'patient-chart-summary-dashboard-slot',
3
5
  path: 'Patient Summary',
4
6
  title: 'Patient Summary',
5
7
  icon: 'omrs-icon-report',
6
8
  };
7
9
 
8
- export const encountersDashboardMeta = {
10
+ export const encountersDashboardMeta: DashboardLinkConfig & { slot: string } = {
9
11
  slot: 'patient-chart-encounters-dashboard-slot',
10
12
  path: 'Visits',
11
13
  title: 'Visits',
package/src/index.ts CHANGED
@@ -1,9 +1,4 @@
1
- import {
2
- defineConfigSchema,
3
- defineExtensionConfigSchema,
4
- getAsyncLifecycle,
5
- getSyncLifecycle,
6
- } from '@openmrs/esm-framework';
1
+ import { defineConfigSchema, getAsyncLifecycle, getSyncLifecycle } from '@openmrs/esm-framework';
7
2
  import * as Framework from '@openmrs/esm-framework';
8
3
  import { createDashboardLink } from '@openmrs/esm-patient-common-lib';
9
4
  import { esmPatientChartSchema } from './config-schema';
@@ -11,7 +6,7 @@ import { moduleName } from './constants';
11
6
  import { setupCacheableRoutes, setupOfflineVisitsSync } from './offline';
12
7
  import { summaryDashboardMeta, encountersDashboardMeta } from './dashboard.meta';
13
8
  import deleteVisitActionButtonComponent from './actions-buttons/delete-visit.component';
14
- import currentVisitSummaryComponent from './visit/visits-widget/current-visit-summary.component';
9
+ import currentVisitSummaryComponent from './visit/visits-widget/current-visit-summary.extension';
15
10
  import markPatientAliveActionButtonComponent from './actions-buttons/mark-patient-alive.component';
16
11
  import markPatientDeceasedActionButtonComponent from './actions-buttons/mark-patient-deceased.component';
17
12
  import pastVisitsOverviewComponent from './visit/visits-widget/visit-detail-overview.component';
@@ -20,7 +15,7 @@ import patientDetailsTileComponent from './patient-details-tile/patient-details-
20
15
  import startVisitActionButtonComponent from './actions-buttons/start-visit.component';
21
16
  import startVisitActionButtonOnPatientSearch from './visit/start-visit-button.component';
22
17
  import stopVisitActionButtonComponent from './actions-buttons/stop-visit.component';
23
- import visitAttributeTagsComponent from './patient-banner-tags/visit-attribute-tags.component';
18
+ import visitAttributeTagsComponent from './patient-banner-tags/visit-attribute-tags.extension';
24
19
 
25
20
  // This allows @openmrs/esm-framework to be accessed by modules that are not
26
21
  // using webpack. This is used for ngx-formentry.
@@ -50,37 +45,37 @@ export const patientSummaryDashboardLink =
50
45
  );
51
46
 
52
47
  export const markPatientAliveActionButton = getSyncLifecycle(markPatientAliveActionButtonComponent, {
53
- featureName: 'patient-actions-slot',
48
+ featureName: 'patient-action-mark-alive',
54
49
  moduleName,
55
50
  });
56
51
 
57
52
  export const markPatientDeceasedActionButton = getSyncLifecycle(markPatientDeceasedActionButtonComponent, {
58
- featureName: 'patient-actions-slot-deceased-button',
53
+ featureName: 'patient-action-mark-deceased',
59
54
  moduleName,
60
55
  });
61
56
 
62
57
  export const startVisitActionButton = getSyncLifecycle(startVisitActionButtonComponent, {
63
- featureName: 'patient-actions-slot',
58
+ featureName: 'patient-action-start-visit',
64
59
  moduleName,
65
60
  });
66
61
 
67
62
  export const stopVisitActionButton = getSyncLifecycle(stopVisitActionButtonComponent, {
68
- featureName: 'patient-actions-slot',
63
+ featureName: 'patient-action-stop-visit',
69
64
  moduleName,
70
65
  });
71
66
 
72
67
  export const deleteVisitActionMenuButton = getSyncLifecycle(deleteVisitActionButtonComponent, {
73
- featureName: 'patient-actions-slot',
68
+ featureName: 'patient-action-delete-visit',
74
69
  moduleName,
75
70
  });
76
71
 
77
72
  export const startVisitPatientSearchActionButton = getSyncLifecycle(startVisitActionButtonOnPatientSearch, {
78
- featureName: 'start-visit-button-patient-search',
73
+ featureName: 'patient-search-action-start-visit',
79
74
  moduleName,
80
75
  });
81
76
 
82
77
  export const stopVisitPatientSearchActionButton = getSyncLifecycle(stopVisitActionButtonComponent, {
83
- featureName: 'patient-actions-slot',
78
+ featureName: 'patient-search-action-stop-visit',
84
79
  moduleName,
85
80
  });
86
81
 
@@ -104,7 +99,7 @@ export const currentVisitSummary = getSyncLifecycle(currentVisitSummaryComponent
104
99
  });
105
100
 
106
101
  export const pastVisitsDetailOverview = getSyncLifecycle(pastVisitsOverviewComponent, {
107
- featureName: 'visits-detail-slot',
102
+ featureName: 'visits-detail-overview',
108
103
  moduleName,
109
104
  });
110
105
 
@@ -118,12 +113,16 @@ export const visitAttributeTags = getSyncLifecycle(visitAttributeTagsComponent,
118
113
  moduleName,
119
114
  });
120
115
 
121
- // t('startVisitWorkspaceTitle', 'Start a visit')
122
116
  export const startVisitWorkspace = getAsyncLifecycle(() => import('./visit/visit-form/visit-form.workspace'), {
123
117
  featureName: 'start-visit-form',
124
118
  moduleName,
125
119
  });
126
120
 
121
+ export const exportedVisitForm = getAsyncLifecycle(() => import('./visit/visit-form/exported-visit-form.workspace'), {
122
+ featureName: 'exported-visit-form',
123
+ moduleName,
124
+ });
125
+
127
126
  // t('markPatientDeceased', 'Mark patient deceased')
128
127
  export const markPatientDeceasedForm = getAsyncLifecycle(
129
128
  () => import('./mark-patient-deceased/mark-patient-deceased-form.workspace'),
@@ -133,12 +132,12 @@ export const markPatientDeceasedForm = getAsyncLifecycle(
133
132
  },
134
133
  );
135
134
 
136
- export const startVisitModal = getAsyncLifecycle(() => import('./visit/visit-prompt/start-visit-dialog.component'), {
135
+ export const startVisitModal = getAsyncLifecycle(() => import('./visit/visit-prompt/start-visit-dialog.modal'), {
137
136
  featureName: 'start visit',
138
137
  moduleName,
139
138
  });
140
139
 
141
- export const deleteVisitModal = getAsyncLifecycle(() => import('./visit/visit-prompt/delete-visit-dialog.component'), {
140
+ export const deleteVisitModal = getAsyncLifecycle(() => import('./visit/visit-prompt/delete-visit-dialog.modal'), {
142
141
  featureName: 'delete visit',
143
142
  moduleName,
144
143
  });
@@ -148,7 +147,7 @@ export const modifyVisitDateModal = getAsyncLifecycle(() => import('./visit/visi
148
147
  moduleName,
149
148
  });
150
149
 
151
- export const endVisitModal = getAsyncLifecycle(() => import('./visit/visit-prompt/end-visit-dialog.component'), {
150
+ export const endVisitModal = getAsyncLifecycle(() => import('./visit/visit-prompt/end-visit-dialog.modal'), {
152
151
  featureName: 'end visit',
153
152
  moduleName,
154
153
  });
@@ -182,7 +181,7 @@ export const activeVisitActionsComponent = getAsyncLifecycle(
182
181
  );
183
182
 
184
183
  export const encounterListTableTabs = getAsyncLifecycle(
185
- () => import('./clinical-views/encounter-list/encounter-list-tabs.component'),
184
+ () => import('./clinical-views/encounter-list/encounter-list-tabs.extension'),
186
185
  { featureName: 'encounter-list-table-tabs', moduleName },
187
186
  );
188
187
 
@@ -192,7 +191,7 @@ export const visitContextSwitcherModal = getAsyncLifecycle(
192
191
  );
193
192
 
194
193
  export const visitContextHeader = getAsyncLifecycle(
195
- () => import('./visit/visits-widget/visit-context/visit-context-header.component'),
194
+ () => import('./visit/visits-widget/visit-context/visit-context-header.extension'),
196
195
  { featureName: 'visit-context-header', moduleName },
197
196
  );
198
197
 
@@ -6,10 +6,14 @@ import { esmPatientChartSchema, type ChartConfig } from '../config-schema';
6
6
  import { mockPatient } from 'tools';
7
7
  import { markPatientDeceased, useCausesOfDeath } from '../data.resource';
8
8
  import MarkPatientDeceasedForm from './mark-patient-deceased-form.workspace';
9
+ import { type PatientWorkspace2DefinitionProps } from '@openmrs/esm-patient-common-lib/src';
9
10
 
10
- const originalLocation = window.location;
11
- delete window.location;
12
- window.location = { ...originalLocation, reload: jest.fn() };
11
+ const mockReload = jest.fn();
12
+
13
+ Object.defineProperty(window, 'location', {
14
+ value: { ...window.location, reload: mockReload },
15
+ writable: true,
16
+ });
13
17
 
14
18
  const mockMarkPatientDeceased = jest.mocked(markPatientDeceased);
15
19
  const mockUseCausesOfDeath = jest.mocked(useCausesOfDeath);
@@ -17,7 +21,7 @@ const mockUseConfig = jest.mocked(useConfig<ChartConfig>);
17
21
  const mockShowSnackbar = jest.mocked(showSnackbar);
18
22
  const mockCloseWorkspace = jest.fn();
19
23
 
20
- jest.mock('../data.resource.ts', () => ({
24
+ jest.mock('../data.resource', () => ({
21
25
  markPatientDeceased: jest.fn().mockResolvedValue({}),
22
26
  useCausesOfDeath: jest.fn(),
23
27
  }));
@@ -25,13 +29,20 @@ jest.mock('../data.resource.ts', () => ({
25
29
  describe('MarkPatientDeceasedForm', () => {
26
30
  const freeTextFieldConceptUuid = '1234e218-6c8a-4ca3-8edb-9f6d9c8c8c7f';
27
31
 
28
- const defaultProps = {
29
- patientUuid: mockPatient.id,
30
- patient: mockPatient,
32
+ const defaultProps: PatientWorkspace2DefinitionProps<{}, {}> = {
31
33
  closeWorkspace: mockCloseWorkspace,
32
- closeWorkspaceWithSavedChanges: jest.fn(),
33
- promptBeforeClosing: jest.fn(),
34
- setTitle: jest.fn(),
34
+ workspaceName: null,
35
+ launchChildWorkspace: jest.fn(),
36
+ windowProps: {},
37
+ workspaceProps: {},
38
+ groupProps: {
39
+ patientUuid: mockPatient.id,
40
+ patient: mockPatient,
41
+ visitContext: null,
42
+ mutateVisitContext: null,
43
+ },
44
+ windowName: '',
45
+ isRootWorkspace: false,
35
46
  };
36
47
 
37
48
  const codedCausesOfDeath = [
@@ -71,7 +82,7 @@ describe('MarkPatientDeceasedForm', () => {
71
82
  });
72
83
 
73
84
  afterAll(() => {
74
- window.location = originalLocation;
85
+ jest.restoreAllMocks();
75
86
  });
76
87
 
77
88
  it('renders the cause of death form', () => {