Skip to content

Commit

Permalink
Feat/import export app
Browse files Browse the repository at this point in the history
Feat/import export app
  • Loading branch information
Michaelndula authored Jul 1, 2024
2 parents 4566ae0 + 4e4ff2a commit a9a3bc6
Show file tree
Hide file tree
Showing 39 changed files with 4,589 additions and 21,733 deletions.
20,381 changes: 0 additions & 20,381 deletions packages/esm-billing-app/yarn.lock

This file was deleted.

20 changes: 20 additions & 0 deletions packages/esm-import-export-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Service Queues

The `Service Queues` app is a frontend module that enables users to track a patient's progress as they move through a clinic. Users can see an overview of various clinic metrics such as:

- The number of active visits.
- The number of patients waiting for a particular service.
- The average number of minutes spent by patients waiting for a service.

The key component of the service queue app is the `Active Visits` table. It displays a tabular overview of the active visits ongoing in a facility and the wait time of patients. Users can add patients to the service queue by starting visits for them. They can also view information from the current active visits as well as the previous visit on each queue entry by clicking the table extension slot. Users can also change the priority and status of an entry in the queue from the UI, effectively moving a patient from one point in the queue to another. In order to indicate that a patient is currently attending service, click on the bell icon. In order to edit an entry, click the pencil icon.

Amend the following concepts in the configuration schema to get started using the module:
- `defaultPriorityConceptUuid` - concept UUID for `not urgent`.
- `defaultStatusConceptUuid` - concept UUID for `waiting`.
- `emergencyPriorityConcept` - concept UUID for `emergency`.

After configuring the concepts, add the services according to the facility setup by clicking the `Add new service` button.

In order to configure rooms that provide different services, click the `Add new room` button. To view patients attending service in different rooms, click the `Queue screen` button.

