@openmrs/esm-patient-programs-app 3.0.0-pre.65 → 3.0.0-pre.656

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 (76) hide show
  1. package/dist/133.openmrs-esm-patient-programs-app.js +3 -0
  2. package/dist/133.openmrs-esm-patient-programs-app.js.LICENSE.txt +14 -0
  3. package/dist/133.openmrs-esm-patient-programs-app.js.map +1 -0
  4. package/dist/401.openmrs-esm-patient-programs-app.js +3 -0
  5. package/dist/401.openmrs-esm-patient-programs-app.js.LICENSE.txt +14 -0
  6. package/dist/401.openmrs-esm-patient-programs-app.js.map +1 -0
  7. package/dist/574.openmrs-esm-patient-programs-app.js +1 -0
  8. package/dist/639.openmrs-esm-patient-programs-app.js +2 -0
  9. package/dist/639.openmrs-esm-patient-programs-app.js.map +1 -0
  10. package/dist/757.openmrs-esm-patient-programs-app.js +1 -0
  11. package/dist/783.openmrs-esm-patient-programs-app.js +3 -0
  12. package/dist/783.openmrs-esm-patient-programs-app.js.LICENSE.txt +23 -0
  13. package/dist/783.openmrs-esm-patient-programs-app.js.map +1 -0
  14. package/dist/839.openmrs-esm-patient-programs-app.js +2 -0
  15. package/dist/839.openmrs-esm-patient-programs-app.js.map +1 -0
  16. package/dist/972.openmrs-esm-patient-programs-app.js +2 -0
  17. package/dist/972.openmrs-esm-patient-programs-app.js.map +1 -0
  18. package/dist/openmrs-esm-patient-programs-app.js +2 -1
  19. package/dist/openmrs-esm-patient-programs-app.js.LICENSE.txt +5 -0
  20. package/dist/openmrs-esm-patient-programs-app.js.buildmanifest.json +220 -0
  21. package/dist/openmrs-esm-patient-programs-app.js.map +1 -1
  22. package/package.json +10 -11
  23. package/src/dashboard.meta.tsx +6 -0
  24. package/src/declarations.d.tsx +3 -3
  25. package/src/index.ts +31 -30
  26. package/src/programs/program-record.component.tsx +29 -48
  27. package/src/programs/program-record.test.outdated.tsx +30 -34
  28. package/src/programs/programs-detailed-summary.component.tsx +123 -114
  29. package/src/programs/programs-detailed-summary.scss +24 -0
  30. package/src/programs/programs-detailed-summary.test.tsx +71 -0
  31. package/src/programs/programs-form.component.tsx +257 -473
  32. package/src/programs/programs-form.scss +20 -0
  33. package/src/programs/programs-form.test.tsx +206 -0
  34. package/src/programs/programs-overview.component.tsx +44 -74
  35. package/src/programs/programs-overview.scss +4 -0
  36. package/src/programs/programs-overview.test.tsx +70 -0
  37. package/src/programs/programs.component.test.tsx +21 -0
  38. package/src/programs/programs.component.tsx +6 -10
  39. package/src/programs/programs.context.tsx +1 -1
  40. package/src/programs/programs.resource.tsx +31 -43
  41. package/translations/en.json +29 -1
  42. package/webpack.config.js +1 -80
  43. package/dist/0.openmrs-esm-patient-programs-app.js +0 -22
  44. package/dist/0.openmrs-esm-patient-programs-app.js.map +0 -1
  45. package/dist/1.openmrs-esm-patient-programs-app.js +0 -2
  46. package/dist/1.openmrs-esm-patient-programs-app.js.map +0 -1
  47. package/dist/3.openmrs-esm-patient-programs-app.js +0 -23
  48. package/dist/3.openmrs-esm-patient-programs-app.js.map +0 -1
  49. package/dist/4.openmrs-esm-patient-programs-app.js +0 -2
  50. package/dist/4.openmrs-esm-patient-programs-app.js.map +0 -1
  51. package/dist/5.openmrs-esm-patient-programs-app.js +0 -2
  52. package/dist/5.openmrs-esm-patient-programs-app.js.map +0 -1
  53. package/dist/6.openmrs-esm-patient-programs-app.js +0 -2
  54. package/dist/6.openmrs-esm-patient-programs-app.js.map +0 -1
  55. package/dist/7.openmrs-esm-patient-programs-app.js +0 -2
  56. package/dist/7.openmrs-esm-patient-programs-app.js.map +0 -1
  57. package/dist/8.openmrs-esm-patient-programs-app.js +0 -2
  58. package/dist/8.openmrs-esm-patient-programs-app.js.map +0 -1
  59. package/src/cards/summary-card.component.tsx +0 -82
  60. package/src/cards/summary-card.css +0 -65
  61. package/src/dashboard/dashboard-link.component.tsx +0 -7
  62. package/src/dashboard/dashboard.meta.tsx +0 -6
  63. package/src/openmrs-backend-dependencies.ts +0 -4
  64. package/src/programs/empty-state/empty-data-illustration.component.tsx +0 -53
  65. package/src/programs/empty-state/empty-state.component.tsx +0 -39
  66. package/src/programs/empty-state/empty-state.scss +0 -34
  67. package/src/programs/error-state/error-state.component.tsx +0 -26
  68. package/src/programs/error-state/error-state.scss +0 -36
  69. package/src/programs/openWorkspaceTab.tsx +0 -40
  70. package/src/programs/programs-detailed-summary.css +0 -63
  71. package/src/programs/programs-detailed-summary.test.outdated.tsx +0 -57
  72. package/src/programs/programs-form.css +0 -95
  73. package/src/programs/programs-form.test.outdated.tsx +0 -276
  74. package/src/programs/programs-overview.test.outdated.tsx +0 -73
  75. package/src/programs/programs.component.test.outdated.tsx +0 -18
  76. package/src/set-public-path.ts +0 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-patient-programs-app",
