@openmrs/esm-bed-management-app 7.0.3-pre.94
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.
- package/.turbo/turbo-build.log +36 -0
- package/README.md +8 -0
- package/dist/130.js +2 -0
- package/dist/130.js.LICENSE.txt +3 -0
- package/dist/130.js.map +1 -0
- package/dist/148.js +1 -0
- package/dist/148.js.map +1 -0
- package/dist/169.js +1 -0
- package/dist/169.js.map +1 -0
- package/dist/271.js +1 -0
- package/dist/319.js +1 -0
- package/dist/460.js +1 -0
- package/dist/501.js +1 -0
- package/dist/501.js.map +1 -0
- package/dist/542.js +1 -0
- package/dist/542.js.map +1 -0
- package/dist/574.js +1 -0
- package/dist/591.js +2 -0
- package/dist/591.js.LICENSE.txt +32 -0
- package/dist/591.js.map +1 -0
- package/dist/644.js +1 -0
- package/dist/668.js +2 -0
- package/dist/668.js.LICENSE.txt +15 -0
- package/dist/668.js.map +1 -0
- package/dist/729.js +1 -0
- package/dist/729.js.map +1 -0
- package/dist/757.js +1 -0
- package/dist/766.js +2 -0
- package/dist/766.js.LICENSE.txt +35 -0
- package/dist/766.js.map +1 -0
- package/dist/784.js +2 -0
- package/dist/784.js.LICENSE.txt +9 -0
- package/dist/784.js.map +1 -0
- package/dist/788.js +1 -0
- package/dist/805.js +1 -0
- package/dist/805.js.map +1 -0
- package/dist/807.js +1 -0
- package/dist/833.js +1 -0
- package/dist/main.js +1 -0
- package/dist/main.js.map +1 -0
- package/dist/openmrs-esm-bed-management-app.js +1 -0
- package/dist/openmrs-esm-bed-management-app.js.buildmanifest.json +579 -0
- package/dist/openmrs-esm-bed-management-app.js.map +1 -0
- package/dist/routes.json +1 -0
- package/jest.config.js +3 -0
- package/package.json +55 -0
- package/src/__mocks__/react-i18next.js +50 -0
- package/src/admin-card-link.component.tsx +24 -0
- package/src/bed-administration/bed-administration-form.component.tsx +292 -0
- package/src/bed-administration/bed-administration-form.scss +0 -0
- package/src/bed-administration/bed-administration-table.component.tsx +258 -0
- package/src/bed-administration/bed-administration-table.scss +112 -0
- package/src/bed-administration/bed-administration-types.ts +20 -0
- package/src/bed-administration/bed-administration.resource.ts +57 -0
- package/src/bed-administration/edit-bed-form.component.tsx +89 -0
- package/src/bed-administration/new-bed-form.component.tsx +96 -0
- package/src/bed-tag/bed-tag-administration-table.component.tsx +192 -0
- package/src/bed-tag/bed-tags-admin-form.component.tsx +127 -0
- package/src/bed-tag/edit-tag-form.component.tsx +72 -0
- package/src/bed-tag/new-tag-form.component.tsx +76 -0
- package/src/bed-type/bed-type-admin-form.component.tsx +166 -0
- package/src/bed-type/bed-type-administration-table.component.tsx +198 -0
- package/src/bed-type/edit-bed-type.component.tsx +72 -0
- package/src/bed-type/new-bed-type-form.component.tsx +80 -0
- package/src/card-header/card-header.component.tsx +20 -0
- package/src/card-header/card-header.scss +45 -0
- package/src/config-schema.ts +13 -0
- package/src/declarations.d.ts +7 -0
- package/src/empty-state/empty-state.component.tsx +54 -0
- package/src/empty-state/empty-state.scss +62 -0
- package/src/header/header.component.tsx +42 -0
- package/src/header/header.scss +72 -0
- package/src/header/illustration.component.tsx +13 -0
- package/src/home.component.tsx +15 -0
- package/src/home.scss +5 -0
- package/src/index.ts +51 -0
- package/src/left-panel/left-panel.component.tsx +23 -0
- package/src/left-panel/left-panel.scss +42 -0
- package/src/left-panel-link.component.tsx +39 -0
- package/src/root.component.tsx +39 -0
- package/src/root.scss +11 -0
- package/src/routes.json +56 -0
- package/src/setup-tests.ts +1 -0
- package/src/summary/summary.component.tsx +60 -0
- package/src/summary/summary.resource.ts +232 -0
- package/src/summary/summary.scss +74 -0
- package/src/types.ts +173 -0
- package/src/ward-card/ward-card.component.tsx +34 -0
- package/src/ward-card/ward-card.scss +51 -0
- package/src/ward-with-beds/ward-with-beds.component.tsx +167 -0
- package/src/ward-with-beds/ward-with-beds.scss +27 -0
- package/translations/am.json +52 -0
- package/translations/ar.json +52 -0
- package/translations/en.json +52 -0
- package/translations/es.json +52 -0
- package/translations/fr.json +52 -0
- package/translations/he.json +52 -0
- package/translations/km.json +52 -0
- package/translations/zh.json +52 -0
- package/translations/zh_CN.json +52 -0
- package/tsconfig.json +5 -0
- package/webpack.config.js +1 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
@use '@carbon/layout';
|
|
2
|
+
@use '@carbon/type';
|
|
3
|
+
@use '@openmrs/esm-styleguide/src/vars' as *;
|
|
4
|
+
|
|
5
|
+
.desktopHeader,
|
|
6
|
+
.tabletHeader {
|
|
7
|
+
display: flex;
|
|
8
|
+
justify-content: space-between;
|
|
9
|
+
align-items: center;
|
|
10
|
+
padding: layout.$spacing-04 0 layout.$spacing-04 layout.$spacing-05;
|
|
11
|
+
background-color: $ui-background;
|
|
12
|
+
|
|
13
|
+
h4:after {
|
|
14
|
+
content: '';
|
|
15
|
+
display: block;
|
|
16
|
+
width: layout.$spacing-07;
|
|
17
|
+
padding-top: 0.188rem;
|
|
18
|
+
border-bottom: 0.375rem solid var(--brand-03);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.desktopHeader {
|
|
23
|
+
height: layout.$spacing-09;
|
|
24
|
+
h4 {
|
|
25
|
+
@include type.type-style('heading-compact-02');
|
|
26
|
+
color: $text-02;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.tabletHeader {
|
|
31
|
+
height: 4.5rem;
|
|
32
|
+
h4 {
|
|
33
|
+
@include type.type-style('heading-03');
|
|
34
|
+
color: $text-02;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Overriding styles for RTL support
|
|
39
|
+
html[dir='rtl'] {
|
|
40
|
+
.desktopHeader,
|
|
41
|
+
.tabletHeader {
|
|
42
|
+
text-align: right;
|
|
43
|
+
padding: layout.$spacing-04 layout.$spacing-05 layout.$spacing-04 0;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Type } from '@openmrs/esm-framework';
|
|
2
|
+
|
|
3
|
+
export const configSchema = {
|
|
4
|
+
admissionLocationTagName: {
|
|
5
|
+
_type: Type.String,
|
|
6
|
+
_description: 'Patients may only be admitted to inpatient care in a location with this tag',
|
|
7
|
+
_default: 'Admission Location',
|
|
8
|
+
},
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export interface BedManagementConfig {
|
|
12
|
+
admissionLocationTagName: string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Layer, Tile } from '@carbon/react';
|
|
3
|
+
import styles from './empty-state.scss';
|
|
4
|
+
|
|
5
|
+
type EmptyStateProps = {
|
|
6
|
+
msg: string;
|
|
7
|
+
helper: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const EmptyState: React.FC<EmptyStateProps> = ({ msg, helper }: EmptyStateProps) => {
|
|
11
|
+
return (
|
|
12
|
+
<Layer className={styles.layer}>
|
|
13
|
+
<Tile className={styles.tile}>
|
|
14
|
+
<svg width={64} height={64} viewBox="0 0 64 64">
|
|
15
|
+
<title>Empty data illustration</title>
|
|
16
|
+
<g fill="none" fillRule="evenodd">
|
|
17
|
+
<path
|
|
18
|
+
d="M38.133 13.186H21.947c-.768.001-1.39.623-1.39 1.391V50.55l-.186.057-3.97 1.216a.743.743 0 01-.927-.493L3.664 12.751a.742.742 0 01.492-.926l6.118-1.874 17.738-5.43 6.119-1.873a.741.741 0 01.926.492L38.076 13l.057.186z"
|
|
19
|
+
fill="#F4F4F4"
|
|
20
|
+
/>
|
|
21
|
+
<path
|
|
22
|
+
d="M41.664 13L38.026 1.117A1.576 1.576 0 0036.056.07l-8.601 2.633-17.737 5.43-8.603 2.634a1.578 1.578 0 00-1.046 1.97l12.436 40.616a1.58 1.58 0 001.969 1.046l5.897-1.805.185-.057v-.194l-.185.057-5.952 1.822a1.393 1.393 0 01-1.737-.923L.247 12.682a1.39 1.39 0 01.923-1.738L9.772 8.31 27.51 2.881 36.112.247a1.393 1.393 0 011.737.923L41.47 13l.057.186h.193l-.057-.185z"
|
|
23
|
+
fill="#8D8D8D"
|
|
24
|
+
/>
|
|
25
|
+
<path
|
|
26
|
+
d="M11.378 11.855a.836.836 0 01-.798-.59L9.385 7.361a.835.835 0 01.554-1.042l16.318-4.996a.836.836 0 011.042.554l1.195 3.902a.836.836 0 01-.554 1.043l-16.318 4.995a.831.831 0 01-.244.037z"
|
|
27
|
+
fill="#C6C6C6"
|
|
28
|
+
/>
|
|
29
|
+
<circle fill="#C6C6C6" cx={17.636} cy={2.314} r={1.855} />
|
|
30
|
+
<circle fill="#FFF" fillRule="nonzero" cx={17.636} cy={2.314} r={1.175} />
|
|
31
|
+
<path
|
|
32
|
+
d="M55.893 53.995H24.544a.79.79 0 01-.788-.789V15.644a.79.79 0 01.788-.788h31.349a.79.79 0 01.788.788v37.562a.79.79 0 01-.788.789z"
|
|
33
|
+
fill="#F4F4F4"
|
|
34
|
+
/>
|
|
35
|
+
<path
|
|
36
|
+
d="M41.47 13H21.948a1.579 1.579 0 00-1.576 1.577V52.4l.185-.057V14.577c.001-.768.623-1.39 1.391-1.39h19.581L41.471 13zm17.02 0H21.947a1.579 1.579 0 00-1.576 1.577v42.478c0 .87.706 1.576 1.576 1.577H58.49a1.579 1.579 0 001.576-1.577V14.577a1.579 1.579 0 00-1.576-1.576zm1.39 44.055c0 .768-.622 1.39-1.39 1.392H21.947c-.768-.001-1.39-.624-1.39-1.392V14.577c0-.768.622-1.39 1.39-1.39H58.49c.768 0 1.39.622 1.39 1.39v42.478z"
|
|
37
|
+
fill="#8D8D8D"
|
|
38
|
+
/>
|
|
39
|
+
<path
|
|
40
|
+
d="M48.751 17.082H31.686a.836.836 0 01-.835-.835v-4.081c0-.46.374-.834.835-.835H48.75c.461 0 .834.374.835.835v4.08c0 .462-.374.835-.835.836z"
|
|
41
|
+
fill="#C6C6C6"
|
|
42
|
+
/>
|
|
43
|
+
<circle fill="#C6C6C6" cx={40.218} cy={9.755} r={1.855} />
|
|
44
|
+
<circle fill="#FFF" fillRule="nonzero" cx={40.218} cy={9.755} r={1.13} />
|
|
45
|
+
</g>
|
|
46
|
+
</svg>
|
|
47
|
+
<p className={styles.content}>{msg}</p>
|
|
48
|
+
<p className={styles.explainer}>{helper}</p>
|
|
49
|
+
</Tile>
|
|
50
|
+
</Layer>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export default EmptyState;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
@use '@carbon/colors';
|
|
2
|
+
@use '@carbon/layout';
|
|
3
|
+
@use '@carbon/type';
|
|
4
|
+
|
|
5
|
+
.desktopHeading {
|
|
6
|
+
h4 {
|
|
7
|
+
@include type.type-style('heading-compact-02');
|
|
8
|
+
color: colors.$gray-70;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.tabletHeading {
|
|
13
|
+
h4 {
|
|
14
|
+
@include type.type-style('heading-03');
|
|
15
|
+
color: colors.$gray-70;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.desktopHeading,
|
|
20
|
+
.tabletHeading {
|
|
21
|
+
text-align: left;
|
|
22
|
+
text-transform: capitalize;
|
|
23
|
+
margin-bottom: layout.$spacing-05;
|
|
24
|
+
|
|
25
|
+
h4:after {
|
|
26
|
+
content: '';
|
|
27
|
+
display: block;
|
|
28
|
+
width: layout.$spacing-07;
|
|
29
|
+
padding-top: 0.188rem;
|
|
30
|
+
border-bottom: 0.375rem solid var(--brand-03);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.heading:after {
|
|
35
|
+
content: '';
|
|
36
|
+
display: block;
|
|
37
|
+
width: layout.$spacing-07;
|
|
38
|
+
padding-top: 0.188rem;
|
|
39
|
+
border-bottom: 0.375rem solid var(--brand-03);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.tile {
|
|
43
|
+
padding: layout.$spacing-07;
|
|
44
|
+
border: 1px solid colors.$gray-20;
|
|
45
|
+
margin: layout.$spacing-06;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.layer {
|
|
49
|
+
text-align: center;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.content {
|
|
53
|
+
@include type.type-style('heading-compact-02');
|
|
54
|
+
color: colors.$gray-70;
|
|
55
|
+
margin-top: layout.$spacing-05;
|
|
56
|
+
margin-bottom: layout.$spacing-03;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.explainer {
|
|
60
|
+
@include type.type-style('body-compact-01');
|
|
61
|
+
color: colors.$gray-70;
|
|
62
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ConfigurableLink, formatDate, useSession } from '@openmrs/esm-framework';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { Calendar, Location } from '@carbon/react/icons';
|
|
5
|
+
import Illustration from './illustration.component';
|
|
6
|
+
import styles from './header.scss';
|
|
7
|
+
|
|
8
|
+
type HeaderProps = {
|
|
9
|
+
route: string;
|
|
10
|
+
headerTitle?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const Header: React.FC<HeaderProps> = ({ route, headerTitle = 'Bed Management' }) => {
|
|
14
|
+
const { t } = useTranslation();
|
|
15
|
+
const userSession = useSession();
|
|
16
|
+
const userLocation = userSession?.sessionLocation?.display;
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<div className={styles.header}>
|
|
20
|
+
<div className={styles['left-justified-items']}>
|
|
21
|
+
<ConfigurableLink to={`${window.getOpenmrsSpaBase()}bed-management`}>
|
|
22
|
+
<Illustration />
|
|
23
|
+
</ConfigurableLink>
|
|
24
|
+
<div className={styles['page-labels']}>
|
|
25
|
+
<p>{t('headerTitle', headerTitle)}</p>
|
|
26
|
+
<p className={styles['page-name']}>{route}</p>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
<div className={styles['right-justified-items']}>
|
|
30
|
+
<div className={styles['date-and-location']}>
|
|
31
|
+
<Location size={16} />
|
|
32
|
+
<span className={styles.value}>{userLocation}</span>
|
|
33
|
+
<span className={styles.middot}>·</span>
|
|
34
|
+
<Calendar size={16} />
|
|
35
|
+
<span className={styles.value}>{formatDate(new Date(), { mode: 'standard' })}</span>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default Header;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
@use '@carbon/colors';
|
|
2
|
+
@use '@carbon/layout';
|
|
3
|
+
@use '@carbon/type';
|
|
4
|
+
|
|
5
|
+
.header {
|
|
6
|
+
@include type.type-style('body-compact-02');
|
|
7
|
+
color: colors.$gray-70;
|
|
8
|
+
height: layout.$spacing-12;
|
|
9
|
+
background-color: colors.$white-0;
|
|
10
|
+
display: flex;
|
|
11
|
+
padding-left: layout.$spacing-03;
|
|
12
|
+
justify-content: space-between;
|
|
13
|
+
border-bottom: 1px solid colors.$gray-20;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.left-justified-items {
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: row;
|
|
19
|
+
align-items: center;
|
|
20
|
+
cursor: pointer;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.right-justified-items {
|
|
24
|
+
@include type.type-style('body-compact-02');
|
|
25
|
+
color: colors.$gray-70;
|
|
26
|
+
margin: layout.$spacing-03;
|
|
27
|
+
padding-top: layout.$spacing-04;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.page-name {
|
|
31
|
+
white-space: nowrap;
|
|
32
|
+
@include type.type-style('heading-04');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.page-labels {
|
|
36
|
+
margin: layout.$spacing-05;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.middot {
|
|
40
|
+
margin: 0 layout.$spacing-03;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.date-and-location {
|
|
44
|
+
display: flex;
|
|
45
|
+
justify-content: flex-end;
|
|
46
|
+
align-items: center;
|
|
47
|
+
margin-right: layout.$spacing-05;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.value {
|
|
51
|
+
margin-left: layout.$spacing-02;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.middot {
|
|
55
|
+
margin: 0 layout.$spacing-03;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.view {
|
|
59
|
+
@include type.type-style('label-01');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
svg.iconOverrides {
|
|
63
|
+
width: 72 !important;
|
|
64
|
+
height: 72 !important;
|
|
65
|
+
fill: var(--brand-03);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.svgContainer svg {
|
|
69
|
+
width: 4.5rem;
|
|
70
|
+
height: 4.5rem;
|
|
71
|
+
fill: var(--brand-03);
|
|
72
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styles from './header.scss';
|
|
3
|
+
import { Stethoscope } from '@carbon/react/icons';
|
|
4
|
+
|
|
5
|
+
const Illustration: React.FC = () => {
|
|
6
|
+
return (
|
|
7
|
+
<div className={styles.svgContainer}>
|
|
8
|
+
<Stethoscope className={styles.iconOverrides} />
|
|
9
|
+
</div>
|
|
10
|
+
);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default Illustration;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import BedManagementSummary from './summary/summary.component';
|
|
3
|
+
import Header from './header/header.component';
|
|
4
|
+
import styles from './home.scss';
|
|
5
|
+
|
|
6
|
+
const Home: React.FC = () => {
|
|
7
|
+
return (
|
|
8
|
+
<section className={styles.section}>
|
|
9
|
+
<Header route="Summary" />
|
|
10
|
+
<BedManagementSummary />
|
|
11
|
+
</section>
|
|
12
|
+
);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default Home;
|
package/src/home.scss
ADDED
package/src/index.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { getAsyncLifecycle, defineConfigSchema, getSyncLifecycle } from '@openmrs/esm-framework';
|
|
2
|
+
import { configSchema } from './config-schema';
|
|
3
|
+
import { createLeftPanelLink } from './left-panel-link.component';
|
|
4
|
+
|
|
5
|
+
const moduleName = '@ugandaemr/esm-bed-management-app';
|
|
6
|
+
|
|
7
|
+
const options = {
|
|
8
|
+
featureName: 'bed-management',
|
|
9
|
+
moduleName,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const importTranslation = require.context('../translations', false, /.json$/, 'lazy');
|
|
13
|
+
|
|
14
|
+
export function startupApp() {
|
|
15
|
+
defineConfigSchema(moduleName, configSchema);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const root = getAsyncLifecycle(() => import('./root.component'), options);
|
|
19
|
+
|
|
20
|
+
export const adminCardLink = getAsyncLifecycle(() => import('./admin-card-link.component'), options);
|
|
21
|
+
|
|
22
|
+
export const summaryLeftPanelLink = getSyncLifecycle(
|
|
23
|
+
createLeftPanelLink({
|
|
24
|
+
name: 'bed-management',
|
|
25
|
+
title: 'Summary',
|
|
26
|
+
}),
|
|
27
|
+
options,
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
export const adminLeftPanelLink = getSyncLifecycle(
|
|
31
|
+
createLeftPanelLink({
|
|
32
|
+
name: 'administration',
|
|
33
|
+
title: 'Ward Allocation',
|
|
34
|
+
}),
|
|
35
|
+
options,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
export const bedTypeLeftPanelLink = getSyncLifecycle(
|
|
39
|
+
createLeftPanelLink({
|
|
40
|
+
name: 'bed-type',
|
|
41
|
+
title: 'Bed Type',
|
|
42
|
+
}),
|
|
43
|
+
options,
|
|
44
|
+
);
|
|
45
|
+
export const bedTagLeftPanelLink = getSyncLifecycle(
|
|
46
|
+
createLeftPanelLink({
|
|
47
|
+
name: 'bed-tag',
|
|
48
|
+
title: 'Bed Tag',
|
|
49
|
+
}),
|
|
50
|
+
options,
|
|
51
|
+
);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import { attach, detach, ExtensionSlot, isDesktop, useLayoutType } from '@openmrs/esm-framework';
|
|
3
|
+
import { SideNav } from '@carbon/react';
|
|
4
|
+
import styles from './left-panel.scss';
|
|
5
|
+
|
|
6
|
+
const LeftPanel: React.FC = () => {
|
|
7
|
+
const layout = useLayoutType();
|
|
8
|
+
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
attach('nav-menu-slot', 'bed-management-left-panel');
|
|
11
|
+
return () => detach('nav-menu-slot', 'bed-management-left-panel');
|
|
12
|
+
}, []);
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
isDesktop(layout) && (
|
|
16
|
+
<SideNav aria-label="Bed management left panel" className={styles.leftPanel} expanded>
|
|
17
|
+
<ExtensionSlot name="bed-management-left-panel-slot" />
|
|
18
|
+
</SideNav>
|
|
19
|
+
)
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default LeftPanel;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
@use '@carbon/colors';
|
|
2
|
+
@use '@carbon/layout';
|
|
3
|
+
@use '@carbon/type';
|
|
4
|
+
|
|
5
|
+
.leftPanel {
|
|
6
|
+
border-right: 1px solid colors.$gray-20;
|
|
7
|
+
padding-top: layout.$spacing-05;
|
|
8
|
+
|
|
9
|
+
// Left nav menu item
|
|
10
|
+
:global(.cds--side-nav__link) {
|
|
11
|
+
color: colors.$gray-70;
|
|
12
|
+
@include type.type-style('heading-compact-01');
|
|
13
|
+
|
|
14
|
+
&:focus,
|
|
15
|
+
&:hover {
|
|
16
|
+
background-color: colors.$gray-10-hover;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Active menu item
|
|
20
|
+
&:global(.active-left-nav-link) {
|
|
21
|
+
color: colors.$gray-100;
|
|
22
|
+
border-left: layout.$spacing-02 solid var(--brand-01);
|
|
23
|
+
outline: none;
|
|
24
|
+
padding: 0 layout.$spacing-04;
|
|
25
|
+
background-color: colors.$gray-20;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Desktop */
|
|
31
|
+
:global(.omrs-breakpoint-gt-tablet) {
|
|
32
|
+
:global(.cds--side-nav__link) {
|
|
33
|
+
height: layout.$spacing-07;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Tablet */
|
|
38
|
+
:global(.omrs-breakpoint-lt-desktop) {
|
|
39
|
+
:global(.cds--side-nav__link) {
|
|
40
|
+
height: layout.$spacing-09;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import last from 'lodash-es/last';
|
|
3
|
+
import { BrowserRouter, useLocation } from 'react-router-dom';
|
|
4
|
+
import { ConfigurableLink } from '@openmrs/esm-framework';
|
|
5
|
+
|
|
6
|
+
export interface LinkConfig {
|
|
7
|
+
name: string;
|
|
8
|
+
title: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function LinkExtension({ config }: { config: LinkConfig }) {
|
|
12
|
+
const { name, title } = config;
|
|
13
|
+
const location = useLocation();
|
|
14
|
+
|
|
15
|
+
let urlSegment = useMemo(() => decodeURIComponent(last(location.pathname.split('/'))), [location.pathname]);
|
|
16
|
+
|
|
17
|
+
const isUUID = (value) => {
|
|
18
|
+
const regex = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/;
|
|
19
|
+
return regex.test(value);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
if (isUUID(urlSegment)) {
|
|
23
|
+
urlSegment = 'summary';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<ConfigurableLink
|
|
28
|
+
to={`${window.getOpenmrsSpaBase()}bed-management${name && name !== 'bed-management' ? `/${name}` : ''}`}
|
|
29
|
+
className={`cds--side-nav__link ${name === urlSegment && 'active-left-nav-link'}`}>
|
|
30
|
+
{title}
|
|
31
|
+
</ConfigurableLink>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const createLeftPanelLink = (config: LinkConfig) => () => (
|
|
36
|
+
<BrowserRouter>
|
|
37
|
+
<LinkExtension config={config} />
|
|
38
|
+
</BrowserRouter>
|
|
39
|
+
);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import { BrowserRouter, Route, Routes } from 'react-router-dom';
|
|
3
|
+
import { setLeftNav, unsetLeftNav } from '@openmrs/esm-framework';
|
|
4
|
+
import Home from './home.component';
|
|
5
|
+
import LeftPanel from './left-panel/left-panel.component';
|
|
6
|
+
import WardWithBeds from './ward-with-beds/ward-with-beds.component';
|
|
7
|
+
import BedAdministrationTable from './bed-administration/bed-administration-table.component';
|
|
8
|
+
import BedTagAdministrationTable from './bed-tag/bed-tag-administration-table.component';
|
|
9
|
+
import BedTypeAdministrationTable from './bed-type/bed-type-administration-table.component';
|
|
10
|
+
import styles from './root.scss';
|
|
11
|
+
|
|
12
|
+
const Root: React.FC = () => {
|
|
13
|
+
const spaBasePath = window.spaBase;
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
setLeftNav({
|
|
17
|
+
name: 'bed-management-left-panel-slot',
|
|
18
|
+
basePath: spaBasePath,
|
|
19
|
+
});
|
|
20
|
+
return () => unsetLeftNav('bed-management-left-panel-slot');
|
|
21
|
+
}, [spaBasePath]);
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<BrowserRouter basename={`${window.getOpenmrsSpaBase()}bed-management`}>
|
|
25
|
+
<LeftPanel />
|
|
26
|
+
<main className={styles.container}>
|
|
27
|
+
<Routes>
|
|
28
|
+
<Route path="/" element={<Home />} />
|
|
29
|
+
<Route path="/location/:location" element={<WardWithBeds />} />
|
|
30
|
+
<Route path="/administration" element={<BedAdministrationTable />} />
|
|
31
|
+
<Route path="/bed-tag" element={<BedTagAdministrationTable />} />
|
|
32
|
+
<Route path="/bed-type" element={<BedTypeAdministrationTable />} />
|
|
33
|
+
</Routes>
|
|
34
|
+
</main>
|
|
35
|
+
</BrowserRouter>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default Root;
|
package/src/root.scss
ADDED
package/src/routes.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.openmrs.org/routes.schema.json",
|
|
3
|
+
"backendDependencies": {
|
|
4
|
+
"fhir2": ">=1.2",
|
|
5
|
+
"webservices.rest": "^2.24.0"
|
|
6
|
+
},
|
|
7
|
+
"pages": [
|
|
8
|
+
{
|
|
9
|
+
"component": "root",
|
|
10
|
+
"route": "bed-management"
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"extensions": [
|
|
14
|
+
{
|
|
15
|
+
"component": "adminCardLink",
|
|
16
|
+
"name": "bed-management-admin-card-link",
|
|
17
|
+
"slot": "system-admin-page-card-link-slot"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"component": "adminLeftPanelLink",
|
|
21
|
+
"name": "bed-administration-left-panel-link",
|
|
22
|
+
"slot": "bed-management-left-panel-slot"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"component": "bedTypeLeftPanelLink",
|
|
26
|
+
"name": "bed-type-left-panel-link",
|
|
27
|
+
"slot": "bed-management-left-panel-slot"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"component": "bedTagLeftPanelLink",
|
|
31
|
+
"name": "bed-tag-left-panel-link",
|
|
32
|
+
"slot": "bed-management-left-panel-slot"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"component": "summaryLeftPanelLink",
|
|
36
|
+
"name": "bed-management-home-dashboard-link",
|
|
37
|
+
"slot": "bed-management-left-panel-slot",
|
|
38
|
+
"order": 0
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"component": "bedAdmission",
|
|
42
|
+
"name": "bed-admission-dashboard",
|
|
43
|
+
"slot": "bed-admission-dashboard-slot"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "bed-admission-dashboard-link",
|
|
47
|
+
"component": "bedAdmissionDashboardLink",
|
|
48
|
+
"slot": "homepage-dashboard-slot",
|
|
49
|
+
"meta": {
|
|
50
|
+
"name": "bed-admission",
|
|
51
|
+
"slot": "bed-admission-dashboard-slot",
|
|
52
|
+
"title": "Bed-admission"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/extend-expect';
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { DataTableSkeleton } from '@carbon/react';
|
|
3
|
+
import { ArrowRight } from '@carbon/react/icons';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { ConfigurableLink, ErrorState } from '@openmrs/esm-framework';
|
|
6
|
+
import { useAdmissionLocations } from './summary.resource';
|
|
7
|
+
import EmptyState from '../empty-state/empty-state.component';
|
|
8
|
+
import WardCard from '../ward-card/ward-card.component';
|
|
9
|
+
import styles from './summary.scss';
|
|
10
|
+
|
|
11
|
+
const Summary: React.FC = () => {
|
|
12
|
+
const { t } = useTranslation();
|
|
13
|
+
const { data: admissionLocations, isLoading, error } = useAdmissionLocations();
|
|
14
|
+
|
|
15
|
+
if (isLoading) {
|
|
16
|
+
return (
|
|
17
|
+
<div className={styles.loader}>
|
|
18
|
+
<DataTableSkeleton role="progressbar" zebra />
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (admissionLocations?.length) {
|
|
24
|
+
return (
|
|
25
|
+
<div className={styles.cardContainer}>
|
|
26
|
+
{admissionLocations.map((admissionLocation) => {
|
|
27
|
+
const routeSegment = `${window.getOpenmrsSpaBase()}bed-management/location/${admissionLocation.ward.uuid}`;
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<WardCard
|
|
31
|
+
headerLabel={admissionLocation.ward.display}
|
|
32
|
+
label={t('beds', 'Beds')}
|
|
33
|
+
value={admissionLocation?.totalBeds}>
|
|
34
|
+
{admissionLocation?.totalBeds && (
|
|
35
|
+
<div className={styles.link}>
|
|
36
|
+
<ConfigurableLink className={styles.link} to={routeSegment}>
|
|
37
|
+
{t('viewBeds', 'View beds')}
|
|
38
|
+
</ConfigurableLink>
|
|
39
|
+
<ArrowRight size={16} />
|
|
40
|
+
</div>
|
|
41
|
+
)}
|
|
42
|
+
</WardCard>
|
|
43
|
+
);
|
|
44
|
+
})}
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!isLoading && admissionLocations?.length === 0 && !error) {
|
|
50
|
+
return <EmptyState msg="No data to display" helper={''} />;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (error) {
|
|
54
|
+
return (
|
|
55
|
+
<ErrorState headerTitle={t('errorFetchingbedInformation', 'Error fetching bed information')} error={error} />
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export default Summary;
|