@openmrs/esm-patient-chart-app 11.3.1-pre.9452 → 11.3.1-pre.9458

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 (86) hide show
  1. package/.turbo/turbo-build.log +11 -11
  2. package/dist/2540.js +1 -1
  3. package/dist/2540.js.map +1 -1
  4. package/dist/2761.js.map +1 -1
  5. package/dist/3697.js +1 -0
  6. package/dist/3697.js.map +1 -0
  7. package/dist/4300.js +1 -1
  8. package/dist/506.js +1 -1
  9. package/dist/506.js.map +1 -1
  10. package/dist/5827.js +1 -0
  11. package/dist/5827.js.map +1 -0
  12. package/dist/6411.js +1 -1
  13. package/dist/6411.js.map +1 -1
  14. package/dist/6568.js +1 -1
  15. package/dist/6568.js.map +1 -1
  16. package/dist/6924.js +1 -1
  17. package/dist/6924.js.map +1 -1
  18. package/dist/7818.js +1 -0
  19. package/dist/7818.js.map +1 -0
  20. package/dist/7822.js +1 -1
  21. package/dist/7822.js.map +1 -1
  22. package/dist/8260.js +1 -1
  23. package/dist/8260.js.map +1 -1
  24. package/dist/{3119.js → 8278.js} +1 -1
  25. package/dist/{3119.js.map → 8278.js.map} +1 -1
  26. package/dist/8454.js +1 -1
  27. package/dist/8454.js.map +1 -1
  28. package/dist/8709.js +1 -1
  29. package/dist/8709.js.map +1 -1
  30. package/dist/{6997.js → 9294.js} +1 -1
  31. package/dist/9294.js.map +1 -0
  32. package/dist/main.js +1 -1
  33. package/dist/main.js.map +1 -1
  34. package/dist/openmrs-esm-patient-chart-app.js +1 -1
  35. package/dist/openmrs-esm-patient-chart-app.js.buildmanifest.json +134 -158
  36. package/dist/openmrs-esm-patient-chart-app.js.map +1 -1
  37. package/dist/routes.json +1 -1
  38. package/package.json +2 -2
  39. package/src/actions-buttons/mark-patient-deceased.component.tsx +2 -2
  40. package/src/actions-buttons/start-visit.component.tsx +10 -5
  41. package/src/actions-buttons/start-visit.test.tsx +9 -5
  42. package/src/clinical-views/encounter-list/encounter-list-tabs.extension.tsx +1 -1
  43. package/src/clinical-views/utils/helpers.ts +2 -2
  44. package/src/index.ts +12 -18
  45. package/src/mark-patient-deceased/mark-patient-deceased-form.test.tsx +15 -9
  46. package/src/mark-patient-deceased/mark-patient-deceased-form.workspace.tsx +147 -138
  47. package/src/patient-chart/chart-review/dashboard-view.component.tsx +2 -2
  48. package/src/patient-chart/patient-chart.component.tsx +45 -42
  49. package/src/patient-chart/patient-chart.resources.ts +52 -10
  50. package/src/patient-chart/patient-chart.scss +0 -4
  51. package/src/routes.json +17 -6
  52. package/src/visit/hooks/useDeleteVisit.tsx +1 -1
  53. package/src/visit/start-visit-button.component.tsx +2 -2
  54. package/src/visit/start-visit-button.test.tsx +2 -2
  55. package/src/visit/visit-action-items/edit-visit-details.component.tsx +29 -8
  56. package/src/visit/visit-form/exported-visit-form.workspace.tsx +2 -10
  57. package/src/visit/visit-form/visit-form.test.tsx +27 -18
  58. package/src/visit/visit-form/visit-form.workspace.tsx +38 -675
  59. package/src/visit/visit-history-table/visit-actions-cell.component.tsx +3 -2
  60. package/src/visit/visit-history-table/visit-date-cell.component.tsx +1 -0
  61. package/src/visit/visit-history-table/visit-diagnoses-cell.component.tsx +1 -0
  62. package/src/visit/visit-history-table/visit-history-table.component.tsx +3 -2
  63. package/src/visit/visit-history-table/visit-type-cell.component.tsx +1 -0
  64. package/src/visit/visit-prompt/delete-visit-dialog.test.tsx +1 -1
  65. package/src/visit/visit-prompt/{end-visit-dialog.component.tsx → end-visit-dialog.modal.tsx} +1 -1
  66. package/src/visit/visit-prompt/end-visit-dialog.test.tsx +1 -1
  67. package/src/visit/visit-prompt/{start-visit-dialog.component.tsx → start-visit-dialog.modal.tsx} +10 -4
  68. package/src/visit/visit-prompt/start-visit-dialog.test.tsx +3 -3
  69. package/src/visit/visits-widget/current-visit-summary.extension.tsx +3 -3
  70. package/src/visit/visits-widget/past-visits-components/encounters-table/encounters-table.component.tsx +12 -35
  71. package/src/visit/visits-widget/visit-context/retrospective-data-date-time-picker/retrospective-date-time-picker.component.tsx +1 -0
  72. package/src/visit/visits-widget/visit-context/visit-context-switcher.modal.tsx +2 -2
  73. package/src/visit/visits-widget/visit-context/visit-context-switcher.test.tsx +22 -20
  74. package/src/visit/visits-widget/visit-detail-overview.component.tsx +3 -2
  75. package/src/visit/visits-widget/visit-detail-overview.test.tsx +4 -4
  76. package/translations/en.json +1 -1
  77. package/dist/276.js +0 -1
  78. package/dist/276.js.map +0 -1
  79. package/dist/3905.js +0 -1
  80. package/dist/3905.js.map +0 -1
  81. package/dist/5048.js +0 -1
  82. package/dist/5048.js.map +0 -1
  83. package/dist/6997.js.map +0 -1
  84. package/dist/7810.js +0 -1
  85. package/dist/7810.js.map +0 -1
  86. /package/src/visit/visit-prompt/{delete-visit-dialog.component.tsx → delete-visit-dialog.modal.tsx} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-patient-chart-app",