3
- "version": "3.0.0-pre.65",
3
+ "version": "3.0.0-pre.656",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Patient programs microfrontend for the OpenMRS SPA",
6
6
  "browser": "dist/openmrs-esm-patient-programs-app.js",
@@ -8,12 +8,13 @@
8
8
  "source": true,
9
9
  "scripts": {
10
10
  "start": "openmrs develop",
11
- "serve": "webpack-dev-server --mode=development",
11
+ "serve": "webpack serve --mode=development",
12
12
  "debug": "npm run serve",
13
13
  "build": "webpack --mode production",
14
- "analyze": "webpack --mode=production --env.analyze=true",
14
+ "analyze": "webpack --mode=production --env analyze=true",
15
15
  "lint": "eslint src --ext tsx",
16
- "typescript": "tsc"
16
+ "typescript": "tsc",
17
+ "extract-translations": "i18next 'src/**/*.component.tsx' --config ../../tools/i18next-parser.config.js"
17
18
  },
18
19
  "browserslist": [
19
20
  "extends browserslist-config-openmrs"
@@ -33,14 +34,12 @@
33
34
  "url": "https://github.com/openmrs/openmrs-esm-patient-chart/issues"
34
35
  },
35
36
  "dependencies": {
36
- "@carbon/charts-react": "^0.41.14",
37
+ "@carbon/charts-react": "^0.49.4",
37
38
  "@carbon/icons-react": "^10.18.0",
38
- "@typescript-eslint/eslint-plugin": "^4.15.1",
39
- "@typescript-eslint/parser": "^4.15.1",
39
+ "@openmrs/esm-patient-common-lib": "^3.0.0-pre.656",
40
40
  "carbon-components-react": "^7.25.0",
41
- "d3": "^5.16.0",
42
- "lodash-es": "^4.17.15",
43
- "systemjs-webpack-interop": "^1.2.1"
41
+ "d3": "^7.0.3",
42
+ "lodash-es": "^4.17.15"
44
43
  },
45
44
  "peerDependencies": {
46
45
  "@openmrs/esm-framework": "3.x",
@@ -52,5 +51,5 @@
52
51
  "react-router-dom": "5.x",
53
52
  "rxjs": "6.x"
54
53
  },
55
- "gitHead": "9c561dc987f568a72d84f14fe0a5441fbd1a899d"
54
+ "gitHead": "05cb6928412c65c483d301ede8b3d6385a6f9e8b"
56
55
  }
