Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(feat) UHM-8240 Create O2 Visit Summary workspace for Ward App #1

Merged
merged 3 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module.exports = {
'@openmrs/esm-framework': '@openmrs/esm-framework/mock',
'^dexie$': require.resolve('dexie'),
'^lodash-es/(.*)$': 'lodash/$1',
'lodash-es': 'lodash',
'^react-i18next$': path.resolve(__dirname, 'react-i18next.js'),
'^uuid$': path.resolve(__dirname, 'node_modules', 'uuid', 'dist', 'index.js'),
},
Expand Down
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
"extract-translations": "turbo extract-translations -- --config ../../tools/i18next-parser.config.js"
},
"devDependencies": {
"@carbon/react": "~1.37.0",
"@openmrs/esm-framework": "next",
"@playwright/test": "^1.42.1",
"@swc/core": "^1.2.203",
"@swc/jest": "^0.2.21",
Expand All @@ -37,19 +39,19 @@
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react-hooks": "^4.6.0",
"husky": "^8.0.3",
"i18next": "^19.0.0",
"i18next": "^21.10.0",
"i18next-parser": "^6.6.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^27.0.4",
"jest-cli": "^27.0.4",
"mockdate": "^3.0.5",
"openmrs": "^5.4.0",
"openmrs": "next",
"prettier": "^3.2.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"rxjs": "^6.6.7",
"swc-loader": "^0.2.6",
"turbo": "^1.12.5",
"turbo": "^2.2.3",
"typescript": "^4.9.5",
"webpack": "^5.90.3",
"webpack-cli": "^4.10.0"
Expand Down
1 change: 1 addition & 0 deletions packages/esm-commons-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This ESM is not really an app (for now). It is a place to define extensions to be slotted into other apps that are not PIH specific (e.g. the ward app).
51 changes: 51 additions & 0 deletions packages/esm-commons-app/__mocks__/react-i18next.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/** At present, this entire mock is boilerplate. */

const React = require('react');
const reactI18next = require('react-i18next');

const hasChildren = (node) => node && (node.children || (node.props && node.props.children));

const getChildren = (node) => (node && node.children ? node.children : node.props && node.props.children);

const renderNodes = (reactNodes) => {
if (typeof reactNodes === 'string') {
return reactNodes;
}

return Object.keys(reactNodes).map((key, i) => {
const child = reactNodes[key];
const isElement = React.isValidElement(child);

if (typeof child === 'string') {
return child;
}
if (hasChildren(child)) {
const inner = renderNodes(getChildren(child));
return React.cloneElement(child, { ...child.props, key: i }, inner);
}
if (typeof child === 'object' && !isElement) {
return Object.keys(child).reduce((str, childKey) => `${str}${child[childKey]}`, '');
}

return child;
});
};

const useMock = [(k) => k, {}];
useMock.t = (k, o) => (o && o.defaultValue) || (typeof o === 'string' ? o : k);
useMock.i18n = {};

module.exports = {
// this mock makes sure any components using the translate HoC receive the t function as a prop
Trans: ({ children }) => renderNodes(children),
Translation: ({ children }) => children((k) => k, { i18n: {} }),
useTranslation: () => useMock,

// mock if needed
I18nextProvider: reactI18next.I18nextProvider,
initReactI18next: reactI18next.initReactI18next,
setDefaults: reactI18next.setDefaults,
getDefaults: reactI18next.getDefaults,
setI18n: reactI18next.setI18n,
getI18n: reactI18next.getI18n,
};
3 changes: 3 additions & 0 deletions packages/esm-commons-app/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const rootConfig = require('../../jest.config.js');

module.exports = rootConfig;
57 changes: 57 additions & 0 deletions packages/esm-commons-app/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"name": "@pih/esm-commons-app",
"version": "1.0.0",
"description": "An app to define extensions to be slotted into other apps that are not PIH specific.",
"browser": "dist/pih-esm-commons-app.js",
"main": "src/index.ts",
"source": true,
"license": "MPL-2.0",
"homepage": "https://github.com/PIH/openmrs-esm-pihemr#readme",
"scripts": {
"start": "openmrs develop",
"serve": "webpack serve --mode=development",
"debug": "npm run serve",
"build": "webpack --mode production",
"analyze": "webpack --mode=production --env.analyze=true",
"lint": "cross-env eslint src --ext ts,tsx",
"test": "cross-env TZ=UTC jest --config jest.config.js --verbose false --passWithNoTests --color",
"test:watch": "cross-env TZ=UTC jest --watch --config jest.config.js --color",
"coverage": "yarn test --coverage",
"typescript": "tsc",
"extract-translations": "i18next 'src/**/*.component.tsx'"
},
"browserslist": [
"extends browserslist-config-openmrs"
],
"keywords": [
"openmrs"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/PIH/openmrs-esm-pihemr.git"
},
"bugs": {
"url": "https://github.com/PIH/openmrs-esm-pihemr/issues"
},
"dependencies": {
"@babel/runtime": "^7.24.0",
"@carbon/react": "~1.37.0",
"moment": "^2.30.1",
"react-dates": "^21.8.0",
"webpack": "^5.74.0"
},
"peerDependencies": {
"@openmrs/esm-framework": "5.x",
"i18next": "^19.0.0",
"react": "18.x",
"react-i18next": "11.x",
"react-router-dom": "^6.x",
"swr": "2.x"
},
"devDependencies": {
"webpack": "^5.74.0"
}
}
30 changes: 30 additions & 0 deletions packages/esm-commons-app/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* This is the entrypoint file of the application. It communicates the
* important features of this microfrontend to the app shell. It
* connects the app shell to the React application(s) that make up this
* microfrontend.
*/