You should now be able to leverage the service queues module 🎉
3 changes: 3 additions & 0 deletions packages/esm-import-export-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;
46 changes: 46 additions & 0 deletions packages/esm-import-export-app/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "@sjthc/esm-import-export-app",
"version": "1.0.0",
"description": "Outpatient front-end module for the OpenMRS SPA",
"browser": "dist/sjthc-esm-service-queues-app.js",
"main": "src/index.ts",
"source": true,
"license": "MPL-2.0",
"homepage": "https://github.com/openmrs/openmrs-esm-patient-management#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' 'src/**/*.extension.tsx' 'src/**/*.workspace.tsx' 'src/index.ts' --config ../../tools/i18next-parser.config.js"
},
"browserslist": [
"extends browserslist-config-openmrs"
],
"keywords": [
"openmrs"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/openmrs/openmrs-esm-patient-management.git"
},
"bugs": {
"url": "https://github.com/openmrs/openmrs-esm-patient-management/issues"
},
"peerDependencies": {
"@openmrs/esm-framework": "5.x",
"react": "^18.1.0",
"react-i18next": "11.x",
"react-router-dom": "6.x",
"swr": "2.x"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React, { useMemo } from 'react';
import classNames from 'classnames';
import { BrowserRouter, useLocation } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { ConfigurableLink } from '@openmrs/esm-framework';

export interface DashboardLinkConfig {
name: string;
title: string;
}

function DashboardExtension({ dashboardLinkConfig }: { dashboardLinkConfig: DashboardLinkConfig }) {
const { t } = useTranslation();
const { name, title } = dashboardLinkConfig;
const location = useLocation();
const spaBasePath = `${window.spaBase}/home`;

const navLink = useMemo(() => {
const pathArray = location.pathname.split('/home');
const lastElement = pathArray[pathArray.length - 1];
return decodeURIComponent(lastElement);
}, [location.pathname]);

return (
<ConfigurableLink
className={classNames('cds--side-nav__link', {
'active-left-nav-link': navLink.match(name),
})}
to={`${spaBasePath}/${name}`}>
{t('importExport', 'Import Export App')}
</ConfigurableLink>
);
}

export const createDashboardLink = (dashboardLinkConfig: DashboardLinkConfig) => () => (
<BrowserRouter>
<DashboardExtension dashboardLinkConfig={dashboardLinkConfig} />
</BrowserRouter>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from "react";
import styles from "./styles/icons.scss"

const ImportExportIllustrationComponent = () => {
return (
<div className={styles.wrapper}>
<svg
className={styles.icon}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512">
<path
fill="#CEE6E5"
d="M128 64c0-35.3 28.7-64 64-64H352V128c0 17.7 14.3 32 32 32H512V448c0 35.3-28.7 64-64 64H192c-35.3 0-64-28.7-64-64V336H302.1l-39 39c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l80-80c9.4-9.4 9.4-24.6 0-33.9l-80-80c-9.4-9.4-24.6-9.4-33.9 0s-9.4 24.6 0 33.9l39 39H128V64zm0 224v48H24c-13.3 0-24-10.7-24-24s10.7-24 24-24H128zM512 128H384V0L512 128z"/>
</svg>
<svg
className={styles.exportIcon}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 576 512">
<path
fill="#7BBCB9"
d="M0 64C0 28.7 28.7 0 64 0H224V128c0 17.7 14.3 32 32 32H384V288H216c-13.3 0-24 10.7-24 24s10.7 24 24 24H384V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V64zM384 336V288H494.1l-39-39c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l80 80c9.4 9.4 9.4 24.6 0 33.9l-80 80c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l39-39H384zm0-208H256V0L384 128z"/>
</svg>
</div>

)
;
};


export default ImportExportIllustrationComponent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import styles from './styles/metric-card.scss';

const MetricCardComponent: React.FC<{stat: string | number, title: string}> = ({ stat, title }) =>{
return (
<div className={styles.container}>
<h1 className={styles.title}>{title}</h1>
<span className={styles.count}>{stat}</span>
</div>
);
}

export default MetricCardComponent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React, {Dispatch, SetStateAction} from "react";
import { Modal } from "@carbon/react";

const DeleteModalComponent:
React.FC<{ isOpen: boolean, setOpen: Dispatch<SetStateAction<boolean>> }> = ({isOpen, setOpen}) => {

const handleSubmit = () => {
setOpen(false);
}

return (
<Modal
open={isOpen}
onRequestSubmit={handleSubmit}
onRequestClose={() => setOpen(false)}
modalHeading="Are you sure you need to delete this backup?"
modalLabel="Delete"
primaryButtonText="Delete"
secondaryButtonText="Cancel"
>
</Modal>
);
};


export default DeleteModalComponent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React, {Dispatch, SetStateAction} from "react";
import {Form, FormGroup, Modal, TextInput} from "@carbon/react";
import styles from "../styles/modals.scss"

const DownloadModalComponent:
React.FC<{ isOpen: boolean, setOpen: Dispatch<SetStateAction<boolean>> }> = ({isOpen, setOpen}) => {

const handleSubmit = () => {
setOpen(false);
}

return (
<Modal
open={isOpen}
onRequestSubmit={handleSubmit}
onRequestClose={() => setOpen(false)}
modalHeading="Download this backup"
modalLabel="Download"
primaryButtonText="Download"
secondaryButtonText="Cancel"
>
<div className={styles.modalBody}>
<Form>
<FormGroup controlId="form">
<TextInput placeholder="File name" labelText="Insert File Name"/>
</FormGroup>
</Form>
</div>
</Modal>
);
};


export default DownloadModalComponent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React, {Dispatch, SetStateAction} from "react";
import { Modal } from "@carbon/react";

const NewBackupModal:
React.FC<{ isOpen: boolean, setOpen: Dispatch<SetStateAction<boolean>> }> = ({isOpen, setOpen}) => {

const handleSubmit = () => {
setOpen(false);
}

return (
<Modal
open={isOpen}
onRequestSubmit={handleSubmit}
onRequestClose={() => setOpen(false)}
modalHeading="Create a new backup?"
modalLabel="New Backup"
primaryButtonText="Create"
secondaryButtonText="Cancel"
>
</Modal>
);
};


export default NewBackupModal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React, {Dispatch, SetStateAction} from "react";
import { Modal } from "@carbon/react";

const RetryModal:
React.FC<{ isOpen: boolean, setOpen: Dispatch<SetStateAction<boolean>> }> = ({isOpen, setOpen}) => {

const handleSubmit = () => {
setOpen(false);
}

return (
<Modal
open={isOpen}
onRequestSubmit={handleSubmit}
onRequestClose={() => setOpen(false)}
modalHeading="Retry this backup?"
modalLabel="New Backup"
primaryButtonText="Retry"
secondaryButtonText="Cancel"
>
</Modal>
);
};


export default RetryModal;
22 changes: 22 additions & 0 deletions packages/esm-import-export-app/src/components/styles/icons.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.wrapper{
display: flex;
flex-direction: row;
position: relative;
width: fit-content;
height: fit-content;
margin-top: auto;
}

.icon{
width: 2.5rem;
height: 2.5rem;
}

.exportIcon{
@extend .icon;
position: absolute;
left: 70%;
bottom: 50%;
z-index: 0;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@use '@carbon/colors';
@use '@carbon/layout';
@use '@carbon/type';

.container {
border: 1px solid colors.$gray-20;
padding: layout.$spacing-05;
flex: 1;
}

.title {
@include type.type-style('heading-compact-02');
}

.count {
@include type.type-style('heading-05');
display: inline-block;
font-weight: 300;
margin-top: layout.$spacing-05;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

.modalBody{
display: flex;
flex-direction: column;
padding: 2rem;
}
1 change: 1 addition & 0 deletions packages/esm-import-export-app/src/config/config-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const configSchema = {};
Empty file.
6 changes: 6 additions & 0 deletions packages/esm-import-export-app/src/config/dashboard.meta.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const dashboardMeta = {
name: 'import-export',
path: 'import-export',
slot: 'import-export-dashboard-slot',
title: 'Import Export App',
};
4 changes: 4 additions & 0 deletions packages/esm-import-export-app/src/config/declarations.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
declare module '@carbon/react';
declare module '*.css';
declare module '*.scss';
declare type SideNavProps = {};
26 changes: 26 additions & 0 deletions packages/esm-import-export-app/src/data/dummy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export const dummyBackupTableData = [
{
id: "e022fa8d-1bb5-4d14-bef8-8637ec385d56",
date: new Date(2020, 2, 1).toLocaleString(),
user: "Dr Amina",
status: "completed"
},
{
id: "dc8cef03-5ef6-4dce-9bb5-347a8218431b",
date: new Date(2021, 2, 31).toLocaleString(),
user: "Dr. Amina",
status: "failed"
},
{
id: "fc96cd48-80d6-4ca3-8974-9856a179cd4b",
date: new Date(2024, 12, 1).toLocaleString(),
user: "Data Clerk",
status: "failed"
},
{
id: "3e7ed04c-a4fe-410e-a557-ed91f22d0e5a",
date: new Date(2022, 2, 1).toLocaleString(),
user: "Dr Khalif",
status: "completed"
},
]
Loading

0 comments on commit a9a3bc6

Please sign in to comment.