3
- "version": "11.3.1-pre.9452",
3
+ "version": "11.3.1-pre.9458",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Patient dashboard microfrontend for the OpenMRS SPA",
6
6
  "browser": "dist/openmrs-esm-patient-chart-app.js",
@@ -55,7 +55,7 @@
55
55
  "swr": "2.x"
56
56
  },
57
57
  "devDependencies": {
58
- "@openmrs/esm-patient-common-lib": "11.3.1-pre.9452",
58
+ "@openmrs/esm-patient-common-lib": "11.3.1-pre.9458",
59
59
  "@types/uuid": "^9.0.4",
60
60
  "webpack": "^5.99.9"
61
61
  },
@@ -1,7 +1,7 @@
1
1
  import React, { useCallback } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import { OverflowMenuItem } from '@carbon/react';
4
- import { launchWorkspace } from '@openmrs/esm-framework';
4
+ import { launchWorkspace2 } from '@openmrs/esm-framework';
5
5
  import styles from './action-button.scss';
6
6
 
7
7
  interface MarkPatientDeceasedOverflowMenuItemProps {
@@ -13,7 +13,7 @@ const MarkPatientDeceasedOverflowMenuItem: React.FC<MarkPatientDeceasedOverflowM
13
13
  const { t } = useTranslation();
14
14
  const isDead = patient.deceasedBoolean ?? Boolean(patient.deceasedDateTime);
15
15
 
16
- const handleLaunchModal = useCallback(() => launchWorkspace('mark-patient-deceased-workspace-form'), []);
16
+ const handleLaunchModal = useCallback(() => launchWorkspace2('mark-patient-deceased-workspace-form'), []);
17
17
 
18
18
  return (
19
19
  patient &&
@@ -1,8 +1,10 @@
1
1
  import React, { useCallback } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import { OverflowMenuItem } from '@carbon/react';
4
- import { launchWorkspace } from '@openmrs/esm-framework';
4
+ import { launchWorkspace2 } from '@openmrs/esm-framework';
5
5
  import styles from './action-button.scss';
6
+ import { type VisitFormProps } from '../visit/visit-form/visit-form.workspace';
7
+ import { type PatientWorkspaceGroupProps } from '@openmrs/esm-patient-common-lib';
6
8
 
7
9
  interface StartVisitOverflowMenuItemProps {
8
10
  patient: fhir.Patient;
@@ -14,10 +16,13 @@ const StartVisitOverflowMenuItem: React.FC<StartVisitOverflowMenuItemProps> = ({
14
16
 
15
17
  const handleLaunchModal = useCallback(
16
18
  () =>
17
- launchWorkspace('start-visit-workspace-form', {
18
- openedFrom: 'patient-chart-start-visit',
19
- }),
20
- [],
19
+ launchWorkspace2<VisitFormProps, {}, PatientWorkspaceGroupProps>(
20
+ 'start-visit-workspace-form',
21
+ { openedFrom: 'patient-chart-start-visit' },
22
+ {},
23
+ { patient, patientUuid: patient.id, visitContext: null, mutateVisitContext: null },
24
+ ),
25
+ [patient],
21
26
  );
22
27
 
23
28
  return (
@@ -1,11 +1,12 @@
1
1
  import React from 'react';
2
2
  import userEvent from '@testing-library/user-event';
3
3
  import { render, screen } from '@testing-library/react';
4
- import { launchWorkspace } from '@openmrs/esm-framework';
4
+ import { launchWorkspace2 } from '@openmrs/esm-framework';
5
5
  import { mockPatient } from 'tools';
6
6
  import StartVisitOverflowMenuItem from './start-visit.component';
7
+ import { object } from 'zod';
7
8
 
8
- const mockLaunchWorkspace = jest.mocked(launchWorkspace);
9
+ const mockLaunchWorkspace = jest.mocked(launchWorkspace2);
9
10
 
10
11
  describe('StartVisitOverflowMenuItem', () => {
11
12
  it('should launch the start visit form', async () => {
@@ -18,9 +19,12 @@ describe('StartVisitOverflowMenuItem', () => {
18
19
 
19
20
  await user.click(startVisitButton);
20
21
  expect(mockLaunchWorkspace).toHaveBeenCalledTimes(1);
21
- expect(mockLaunchWorkspace).toHaveBeenCalledWith('start-visit-workspace-form', {
22
- openedFrom: 'patient-chart-start-visit',
23
- });
22
+ expect(mockLaunchWorkspace).toHaveBeenCalledWith(
23
+ 'start-visit-workspace-form',
24
+ { openedFrom: 'patient-chart-start-visit' },
25
+ {},
26
+ expect.objectContaining({ patient: mockPatient, patientUuid: mockPatient.id }),
27
+ );
24
28
  });
25
29
 
26
30
  it('should not show start visit button for a deceased patient', () => {
@@ -2,12 +2,12 @@ import React, { useMemo } from 'react';
2
2
  import { useTranslation } from 'react-i18next';
3
3
  import { Tabs, Tab, TabList, TabPanels, TabPanel } from '@carbon/react';
4
4
  import { useConfig } from '@openmrs/esm-framework';
5
- import { usePatientChartStore } from '@openmrs/esm-patient-common-lib';
6
5
  import { EncounterList } from './encounter-list.component';
7
6
  import { getMenuItemTabsConfiguration } from '../utils/encounter-list-config-builder';
8
7
  import styles from './encounter-list-tabs.scss';
9
8
  import { filter } from '../utils/helpers';
10
9
  import { type Encounter } from '../types';
10
+ import { usePatientChartStore } from '@openmrs/esm-patient-common-lib/src';
11
11
 
12
12
  interface EncounterListTabsComponentProps {
13
13
  patientUuid: string;
@@ -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,
@@ -26,7 +26,7 @@ export function launchEncounterForm(
26
26
  if (!visit && requireActiveVisitForEncounterTile) {
27
27
  launchStartVisitPrompt();
28
28
  } else
29
- launchWorkspace('patient-form-entry-workspace', {
29
+ launchWorkspace2('patient-form-entry-workspace', {
30
30
  workspaceTitle: form?.display ?? form?.name,
31
31
  mutateForm: onFormSave,
32
32
  formInfo: {
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';
@@ -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,7 +113,6 @@ 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,
@@ -138,12 +132,12 @@ export const markPatientDeceasedForm = getAsyncLifecycle(
138
132
  },
139
133
  );
140
134
 
141
- 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'), {
142
136
  featureName: 'start visit',
143
137
  moduleName,
144
138
  });
145
139
 
146
- 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'), {
147
141
  featureName: 'delete visit',
148
142
  moduleName,
149
143
  });
@@ -153,7 +147,7 @@ export const modifyVisitDateModal = getAsyncLifecycle(() => import('./visit/visi
153
147
  moduleName,
154
148
  });
155
149
 
156
- 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'), {
157
151
  featureName: 'end visit',
158
152
  moduleName,
159
153
  });
@@ -6,6 +6,7 @@ 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
11
  const mockReload = jest.fn();
11
12
 
@@ -20,7 +21,7 @@ const mockUseConfig = jest.mocked(useConfig<ChartConfig>);
20
21
  const mockShowSnackbar = jest.mocked(showSnackbar);
21
22
  const mockCloseWorkspace = jest.fn();
22
23
 
23
- jest.mock('../data.resource.ts', () => ({
24
+ jest.mock('../data.resource', () => ({
24
25
  markPatientDeceased: jest.fn().mockResolvedValue({}),
25
26
  useCausesOfDeath: jest.fn(),
26
27
  }));
@@ -28,15 +29,20 @@ jest.mock('../data.resource.ts', () => ({
28
29
  describe('MarkPatientDeceasedForm', () => {
29
30
  const freeTextFieldConceptUuid = '1234e218-6c8a-4ca3-8edb-9f6d9c8c8c7f';
30
31
 
31
- const defaultProps = {
32
- patientUuid: mockPatient.id,
33
- patient: mockPatient,
32
+ const defaultProps: PatientWorkspace2DefinitionProps<{}, {}> = {
34
33
  closeWorkspace: mockCloseWorkspace,
35
- closeWorkspaceWithSavedChanges: jest.fn(),
36
- promptBeforeClosing: jest.fn(),
37
- setTitle: jest.fn(),
38
- visitContext: null,
39
- mutateVisitContext: null,
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,
40
46
  };
41
47
 
42
48
  const codedCausesOfDeath = [
@@ -20,7 +20,7 @@ import { Controller, useForm, type SubmitHandler } from 'react-hook-form';
20
20
  import { z } from 'zod';
21
21
  import { zodResolver } from '@hookform/resolvers/zod';
22
22
  import { WarningFilled } from '@carbon/react/icons';
23
- import { EmptyState, type DefaultPatientWorkspaceProps } from '@openmrs/esm-patient-common-lib';
23
+ import { type PatientWorkspace2DefinitionProps, EmptyState } from '@openmrs/esm-patient-common-lib';
24
24
  import {
25
25
  ExtensionSlot,
26
26
  useLayoutType,
@@ -28,12 +28,16 @@ import {
28
28
  ResponsiveWrapper,
29
29
  useConfig,
30
30
  OpenmrsDatePicker,
31
+ Workspace2,
31
32
  } from '@openmrs/esm-framework';
32
33
  import { markPatientDeceased, useCausesOfDeath } from '../data.resource';
33
34
  import { type ChartConfig } from '../config-schema';
34
35
  import styles from './mark-patient-deceased-form.scss';
35
36
 
36
- const MarkPatientDeceasedForm: React.FC<DefaultPatientWorkspaceProps> = ({ closeWorkspace, patientUuid }) => {
37
+ const MarkPatientDeceasedForm: React.FC<PatientWorkspace2DefinitionProps<{}, {}>> = ({
38
+ closeWorkspace,
39
+ groupProps: { patientUuid },
40
+ }) => {
37
41
  const { t } = useTranslation();
38
42
  const isTablet = useLayoutType() === 'tablet';
39
43
  const memoizedPatientUuid = useMemo(() => ({ patientUuid }), [patientUuid]);
@@ -78,7 +82,7 @@ const MarkPatientDeceasedForm: React.FC<DefaultPatientWorkspaceProps> = ({ close
78
82
 
79
83
  const {
80
84
  control,
81
- formState: { errors, isSubmitting },
85
+ formState: { errors, isSubmitting, isDirty },
82
86
  handleSubmit,
83
87
  watch,
84
88
  } = useForm<MarkPatientDeceasedFormSchema>({
@@ -117,151 +121,156 @@ const MarkPatientDeceasedForm: React.FC<DefaultPatientWorkspaceProps> = ({ close
117
121
  const onError = (errors) => console.error(errors);
118
122
 
119
123
  return (
120
- <Form className={styles.form} onSubmit={handleSubmit(onSubmit, onError)}>
121
- <div>
122
- {isTablet && (
123
- <Row className={styles.headerGridRow}>
124
- <ExtensionSlot className={styles.dataGridRow} name="visit-form-header-slot" state={memoizedPatientUuid} />
125
- </Row>
126
- )}
127
- <div className={styles.container}>
128
- <span className={styles.warningContainer}>
129
- <WarningFilled aria-label={t('warning', 'Warning')} className={styles.warningIcon} size={20} />
130
- <span className={styles.warningText}>
131
- {t('markDeceasedWarning', 'Marking the patient as deceased will end any active visits for this patient')}
124
+ <Workspace2 title={t('markPatientDeceased', 'Mark patient deceased')} hasUnsavedChanges={isDirty}>
125
+ <Form className={styles.form} onSubmit={handleSubmit(onSubmit, onError)}>
126
+ <div>
127
+ {isTablet && (
128
+ <Row className={styles.headerGridRow}>
129
+ <ExtensionSlot className={styles.dataGridRow} name="visit-form-header-slot" state={memoizedPatientUuid} />
130
+ </Row>
131
+ )}
132
+ <div className={styles.container}>
133
+ <span className={styles.warningContainer}>
134
+ <WarningFilled aria-label={t('warning', 'Warning')} className={styles.warningIcon} size={20} />
135
+ <span className={styles.warningText}>
136
+ {t(
137
+ 'markDeceasedWarning',
138
+ 'Marking the patient as deceased will end any active visits for this patient',
139
+ )}
140
+ </span>
132
141
  </span>
133
- </span>
134
- <section>
135
- <div className={styles.sectionTitle}>{t('dateOfDeath', 'Date of death')}</div>
136
- {causesOfDeath?.length ? (
137
- <ResponsiveWrapper>
138
- <Controller
139
- name="deathDate"
140
- control={control}
141
- render={({ field, fieldState }) => (
142
- <OpenmrsDatePicker
143
- {...field}
144
- className={styles.datePicker}
145
- id="deceasedDate"
146
- data-testid="deceasedDate"
147
- labelText={t('date', 'Date')}
148
- maxDate={new Date()}
149
- invalid={Boolean(fieldState?.error?.message)}
150
- invalidText={fieldState?.error?.message}
151
- />
152
- )}
153
- />
154
- </ResponsiveWrapper>
155
- ) : (
156
- <DatePickerSkeleton />
157
- )}
158
- </section>
159
- <section>
160
- <div className={styles.sectionTitle}>{t('causeOfDeath', 'Cause of death')}</div>
161
- <div
162
- className={classNames(styles.conceptAnswerOverviewWrapper, {
163
- [styles.conceptAnswerOverviewWrapperTablet]: isTablet,
164
- [styles.conceptAnswerOverviewWrapperDesktop]: !isTablet,
165
- [styles.errorOutline]: errors?.causeOfDeath?.message,
166
- })}
167
- >
168
- {isLoadingCausesOfDeath ? <StructuredListSkeleton /> : null}
169
-
142
+ <section>
143
+ <div className={styles.sectionTitle}>{t('dateOfDeath', 'Date of death')}</div>
170
144
  {causesOfDeath?.length ? (
171
145
  <ResponsiveWrapper>
172
- <Search
173
- labelText={t('searchForCauseOfDeath', 'Search for a cause of death')}
174
- onChange={handleSearchTermChange}
175
- placeholder={t('searchForCauseOfDeath', 'Search for a cause of death')}
146
+ <Controller
147
+ name="deathDate"
148
+ control={control}
149
+ render={({ field, fieldState }) => (
150
+ <OpenmrsDatePicker
151
+ {...field}
152
+ className={styles.datePicker}
153
+ id="deceasedDate"
154
+ data-testid="deceasedDate"
155
+ labelText={t('date', 'Date')}
156
+ maxDate={new Date()}
157
+ invalid={Boolean(fieldState?.error?.message)}
158
+ invalidText={fieldState?.error?.message}
159
+ />
160
+ )}
176
161
  />
177
162
  </ResponsiveWrapper>
178
- ) : null}
163
+ ) : (
164
+ <DatePickerSkeleton />
165
+ )}
166
+ </section>
167
+ <section>
168
+ <div className={styles.sectionTitle}>{t('causeOfDeath', 'Cause of death')}</div>
169
+ <div
170
+ className={classNames(styles.conceptAnswerOverviewWrapper, {
171
+ [styles.conceptAnswerOverviewWrapperTablet]: isTablet,
172
+ [styles.conceptAnswerOverviewWrapperDesktop]: !isTablet,
173
+ [styles.errorOutline]: errors?.causeOfDeath?.message,
174
+ })}
175
+ >
176
+ {isLoadingCausesOfDeath ? <StructuredListSkeleton /> : null}
179
177
 
180
- {causesOfDeath?.length && filteredCausesOfDeath.length > 0 ? (
181
- <Controller
182
- name="causeOfDeath"
183
- control={control}
184
- render={({ field: { onChange } }) => (
185
- <RadioButtonGroup
186
- className={styles.radioButtonGroup}
187
- name={
188
- causeOfDeathValue === freeTextFieldConceptUuid
189
- ? 'freeTextFieldCauseOfDeath'
190
- : 'codedCauseOfDeath'
191
- }
192
- orientation="vertical"
193
- onChange={onChange}
194
- >
195
- {filteredCausesOfDeath.map(({ uuid, display, name }) => (
196
- <RadioButton
197
- className={styles.radioButton}
198
- id={name}
199
- key={uuid}
200
- labelText={display}
201
- value={uuid}
202
- />
203
- ))}
204
- </RadioButtonGroup>
205
- )}
206
- />
207
- ) : null}
178
+ {causesOfDeath?.length ? (
179
+ <ResponsiveWrapper>
180
+ <Search
181
+ labelText={t('searchForCauseOfDeath', 'Search for a cause of death')}
182
+ onChange={handleSearchTermChange}
183
+ placeholder={t('searchForCauseOfDeath', 'Search for a cause of death')}
184
+ />
185
+ </ResponsiveWrapper>
186
+ ) : null}
208
187
 
209
- {searchTerm && filteredCausesOfDeath.length === 0 && (
210
- <div className={styles.tileContainer}>
211
- <Tile className={styles.tile}>
212
- <div className={styles.tileContent}>
213
- <p className={styles.content}>
214
- {t('noMatchingCodedCausesOfDeath', 'No matching coded causes of death')}
215
- </p>
216
- <p className={styles.helper}>{t('checkFilters', 'Check the filters above')}</p>
217
- </div>
218
- </Tile>
219
- </div>
220
- )}
188
+ {causesOfDeath?.length && filteredCausesOfDeath.length > 0 ? (
189
+ <Controller
190
+ name="causeOfDeath"
191
+ control={control}
192
+ render={({ field: { onChange } }) => (
193
+ <RadioButtonGroup
194
+ className={styles.radioButtonGroup}
195
+ name={
196
+ causeOfDeathValue === freeTextFieldConceptUuid
197
+ ? 'freeTextFieldCauseOfDeath'
198
+ : 'codedCauseOfDeath'
199
+ }
200
+ orientation="vertical"
201
+ onChange={onChange}
202
+ >
203
+ {filteredCausesOfDeath.map(({ uuid, display, name }) => (
204
+ <RadioButton
205
+ className={styles.radioButton}
206
+ id={name}
207
+ key={uuid}
208
+ labelText={display}
209
+ value={uuid}
210
+ />
211
+ ))}
212
+ </RadioButtonGroup>
213
+ )}
214
+ />
215
+ ) : null}
221
216
 
222
- {!isLoadingCausesOfDeath && !causesOfDeath?.length ? (
223
- <EmptyState
224
- displayText={t('causeOfDeath_lower', 'cause of death concepts configured in the system')}
225
- headerTitle={t('causeOfDeath', 'Cause of death')}
226
- />
227
- ) : null}
228
- </div>
229
- {errors?.causeOfDeath && <p className={styles.errorMessage}>{errors?.causeOfDeath?.message}</p>}
230
- </section>
231
- </div>
232
- {causeOfDeathValue === freeTextFieldConceptUuid && (
233
- <div className={styles.nonCodedCauseOfDeath}>
234
- <Controller
235
- name="nonCodedCauseOfDeath"
236
- control={control}
237
- render={({ field: { onChange, value } }) => (
238
- <TextInput
239
- id="freeTextCauseOfDeath"
240
- invalid={!!errors?.nonCodedCauseOfDeath}
241
- invalidText={errors?.nonCodedCauseOfDeath?.message}
242
- labelText={t('nonCodedCauseOfDeath', 'Non-coded cause of death')}
243
- onChange={onChange}
244
- placeholder={t('enterNonCodedCauseOfDeath', 'Enter non-coded cause of death')}
245
- value={value}
246
- />
247
- )}
248
- />
217
+ {searchTerm && filteredCausesOfDeath.length === 0 && (
218
+ <div className={styles.tileContainer}>
219
+ <Tile className={styles.tile}>
220
+ <div className={styles.tileContent}>
221
+ <p className={styles.content}>
222
+ {t('noMatchingCodedCausesOfDeath', 'No matching coded causes of death')}
223
+ </p>
224
+ <p className={styles.helper}>{t('checkFilters', 'Check the filters above')}</p>
225
+ </div>
226
+ </Tile>
227
+ </div>
228
+ )}
229
+
230
+ {!isLoadingCausesOfDeath && !causesOfDeath?.length ? (
231
+ <EmptyState
232
+ displayText={t('causeOfDeath_lower', 'cause of death concepts configured in the system')}
233
+ headerTitle={t('causeOfDeath', 'Cause of death')}
234
+ />
235
+ ) : null}
236
+ </div>
237
+ {errors?.causeOfDeath && <p className={styles.errorMessage}>{errors?.causeOfDeath?.message}</p>}
238
+ </section>
249
239
  </div>
250
- )}
251
- </div>
252
- <ButtonSet className={classNames({ [styles.tablet]: isTablet, [styles.desktop]: !isTablet })}>
253
- <Button className={styles.button} kind="secondary" onClick={() => closeWorkspace()}>
254
- {t('discard', 'Discard')}
255
- </Button>
256
- <Button className={styles.button} disabled={isSubmitting} kind="primary" type="submit">
257
- {isSubmitting ? (
258
- <InlineLoading description={t('saving', 'Saving') + '...'} role="progressbar" />
259
- ) : (
260
- t('saveAndClose', 'Save and close')
240
+ {causeOfDeathValue === freeTextFieldConceptUuid && (
241
+ <div className={styles.nonCodedCauseOfDeath}>
242
+ <Controller
243
+ name="nonCodedCauseOfDeath"
244
+ control={control}
245
+ render={({ field: { onChange, value } }) => (
246
+ <TextInput
247
+ id="freeTextCauseOfDeath"
248
+ invalid={!!errors?.nonCodedCauseOfDeath}
249
+ invalidText={errors?.nonCodedCauseOfDeath?.message}
250
+ labelText={t('nonCodedCauseOfDeath', 'Non-coded cause of death')}
251
+ onChange={onChange}
252
+ placeholder={t('enterNonCodedCauseOfDeath', 'Enter non-coded cause of death')}
253
+ value={value}
254
+ />
255
+ )}
256
+ />
257
+ </div>
261
258
  )}
262
- </Button>
263
- </ButtonSet>
264
- </Form>
259
+ </div>
260
+ <ButtonSet className={classNames({ [styles.tablet]: isTablet, [styles.desktop]: !isTablet })}>
261
+ <Button className={styles.button} kind="secondary" onClick={() => closeWorkspace()}>
262
+ {t('discard', 'Discard')}
263
+ </Button>
264
+ <Button className={styles.button} disabled={isSubmitting} kind="primary" type="submit">
265
+ {isSubmitting ? (
266
+ <InlineLoading description={t('saving', 'Saving') + '...'} role="progressbar" />
267
+ ) : (
268
+ t('saveAndClose', 'Save and close')
269
+ )}
270
+ </Button>
271
+ </ButtonSet>
272
+ </Form>
273
+ </Workspace2>
265
274
  );
266
275
  };
267
276
 
@@ -2,7 +2,7 @@ import React, { useEffect, useMemo, useState } from 'react';
2
2
  import classNames from 'classnames';
3
3
  import { useMatch } from 'react-router-dom';
4
4
  import { useTranslation } from 'react-i18next';
5
- import { launchWorkspace, Extension, ExtensionSlot, useExtensionSlotMeta } from '@openmrs/esm-framework';
5
+ import { launchWorkspace2, Extension, ExtensionSlot, useExtensionSlotMeta } from '@openmrs/esm-framework';
6
6
  import { launchStartVisitPrompt } from '@openmrs/esm-patient-common-lib';
7
7
  import { dashboardPath } from '../../constants';
8
8
  import styles from './dashboard-view.scss';
@@ -43,7 +43,7 @@ export function DashboardView({ dashboard, patientUuid, patient }: DashboardView
43
43
  basePath: view,
44
44
  patient,
45
45
  patientUuid,
46
- launchWorkspace,
46
+ launchWorkspace2,
47
47
  launchStartVisitPrompt,
48
48
  }),
49
49
  [patient, patientUuid, view],