import { getAsyncLifecycle } from '@openmrs/esm-framework';

const moduleName = '@pih/esm-commons-app';
const options = {
featureName: 'commons',
moduleName,
};

export const importTranslation = require.context('../translations', false, /.json$/, 'lazy');

// export const root = getAsyncLifecycle(() => import('./root.component'), options);

export const o2VisitSummaryWorkspaceSideRailIcon = getAsyncLifecycle(
() => import('./ward-app/o2-visit-summary-action-button.extension'),
options,
);

export const o2VisitSummaryWorkspace = getAsyncLifecycle(
() => import('./ward-app/o2-visit-summary-workspace.component'),
options,
);

export function startupApp() {}
23 changes: 23 additions & 0 deletions packages/esm-commons-app/src/routes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"$schema": "https://json.openmrs.org/routes.schema.json",
"pages": [
],
"extensions": [
{
"name": "o2-visit-summary-workspace-siderail-button",
"component": "o2VisitSummaryWorkspaceSideRailIcon",
"slot": "action-menu-ward-patient-items-slot"
}
],
"workspaces": [
{
"name": "o2-visit-summary-workspace",
"component": "o2VisitSummaryWorkspace",
"title": "visitSummary",
"type": "o2-visit-summary",
"sidebarFamily": "ward-patient",
"hasOwnSidebar": true,
"width": "extra-wide"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ActionMenuButton, launchWorkspace, UserAvatarIcon } from '@openmrs/esm-framework';
import React from 'react';
import { useTranslation } from 'react-i18next';
import type { WardPatientWorkspaceProps } from './types';

export default function WardPatientActionButton() {
const { t } = useTranslation();

return (
<ActionMenuButton
getIcon={(props) => <UserAvatarIcon {...props} />}
label={t('visitSummary', 'Visit summary')}
iconDescription={t('patientVisitSummary', 'Patient visit summary')}
handler={() => launchWorkspace<WardPatientWorkspaceProps>('o2-visit-summary-workspace')}
type={'o2-visit-summary'}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React, { useCallback, useRef } from 'react';
import { type WardPatientWorkspaceProps } from './types';
import styles from './o2-visit-summary-workspace.scss';

const O2VisitSummaryWorkspace: React.FC<WardPatientWorkspaceProps> = ({ wardPatient }) => {
const { patient, visit } = wardPatient ?? {};
const iframeRef = useRef<HTMLIFrameElement>();

// hide the headers breadcrumbs and visit actions from
const onLoad = useCallback(() => {
const dashboard = iframeRef.current.contentDocument;
const elementsToHide = ['header', '.patient-header', '#breadcrumbs', '.visit-actions', '#choose-another-visit'];

const styleTag = dashboard.createElement('style');
styleTag.innerHTML = elementsToHide.map((e) => `${e} {display: none;}`).join('\n');
dashboard.head.appendChild(styleTag);
}, []);

if (patient && visit) {
const src = `/openmrs/pihcore/visit/visit.page?patient=${patient.uuid}&visit=${visit.uuid}`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, but, annoyingly, in Mirebalais the web app is called "mirebalais", not "openmrs". I think we have a variable with the webapp name? Otherwise, we can cross this bridge when we come to it (we've wanted to rename the Mirebalais web app for years).

Copy link
Collaborator Author

@chibongho chibongho Nov 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't find a variable for it. I'll leave it as is for now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sure there must be a variable for this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found openmrsBase. I just pushed a change to make it use that.

return (
<div className={styles.iframeWrapper}>
<iframe ref={iframeRef} src={src} onLoad={onLoad} className={styles.o2Iframe} />
</div>
);
} else {
return;
}
};

export default O2VisitSummaryWorkspace;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.iframeWrapper {
height: 100%;
width: 100%;
}

.o2Iframe {
height: 100%;
width: 100%;
}
11 changes: 11 additions & 0 deletions packages/esm-commons-app/src/ward-app/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { DefaultWorkspaceProps, Patient, Visit } from '@openmrs/esm-framework';

// a stripped down version of the same type defined in esm-ward-app
export type WardPatient = {
patient: Patient;
visit: Visit;
};

export interface WardPatientWorkspaceProps extends DefaultWorkspaceProps {
wardPatient: WardPatient;
}
4 changes: 4 additions & 0 deletions packages/esm-commons-app/translations/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why, but I had to manually add these translations in, even though there is an extract-translations pre-commit hook. Projects like openmrs-esm-patient-management automatically updates this file on commit.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to see if we can get an answer to why that is.

"patientVisitSummary": "Patient visit summary",
"visitSummary": "Visit summary"
}
4 changes: 4 additions & 0 deletions packages/esm-commons-app/translations/es.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"patientVisitSummary": "Patient visit summary",
"visitSummary": "Visit summary"
}
4 changes: 4 additions & 0 deletions packages/esm-commons-app/translations/fr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"patientVisitSummary": "Patient visit summary",
"visitSummary": "Visit summary"
}
5 changes: 5 additions & 0 deletions packages/esm-commons-app/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"extends": "../../tsconfig.json",
"include": ["src/**/*"],
"exclude": ["src/**/*.test.tsx"]
}
1 change: 1 addition & 0 deletions packages/esm-commons-app/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('openmrs/default-webpack-config');
22 changes: 7 additions & 15 deletions packages/esm-referrals-queue-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,28 +38,20 @@
},
"dependencies": {
"@babel/runtime": "^7.24.0",
"@carbon/react": "~1.37.0",
"moment": "^2.30.1",
"react-dates": "^21.8.0"
"react-dates": "^21.8.0",
"webpack": "^5.74.0"
},
"peerDependencies": {
"@openmrs/esm-framework": "^5.4.0",
"@openmrs/esm-framework": "5.x",
"i18next": "^19.0.0",
"react": "18.x",
"react-dom": "18.x",
"react-i18next": "11.x",
"rxjs": "6.x",
"single-spa": "^6.x",
"swr": "^2.2.2"
"react-router-dom": "^6.x",
"swr": "2.x"
},
"devDependencies": {
"@openmrs/esm-framework": "^5.4.0",
"i18next": "^19.0.0",
"react": "18.x",
"react-dates": "^21.8.0",
"react-dom": "18.x",
"react-i18next": "11.x",
"rxjs": "6.x",
"single-spa": "^6.x",
"swr": "^2.2.2"
"webpack": "^5.74.0"
}
}
3 changes: 1 addition & 2 deletions packages/esm-referrals-queue-app/src/declarations.d.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
declare module '@carbon/react';
declare module '*.css';
declare module '*.scss';
declare module '@carbon/react';
declare type SideNavProps = {};

type Referral = {
details: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
@use '@carbon/react';

.container {
margin-right: auto;
margin-left: auto;
Expand Down
21 changes: 8 additions & 13 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
{
"compilerOptions": {
"esModuleInterop": true,
"module": "esnext",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"jsx": "react",
"skipLibCheck": true,
"moduleResolution": "node",
"lib": [
"dom",
"es5",
"scripthost",
"es2015",
"es2015.promise",
"es2016.array.include",
"es2018",
"es2020"
"es2022"
],
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"noEmit": true,
"target": "esnext",
"paths": {
"@openmrs/*": ["./node_modules/@openmrs/*"],
"__mocks__": ["./__mocks__"],
"tools": ["./tools"],
}
},
"resolveJsonModule": true,
"skipLibCheck": true,
"target": "esnext",
}
}
Loading