@@ -0,0 +1,6 @@
1
+ export const dashboardMeta = {
2
+ name: 'programs',
3
+ slot: 'patient-chart-programs-dashboard-slot',
4
+ config: { columns: 1, type: 'grid' },
5
+ title: 'Programs',
6
+ };
@@ -1,3 +1,3 @@
1
- declare module "*.css";
2
- declare module "*.scss";
3
- declare module "*.png";
1
+ declare module '*.css';
2
+ declare module '*.scss';
3
+ declare module '*.png';
package/src/index.ts CHANGED
@@ -1,19 +1,22 @@
1
- import { defineConfigSchema, getAsyncLifecycle } from "@openmrs/esm-framework";
2
- import { backendDependencies } from "./openmrs-backend-dependencies";
3
- import dashboardMeta from "./dashboard/dashboard.meta";
1
+ import { defineConfigSchema, getAsyncLifecycle, getSyncLifecycle } from '@openmrs/esm-framework';
2
+ import { createDashboardLink } from '@openmrs/esm-patient-common-lib';
3
+ import { dashboardMeta } from './dashboard.meta';
4
4
 
5
- const importTranslation = require.context(
6
- "../translations",
7
- false,
8
- /.json$/,
9
- "lazy"
10
- );
5
+ const importTranslation = require.context('../translations', false, /.json$/, 'lazy');
6
+
7
+ const backendDependencies = {
8
+ 'webservices.rest': '^2.2.0',
9
+ };
10
+
11
+ const frontendDependencies = {
12
+ '@openmrs/esm-framework': process.env.FRAMEWORK_VERSION,
13
+ };
11
14
 
12
15
  function setupOpenMRS() {
13
- const moduleName = "@openmrs/esm-patient-programs-app";
16
+ const moduleName = '@openmrs/esm-patient-programs-app';
14
17
 
15
18
  const options = {
16
- featureName: "patient-programs",
19
+ featureName: 'patient-programs',
17
20
  moduleName,
18
21
  };
19
22
 
@@ -22,38 +25,36 @@ function setupOpenMRS() {
22
25
  return {
23
26
  extensions: [
24
27
  {
25
- id: "programs-overview-widget",
26
- slot: "patient-chart-summary-dashboard-slot",
27
- load: getAsyncLifecycle(
28
- () => import("./programs/programs-overview.component"),
29
- options
30
- ),
28
+ id: 'programs-overview-widget',
29
+ slot: 'patient-chart-summary-dashboard-slot',
30
+ load: getAsyncLifecycle(() => import('./programs/programs-overview.component'), options),
31
31
  meta: {
32
- columnSpan: 2,
32
+ columnSpan: 4,
33
33
  },
34
34
  },
35
35
  {
36
- id: "programs-details-widget",
36
+ id: 'programs-details-widget',
37
37
  slot: dashboardMeta.slot,
38
- load: getAsyncLifecycle(
39
- () => import("./programs/programs.component"),
40
- options
41
- ),
38
+ load: getAsyncLifecycle(() => import('./programs/programs.component'), options),
42
39
  meta: {
43
40
  columnSpan: 1,
44
41
  },
45
42
  },
46
43
  {
47
- id: "programs-summary-dashboard",
48
- slot: "patient-chart-dashboard-slot",
49
- load: getAsyncLifecycle(
50
- () => import("./dashboard/dashboard-link.component"),
51
- options
52
- ),
44
+ id: 'programs-summary-dashboard',
45
+ slot: 'patient-chart-dashboard-slot',
46
+ load: getSyncLifecycle(createDashboardLink(dashboardMeta), options),
53
47
  meta: dashboardMeta,
54
48
  },
49
+ {
50
+ id: 'programs-form-workspace',
51
+ load: getAsyncLifecycle(() => import('./programs/programs-form.component'), options),
52
+ meta: {
53
+ title: 'Record Program enrollment',
54
+ },
55
+ },
55
56
  ],
56
57
  };
57
58
  }
58
59
 
59
- export { backendDependencies, importTranslation, setupOpenMRS };
60
+ export { backendDependencies, frontendDependencies, importTranslation, setupOpenMRS };
@@ -1,17 +1,15 @@
1
- import React, { useEffect, useState } from "react";
2
- import dayjs from "dayjs";
3
- import SummaryCard from "../cards/summary-card.component";
4
- import ProgramsForm from "./programs-form.component";
5
- import styles from "./program-record.css";
6
- import { RouteComponentProps } from "react-router-dom";
7
- import { useTranslation, Trans } from "react-i18next";
8
- import { createErrorHandler } from "@openmrs/esm-framework";
9
- import { getPatientProgramByUuid } from "./programs.resource";
10
- import { useProgramsContext } from "./programs.context";
11
- import { openWorkspaceTab } from "./openWorkspaceTab";
1
+ import React, { useEffect, useState } from 'react';
2
+ import dayjs from 'dayjs';
3
+ import ProgramsForm from './programs-form.component';
4
+ import styles from './program-record.css';
5
+ import { SummaryCard, openWorkspaceTab } from '@openmrs/esm-patient-common-lib';
6
+ import { RouteComponentProps } from 'react-router-dom';
7
+ import { useTranslation, Trans } from 'react-i18next';
8
+ import { createErrorHandler } from '@openmrs/esm-framework';
9
+ import { getPatientProgramByUuid } from './programs.resource';
10
+ import { useProgramsContext } from './programs.context';
12
11
 
13
- interface ProgramRecordProps
14
- extends RouteComponentProps<{ programUuid: string }> {}
12
+ interface ProgramRecordProps extends RouteComponentProps<{ programUuid: string }> {}
15
13
 
16
14
  const ProgramRecord: React.FC<ProgramRecordProps> = ({ match }) => {
17
15
  const [patientProgram, setPatientProgram] = useState(null);
@@ -21,11 +19,9 @@ const ProgramRecord: React.FC<ProgramRecordProps> = ({ match }) => {
21
19
 
22
20
  useEffect(() => {
23
21
  if (patient && patientUuid) {
24
- const subscription = getPatientProgramByUuid(programUuid).subscribe(
25
- (program) => {
26
- setPatientProgram(program), createErrorHandler();
27
- }
28
- );
22
+ const subscription = getPatientProgramByUuid(programUuid).subscribe((program) => {
23
+ setPatientProgram(program), createErrorHandler();
24
+ });
29
25
 
30
26
  return () => subscription.unsubscribe();
31
27
  }
@@ -36,23 +32,18 @@ const ProgramRecord: React.FC<ProgramRecordProps> = ({ match }) => {
36
32
  {!!(patientProgram && Object.entries(patientProgram).length) && (
37
33
  <div className={styles.programSummary}>
38
34
  <SummaryCard
39
- name={t("program", "Program")}
40
- styles={{ width: "100%" }}
41
- editComponent={ProgramsForm}
35
+ name={t('program', 'Program')}
36
+ styles={{ width: '100%' }}
37
+ editComponent
42
38
  showComponent={() =>
43
- openWorkspaceTab(
44
- ProgramsForm,
45
- `${t("editProgram", "Edit Program")}`,
46
- {
47
- program: patientProgram?.program?.name,
48
- programUuid: patientProgram?.uuid,
49
- enrollmentDate: patientProgram?.dateEnrolled,
50
- completionDate: patientProgram?.dateCompleted,
51
- locationUuid: patientProgram?.location?.uuid,
52
- }
53
- )
54
- }
55
- >
39
+ openWorkspaceTab(ProgramsForm, `${t('editProgram', 'Edit program')}`, {
40
+ program: patientProgram?.program?.name,
41
+ programUuid: patientProgram?.uuid,
42
+ enrollmentDate: patientProgram?.dateEnrolled,
43
+ completionDate: patientProgram?.dateCompleted,
44
+ locationUuid: patientProgram?.location?.uuid,
45
+ })
46
+ }>
56
47
  <div className={`omrs-type-body-regular ${styles.programCard}`}>
57
48
  <div>
58
49
  <p className="omrs-type-title-3" data-testid="program-name">
@@ -75,28 +66,18 @@ const ProgramRecord: React.FC<ProgramRecordProps> = ({ match }) => {
75
66
  </thead>
76
67
  <tbody>
77
68
  <tr>
78
- <td>
79
- {dayjs(patientProgram?.dateEnrolled).format(
80
- "DD-MMM-YYYY"
81
- )}
82
- </td>
69
+ <td>{dayjs(patientProgram?.dateEnrolled).format('DD-MMM-YYYY')}</td>
83
70
  <td className={styles.completedProgram}>
84
71
  {patientProgram?.dateCompleted ? (
85
72
  <span className={styles.completionDate}>
86
- <Trans i18nKey="completedOn">Completed on</Trans>{" "}
87
- {dayjs(patientProgram?.dateCompleted).format(
88
- "DD-MMM-YYYY"
89
- )}
73
+ <Trans i18nKey="completedOn">Completed on</Trans>{' '}
74
+ {dayjs(patientProgram?.dateCompleted).format('DD-MMM-YYYY')}
90
75
  </span>
91
76
  ) : (
92
77
  <Trans i18nKey="active">Active</Trans>
93
78
  )}
94
79
  </td>
95
- <td>
96
- {patientProgram?.location
97
- ? patientProgram?.location?.display
98
- : "-"}
99
- </td>
80
+ <td>{patientProgram?.location?.display || '-'}</td>
100
81
  </tr>
101
82
  </tbody>
102
83
  </table>
@@ -1,19 +1,19 @@
1
- import React from "react";
2
- import ProgramRecord from "./program-record.component";
3
- import ProgramsForm from "./programs-form.component";
4
- import { fireEvent, render, screen } from "@testing-library/react";
5
- import { BrowserRouter } from "react-router-dom";
6
- import { mockProgramResponse } from "../../../../__mocks__/programs.mock";
7
- import { getPatientProgramByUuid } from "./programs.resource";
8
- import { of } from "rxjs/internal/observable/of";
1
+ import React from 'react';
2
+ import ProgramRecord from './program-record.component';
3
+ import ProgramsForm from './programs-form.component';
4
+ import { fireEvent, render, screen } from '@testing-library/react';
5
+ import { BrowserRouter } from 'react-router-dom';
6
+ import { mockProgramResponse } from '../../../../__mocks__/programs.mock';
7
+ import { getPatientProgramByUuid } from './programs.resource';
8
+ import { of } from 'rxjs/internal/observable/of';
9
9
 
10
10
  const mockFetchPatientProgram = getPatientProgramByUuid as jest.Mock;
11
11
 
12
- jest.mock("./programs.resource", () => ({
12
+ jest.mock('./programs.resource', () => ({
13
13
  getPatientProgramByUuid: jest.fn(),
14
14
  }));
15
15
 
16
- describe("<ProgramRecord />", () => {
16
+ describe('<ProgramRecord />', () => {
17
17
  beforeEach(() => {
18
18
  mockFetchPatientProgram.mockReset;
19
19
  mockFetchPatientProgram.mockReturnValue(of(mockProgramResponse));
@@ -21,41 +21,37 @@ describe("<ProgramRecord />", () => {
21
21
 
22
22
  afterEach(() => jest.restoreAllMocks());
23
23
 
24
- it("displays a detailed summary of the selected care program", async () => {
24
+ it('displays a detailed summary of the selected care program', async () => {
25
25
  const mockOpenWorkspaceTab = jest.fn();
26
26
 
27
27
  render(
28
28
  <BrowserRouter>
29
- <ProgramRecord match={{ params: { programUuid: "" } }} />
30
- </BrowserRouter>
29
+ <ProgramRecord match={{ params: { programUuid: '' } }} />
30
+ </BrowserRouter>,
31
31
  );
32
32
 
33
- await screen.findByRole("heading", { name: "Program" });
33
+ await screen.findByRole('heading', { name: 'Program' });
34
34
 
35
- expect(screen.getByText("Program")).toBeInTheDocument();
36
- const editBtn = screen.getByRole("button", { name: "Edit" });
35
+ expect(screen.getByText('Program')).toBeInTheDocument();
36
+ const editBtn = screen.getByRole('button', { name: 'Edit' });
37
37
  expect(editBtn).toBeInTheDocument();
38
- expect(screen.getByText("HIV Care and Treatment")).toBeInTheDocument();
39
- expect(screen.getByText("Enrolled on")).toBeInTheDocument();
40
- expect(screen.getByText("Status")).toBeInTheDocument();
41
- expect(screen.getByText("Enrolled at")).toBeInTheDocument();
42
- expect(screen.getByText("01-Nov-2019")).toBeInTheDocument();
43
- expect(screen.getByText("Active")).toBeInTheDocument();
44
- expect(screen.getByText("-")).toBeInTheDocument();
38
+ expect(screen.getByText('HIV Care and Treatment')).toBeInTheDocument();
39
+ expect(screen.getByText('Enrolled on')).toBeInTheDocument();
40
+ expect(screen.getByText('Status')).toBeInTheDocument();
41
+ expect(screen.getByText('Enrolled at')).toBeInTheDocument();
42
+ expect(screen.getByText('01-Nov-2019')).toBeInTheDocument();
43
+ expect(screen.getByText('Active')).toBeInTheDocument();
44
+ expect(screen.getByText('-')).toBeInTheDocument();
45
45
 
46
46
  // Clicking "Edit" launches edit form in workspace tab
47
47
  fireEvent.click(editBtn);
48
48
  expect(mockOpenWorkspaceTab).toHaveBeenCalled();
49
- expect(mockOpenWorkspaceTab).toHaveBeenCalledWith(
50
- ProgramsForm,
51
- "Edit Program",
52
- {
53
- completionDate: null,
54
- enrollmentDate: "2019-11-01T15:00:00.000+0000",
55
- location: undefined,
56
- program: "HIV Care and Treatment",
57
- programUuid: "8ba6c08f-66d9-4a18-a233-5f658b1755bf",
58
- }
59
- );
49
+ expect(mockOpenWorkspaceTab).toHaveBeenCalledWith(ProgramsForm, 'Edit Program', {
50
+ completionDate: null,
51
+ enrollmentDate: '2019-11-01T15:00:00.000+0000',
52
+ location: undefined,
53
+ program: 'HIV Care and Treatment',
54
+ programUuid: '8ba6c08f-66d9-4a18-a233-5f658b1755bf',
55
+ });
60
56
  });
61
57
  });
@@ -1,134 +1,143 @@
1
- import React, { useEffect, useState } from "react";
2
- import dayjs from "dayjs";
3
- import ProgramsForm from "./programs-form.component";
4
- import EmptyState from "./empty-state/empty-state.component";
5
- import SummaryCard from "../cards/summary-card.component";
6
- import styles from "./programs-detailed-summary.css";
7
- import { useTranslation, Trans } from "react-i18next";
8
- import { RouteComponentProps, Link } from "react-router-dom";
9
- import { createErrorHandler } from "@openmrs/esm-framework";
10
- import { fetchEnrolledPrograms } from "./programs.resource";
11
- import { useProgramsContext } from "./programs.context";
12
- import { openWorkspaceTab } from "./openWorkspaceTab";
13
- import { PatientProgram } from "../types";
1
+ import React, { useEffect, useMemo, useState } from 'react';
2
+ import dayjs from 'dayjs';
3
+ import Add16 from '@carbon/icons-react/es/add/16';
4
+ import styles from './programs-detailed-summary.scss';
5
+ import { EmptyState, ErrorState } from '@openmrs/esm-patient-common-lib';
6
+ import { useTranslation } from 'react-i18next';
7
+ import { attach } from '@openmrs/esm-framework';
8
+ import { fetchEnrolledPrograms } from './programs.resource';
9
+ import { useProgramsContext } from './programs.context';
10
+ import { PatientProgram } from '../types';
11
+ import {
12
+ Button,
13
+ DataTable,
14
+ DataTableSkeleton,
15
+ Table,
16
+ TableCell,
17
+ TableContainer,
18
+ TableBody,
19
+ TableHead,
20
+ TableHeader,
21
+ TableRow,
22
+ DataTableHeader,
23
+ DataTableRow,
24
+ } from 'carbon-components-react';
14
25
 
15
- interface ProgramsDetailedSummaryProps extends RouteComponentProps<{}> {}
26
+ interface ProgramsDetailedSummaryProps {}
16
27
 
17
28
  const ProgramsDetailedSummary: React.FC<ProgramsDetailedSummaryProps> = () => {
18
- const [enrolledPrograms, setEnrolledPrograms] = useState<
19
- Array<PatientProgram>
20
- >([]);
21
- const { patientUuid } = useProgramsContext();
22
29
  const { t } = useTranslation();
30
+ const displayText = t('programEnrollments', 'Program enrollments');
31
+ const headerTitle = t('carePrograms', 'Care Programs');
32
+ const [enrolledPrograms, setEnrolledPrograms] = useState<Array<PatientProgram>>(null);
33
+ const { patientUuid } = useProgramsContext();
34
+ const [error, setError] = useState(null);
23
35
 
24
36
  useEffect(() => {
25
37
  if (patientUuid) {
26
38
  const subscription = fetchEnrolledPrograms(patientUuid).subscribe(
27
39
  (enrolledPrograms) => setEnrolledPrograms(enrolledPrograms),
28
- createErrorHandler()
40
+ setError,
29
41
  );
30
42
  return () => subscription.unsubscribe();
31
43
  }
32
44
  }, [patientUuid]);
33
45
 
46
+ const tableHeader: Array<DataTableHeader> = useMemo(
47
+ () => [
48
+ {
49
+ key: 'display',
50
+ header: t('activePrograms', 'Active programs'),
51
+ },
52
+ {
53
+ key: 'dateEnrolled',
54
+ header: t('dateEnrolled', 'Date enrolled'),
55
+ },
56
+ {
57
+ key: 'status',
58
+ header: t('status', 'Status'),
59
+ },
60
+ ],
61
+ [t],
62
+ );
63
+
64
+ const tableRows: Array<DataTableRow> = useMemo(() => {
65
+ return enrolledPrograms?.map((programs) => {
66
+ return {
67
+ id: programs.uuid,
68
+ display: programs.display,
69
+ dateEnrolled: dayjs(programs.dateEnrolled).format('MMM-YYYY'),
70
+ status: programs.dateCompleted
71
+ ? `${t('completedOn', 'Completed On')} ${dayjs(programs.dateCompleted).format('MMM-YYYY')}`
72
+ : t('active', 'Active'),
73
+ };
74
+ });
75
+ }, [enrolledPrograms, t]);
76
+
77
+ const launchProgramsForm = React.useCallback(
78
+ () => attach('patient-chart-workspace-slot', 'programs-form-workspace'),
79
+ [],
80
+ );
81
+
82
+ const RenderPrograms = () => {
83
+ return (
84
+ <>
85
+ {enrolledPrograms?.length ? (
86
+ <div className={styles.widgetCard}>
87
+ <div className={styles.programsHeader}>
88
+ <h4 className={`${styles.productiveHeading03} ${styles.text02}`}>{headerTitle}</h4>
89
+ <Button kind="ghost" renderIcon={Add16} iconDescription="Add programs" onClick={launchProgramsForm}>
90
+ {t('add', 'Add')}
91
+ </Button>
92
+ </div>
93
+
94
+ <TableContainer>
95
+ <DataTable rows={tableRows} headers={tableHeader} isSortable={true} size="short">
96
+ {({ rows, headers, getHeaderProps, getTableProps }) => (
97
+ <Table {...getTableProps()} useZebraStyles>
98
+ <TableHead>
99
+ <TableRow>
100
+ {headers.map((header) => (
101
+ <TableHeader
102
+ className={`${styles.productiveHeading01} ${styles.text02}`}
103
+ {...getHeaderProps({
104
+ header,
105
+ isSortable: header.isSortable,
106
+ })}>
107
+ {header.header?.content ?? header.header}
108
+ </TableHeader>
109
+ ))}
110
+ </TableRow>
111
+ </TableHead>
112
+ <TableBody>
113
+ {rows.map((row) => (
114
+ <TableRow key={row.id}>
115
+ {row.cells.map((cell) => (
116
+ <TableCell key={cell.id}>{cell.value?.content ?? cell.value}</TableCell>
117
+ ))}
118
+ </TableRow>
119
+ ))}
120
+ </TableBody>
121
+ </Table>
122
+ )}
123
+ </DataTable>
124
+ </TableContainer>
125
+ </div>
126
+ ) : (
127
+ <EmptyState displayText={displayText} headerTitle={headerTitle} launchForm={launchProgramsForm} />
128
+ )}
129
+ </>
130
+ );
131
+ };
132
+
34
133
  return (
35
134
  <>
36
- {enrolledPrograms?.length ? (
37
- <div className={styles.programsSummary}>
38
- <SummaryCard
39
- name={t("carePrograms", "Care Programs")}
40
- styles={{
41
- width: "100%",
42
- }}
43
- addComponent={ProgramsForm}
44
- showComponent={() =>
45
- openWorkspaceTab(
46
- ProgramsForm,
47
- `${t("programsForm", "Programs Form")}`,
48
- {
49
- setEnrolledPrograms: setEnrolledPrograms,
50
- enrolledPrograms: enrolledPrograms,
51
- }
52
- )
53
- }
54
- >
55
- <table className={`omrs-type-body-regular ${styles.programTable}`}>
56
- <thead>
57
- <tr>
58
- <th>
59
- <Trans i18nKey="activePrograms">Active Programs</Trans>
60
- </th>
61
- <th>
62
- <Trans i18nKey="since">Since</Trans>
63
- </th>
64
- <th>
65
- <Trans i18nKey="status">Status</Trans>
66
- </th>
67
- <th></th>
68
- </tr>
69
- </thead>
70
- <tbody>
71
- {enrolledPrograms?.map((program) => {
72
- return (
73
- <React.Fragment key={program.uuid}>
74
- <tr
75
- className={`${
76
- program.dateCompleted
77
- ? `${styles.inactive}`
78
- : `${styles.active}`
79
- }`}
80
- >
81
- <td className="omrs-medium">{program.display}</td>
82
- <td>
83
- {dayjs(program.dateEnrolled).format("MMM-YYYY")}
84
- </td>
85
- <td>
86
- {program.dateCompleted ? (
87
- <span className={styles.completionDate}>
88
- <Trans i18nKey="Completed on">Completed on</Trans>{" "}
89
- {dayjs(program.dateCompleted).format(
90
- "DD-MMM-YYYY"
91
- )}
92
- </span>
93
- ) : (
94
- <Trans i18nKey="active">Active</Trans>
95
- )}
96
- </td>
97
- <td>
98
- {
99
- <Link to={`/${program.uuid}`}>
100
- <svg
101
- className="omrs-icon"
102
- fill="var(--omrs-color-ink-low-contrast)"
103
- >
104
- <use xlinkHref="#omrs-icon-chevron-right" />
105
- </svg>
106
- </Link>
107
- }
108
- </td>
109
- </tr>
110
- </React.Fragment>
111
- );
112
- })}
113
- </tbody>
114
- </table>
115
- </SummaryCard>
116
- </div>
135
+ {enrolledPrograms ? (
136
+ <RenderPrograms />
137
+ ) : error ? (
138
+ <ErrorState error={error} headerTitle={headerTitle} />
117
139
  ) : (
118
- <EmptyState
119
- displayText={t("programEnrollments", "program enrollments")}
120
- headerTitle={t("carePrograms", "Care Programs")}
121
- launchForm={() =>
122
- openWorkspaceTab(
123
- ProgramsForm,
124
- `${t("programsForm", "Programs Form")}`,
125
- {
126
- setEnrolledPrograms: setEnrolledPrograms,
127
- enrolledPrograms: enrolledPrograms,
128
- }
129
- )
130
- }
131
- />
140
+ <DataTableSkeleton rowCount={5} />
132
141
  )}
133
142
  </>
134
143
  );
@@ -0,0 +1,24 @@
1
+
2
+ @import "~@openmrs/esm-styleguide/src/vars";
3
+ @import "~carbon-components/src/globals/scss/vars";
4
+ @import "~carbon-components/src/globals/scss/mixins";
5
+
6
+ .widgetCard {
7
+ border: 1px solid $ui-03;
8
+ }
9
+
10
+ .programsHeader {
11
+ display: flex;
12
+ justify-content: space-between;
13
+ align-items: center;
14
+ padding: $spacing-04 0 $spacing-04 $spacing-05;
15
+ background-color: $ui-background;
16
+ }
17
+
18
+ .programsHeader > h4:after {
19
+ content: "";
20
+ display: block;
21
+ width: 2rem;
22
+ padding-top: 0.188rem;
23
+ border-bottom: 0.375rem solid $brand-teal-01;
24
+ }