@openmrs/esm-bed-management-app 7.1.1-pre.3735

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 +35 -0
  2. package/README.md +8 -0
  3. package/dist/130.js +2 -0
  4. package/dist/130.js.LICENSE.txt +3 -0
  5. package/dist/130.js.map +1 -0
  6. package/dist/169.js +1 -0
  7. package/dist/169.js.map +1 -0
  8. package/dist/391.js +2 -0
  9. package/dist/391.js.LICENSE.txt +15 -0
  10. package/dist/391.js.map +1 -0
  11. package/dist/501.js +1 -0
  12. package/dist/501.js.map +1 -0
  13. package/dist/542.js +1 -0
  14. package/dist/542.js.map +1 -0
  15. package/dist/574.js +1 -0
  16. package/dist/591.js +2 -0
  17. package/dist/591.js.LICENSE.txt +32 -0
  18. package/dist/591.js.map +1 -0
  19. package/dist/596.js +1 -0
  20. package/dist/596.js.map +1 -0
  21. package/dist/642.js +1 -0
  22. package/dist/642.js.map +1 -0
  23. package/dist/729.js +1 -0
  24. package/dist/729.js.map +1 -0
  25. package/dist/784.js +2 -0
  26. package/dist/784.js.LICENSE.txt +9 -0
  27. package/dist/784.js.map +1 -0
  28. package/dist/878.js +2 -0
  29. package/dist/878.js.LICENSE.txt +35 -0
  30. package/dist/878.js.map +1 -0
  31. package/dist/main.js +1 -0
  32. package/dist/main.js.map +1 -0
  33. package/dist/openmrs-esm-bed-management-app.js +1 -0
  34. package/dist/openmrs-esm-bed-management-app.js.buildmanifest.json +403 -0
  35. package/dist/openmrs-esm-bed-management-app.js.map +1 -0
  36. package/dist/routes.json +1 -0
  37. package/jest.config.js +3 -0
  38. package/package.json +55 -0
  39. package/src/__mocks__/react-i18next.js +50 -0
  40. package/src/admin-card-link.component.tsx +24 -0
  41. package/src/bed-administration/bed-administration-form.component.tsx +292 -0
  42. package/src/bed-administration/bed-administration-form.scss +0 -0
  43. package/src/bed-administration/bed-administration-table.component.tsx +258 -0
  44. package/src/bed-administration/bed-administration-table.scss +111 -0
  45. package/src/bed-administration/bed-administration-types.ts +20 -0
  46. package/src/bed-administration/bed-administration.resource.ts +57 -0
  47. package/src/bed-administration/edit-bed-form.component.tsx +89 -0
  48. package/src/bed-administration/new-bed-form.component.tsx +96 -0
  49. package/src/bed-tag/bed-tag-administration-table.component.tsx +192 -0
  50. package/src/bed-tag/bed-tags-admin-form.component.tsx +127 -0
  51. package/src/bed-tag/edit-tag-form.component.tsx +72 -0
  52. package/src/bed-tag/new-tag-form.component.tsx +76 -0
  53. package/src/bed-type/bed-type-admin-form.component.tsx +166 -0
  54. package/src/bed-type/bed-type-administration-table.component.tsx +198 -0
  55. package/src/bed-type/edit-bed-type.component.tsx +72 -0
  56. package/src/bed-type/new-bed-type-form.component.tsx +80 -0
  57. package/src/card-header/card-header.component.tsx +20 -0
  58. package/src/card-header/card-header.scss +45 -0
  59. package/src/config-schema.ts +13 -0
  60. package/src/declarations.d.ts +7 -0
  61. package/src/empty-state/empty-state.component.tsx +54 -0
  62. package/src/empty-state/empty-state.scss +62 -0
  63. package/src/header/header.component.tsx +42 -0
  64. package/src/header/header.scss +72 -0
  65. package/src/header/illustration.component.tsx +13 -0
  66. package/src/home.component.tsx +15 -0
  67. package/src/home.scss +5 -0
  68. package/src/index.ts +51 -0
  69. package/src/left-panel/left-panel.component.tsx +23 -0
  70. package/src/left-panel/left-panel.scss +41 -0
  71. package/src/left-panel-link.component.tsx +39 -0
  72. package/src/root.component.tsx +39 -0
  73. package/src/root.scss +11 -0
  74. package/src/routes.json +56 -0
  75. package/src/setup-tests.ts +1 -0
  76. package/src/summary/summary.component.tsx +60 -0
  77. package/src/summary/summary.resource.ts +232 -0
  78. package/src/summary/summary.scss +74 -0
  79. package/src/types.ts +173 -0
  80. package/src/ward-card/ward-card.component.tsx +34 -0
  81. package/src/ward-card/ward-card.scss +51 -0
  82. package/src/ward-with-beds/ward-with-beds.component.tsx +167 -0
  83. package/src/ward-with-beds/ward-with-beds.scss +27 -0
  84. package/translations/en.json +52 -0
  85. package/tsconfig.json +5 -0
  86. package/webpack.config.js +1 -0
@@ -0,0 +1,232 @@
1
+ import useSWR from 'swr';
2
+ import { type FetchResponse, openmrsFetch, useConfig } from '@openmrs/esm-framework';
3
+ import type {
4
+ AdmissionLocation,
5
+ Bed,
6
+ BedFetchResponse,
7
+ BedTagPayload,
8
+ BedTypePayload,
9
+ LocationFetchResponse,
10
+ MappedBedData,
11
+ Mutator,
12
+ } from '../types';
13
+ import { type BedManagementConfig } from '../config-schema';
14
+ import { useCallback, useEffect, useState } from 'react';
15
+
16
+ export const useLocationsWithAdmissionTag = () => {
17
+ const { admissionLocationTagName } = useConfig<BedManagementConfig>();
18
+ const locationsUrl = `/ws/rest/v1/location?tag=${admissionLocationTagName}&v=full`;
19
+
20
+ const { data, error, isLoading, isValidating, mutate } = useSWR<LocationFetchResponse, Error>(
21
+ admissionLocationTagName ? locationsUrl : null,
22
+ openmrsFetch,
23
+ );
24
+
25
+ return {
26
+ data: data?.data?.results ?? [],
27
+ error,
28
+ isLoading,
29
+ isValidating,
30
+ mutate,
31
+ };
32
+ };
33
+
34
+ export const useBedsForLocation = (locationUuid: string) => {
35
+ const apiUrl = `/ws/rest/v1/bed?locationUuid=${locationUuid}&v=full`;
36
+
37
+ const { data, isLoading, error } = useSWR<{ data: { results: Array<Bed> } }, Error>(
38
+ locationUuid ? apiUrl : null,
39
+ openmrsFetch,
40
+ );
41
+
42
+ const mappedBedData: MappedBedData = (data?.data?.results ?? []).map((bed) => ({
43
+ id: bed.id,
44
+ number: bed.bedNumber,
45
+ name: bed.bedType?.displayName,
46
+ description: bed.bedType?.description,
47
+ status: bed.status,
48
+ uuid: bed.uuid,
49
+ }));
50
+
51
+ return {
52
+ bedData: mappedBedData,
53
+ isLoading,
54
+ error,
55
+ };
56
+ };
57
+
58
+ export const useLocationName = (locationUuid: string) => {
59
+ const { data: allLocations, isLoading } = useLocationsWithAdmissionTag();
60
+
61
+ const location = allLocations.find((loc) => loc.uuid == locationUuid);
62
+ return {
63
+ name: location?.display ?? null,
64
+ isLoadingLocationData: isLoading,
65
+ };
66
+ };
67
+
68
+ export function useBedsGroupedByLocation() {
69
+ const { data: locations, isLoading: isLoadingLocations } = useLocationsWithAdmissionTag();
70
+ const [isLoading, setIsLoading] = useState(true);
71
+ const [isValidating, setIsValidating] = useState(true);
72
+ const [error, setError] = useState(null);
73
+ const [result, setResult] = useState([]);
74
+
75
+ useEffect(() => {
76
+ if (!isLoadingLocations && locations && isValidating) {
77
+ const fetchData = async () => {
78
+ const promises = locations.map(async (location) => {
79
+ const bedsUrl = `/ws/rest/v1/bed?locationUuid=${location.uuid}`;
80
+ const bedsFetchResult = await openmrsFetch<BedFetchResponse>(bedsUrl, {
81
+ method: 'GET',
82
+ });
83
+ if (bedsFetchResult.data.results.length) {
84
+ return bedsFetchResult.data.results.map((bed) => ({
85
+ ...bed,
86
+ location: location,
87
+ }));
88
+ }
89
+ return null;
90
+ });
91
+
92
+ const updatedWards = (await Promise.all(promises)).filter(Boolean);
93
+ setResult(updatedWards);
94
+ };
95
+ fetchData()
96
+ .catch((e) => {
97
+ setError(e);
98
+ })
99
+ .finally(() => {
100
+ setIsLoading(false);
101
+ setIsValidating(false);
102
+ });
103
+ }
104
+ }, [locations, isLoading]);
105
+
106
+ const mutate = useCallback(() => {
107
+ setIsValidating(true);
108
+ }, []);
109
+
110
+ return {
111
+ data: result,
112
+ error,
113
+ isLoading: isLoading || isLoadingLocations,
114
+ isValidating,
115
+ mutate,
116
+ };
117
+ }
118
+
119
+ export const useAdmissionLocations = () => {
120
+ const locationsUrl = `/ws/rest/v1/admissionLocation?v=full`;
121
+ const { data, error, isLoading, isValidating, mutate } = useSWR<
122
+ { data: { results: Array<AdmissionLocation> } },
123
+ Error
124
+ >(locationsUrl, openmrsFetch);
125
+
126
+ return {
127
+ data: data?.data?.results ?? [],
128
+ error,
129
+ isLoading,
130
+ isValidating,
131
+ mutate,
132
+ };
133
+ };
134
+
135
+ export const useAdmissionLocationBedLayout = (locationUuid: string) => {
136
+ const locationsUrl = `/ws/rest/v1/admissionLocation/${locationUuid}?v=full`;
137
+ const { data, error, isLoading, isValidating, mutate } = useSWR<{ data: AdmissionLocation }, Error>(
138
+ locationsUrl,
139
+ openmrsFetch,
140
+ );
141
+
142
+ return {
143
+ data: data?.data?.bedLayouts ?? [],
144
+ error,
145
+ isLoading,
146
+ isValidating,
147
+ mutate,
148
+ };
149
+ };
150
+
151
+ export const useBedType = () => {
152
+ const url = `/ws/rest/v1/bedtype/`;
153
+ const { data, error, isLoading, isValidating, mutate } = useSWR<{ data }, Error>(url, openmrsFetch);
154
+ const results = data?.data?.results ? data?.data?.results : [];
155
+ return {
156
+ bedTypeData: results,
157
+ isError: error,
158
+ loading: isLoading,
159
+ validate: isValidating,
160
+ mutate,
161
+ };
162
+ };
163
+
164
+ export const useBedTag = () => {
165
+ const url = `/ws/rest/v1/bedTag/`;
166
+ const { data, error, isLoading, isValidating, mutate } = useSWR<{ data }, Error>(url, openmrsFetch);
167
+ const results = data?.data?.results ? data?.data?.results : [];
168
+ return {
169
+ bedTypeData: results,
170
+ isError: error,
171
+ loading: isLoading,
172
+ validate: isValidating,
173
+ mutate,
174
+ };
175
+ };
176
+ interface BedType {
177
+ name: string;
178
+ displayName: string;
179
+ description: string;
180
+ }
181
+ interface BedTag {
182
+ name: string;
183
+ }
184
+ export async function saveBedType({
185
+ bedTypePayload,
186
+ }: {
187
+ bedTypePayload: BedTypePayload;
188
+ }): Promise<FetchResponse<BedType>> {
189
+ const response: FetchResponse = await openmrsFetch(`/ws/rest/v1/bedtype`, {
190
+ method: 'POST',
191
+ headers: { 'Content-Type': 'application/json' },
192
+ body: bedTypePayload,
193
+ });
194
+ return response;
195
+ }
196
+
197
+ export async function saveBedTag({ bedTagPayload }: { bedTagPayload: BedTagPayload }): Promise<FetchResponse<BedTag>> {
198
+ const response: FetchResponse = await openmrsFetch(`/ws/rest/v1/bedTag/`, {
199
+ method: 'POST',
200
+ headers: { 'Content-Type': 'application/json' },
201
+ body: bedTagPayload,
202
+ });
203
+ return response;
204
+ }
205
+ export async function editBedType({
206
+ bedTypePayload,
207
+ bedTypeId,
208
+ }: {
209
+ bedTypePayload: BedTypePayload;
210
+ bedTypeId: string;
211
+ }): Promise<FetchResponse<BedType>> {
212
+ const response: FetchResponse = await openmrsFetch(`/ws/rest/v1/bedtype/${bedTypeId}`, {
213
+ method: 'POST',
214
+ headers: { 'Content-Type': 'application/json' },
215
+ body: bedTypePayload,
216
+ });
217
+ return response;
218
+ }
219
+ export async function editBedTag({
220
+ bedTagPayload,
221
+ bedTagId,
222
+ }: {
223
+ bedTagPayload: BedTagPayload;
224
+ bedTagId: string;
225
+ }): Promise<FetchResponse<BedType>> {
226
+ const response: FetchResponse = await openmrsFetch(`/ws/rest/v1/bedTag/${bedTagId}`, {
227
+ method: 'POST',
228
+ headers: { 'Content-Type': 'application/json' },
229
+ body: bedTagPayload,
230
+ });
231
+ return response;
232
+ }
@@ -0,0 +1,74 @@
1
+ @use '@carbon/colors';
2
+ @use '@carbon/layout';
3
+
4
+ .cardContainer {
5
+ background-color: colors.$white-0;
6
+ display: grid;
7
+ grid-template-columns: repeat(3, minmax(0, 1fr));
8
+ justify-content: space-between;
9
+ padding: 1rem;
10
+ }
11
+
12
+ .buttonMain {
13
+ background-color: colors.$white-0;
14
+ color: colors.$teal-60;
15
+ cursor: text;
16
+ }
17
+
18
+ .sectionLoader {
19
+ text-align: center;
20
+ }
21
+
22
+ .buttonMain {
23
+ &:active,
24
+ &:focus,
25
+ &:hover {
26
+ color: colors.$teal-60 !important;
27
+ background-color: colors.$white-0 !important;
28
+ }
29
+ }
30
+
31
+ .inactiveMain {
32
+ margin-bottom: 4rem;
33
+ }
34
+
35
+ .buttonContainer {
36
+ display: flex;
37
+ }
38
+
39
+ .buttonItems {
40
+ flex: auto;
41
+ }
42
+
43
+ .pageHeaderContainer {
44
+ display: flex;
45
+ justify-content: space-between;
46
+ align-items: center;
47
+ padding: layout.$spacing-05;
48
+ background-color: #ededed;
49
+ }
50
+
51
+ .pageHeader {
52
+ text-overflow: ellipsis;
53
+ overflow: hidden;
54
+ white-space: nowrap;
55
+ font-size: 1.25rem;
56
+ font-weight: 400;
57
+ line-height: 1.4;
58
+ letter-spacing: 0;
59
+ }
60
+
61
+ .link {
62
+ text-decoration: none;
63
+ display: flex;
64
+ align-items: center;
65
+ color: colors.$blue-60;
66
+
67
+ svg {
68
+ margin-left: layout.$spacing-03;
69
+ }
70
+ }
71
+
72
+ .loader {
73
+ margin: 2rem;
74
+ }
package/src/types.ts ADDED
@@ -0,0 +1,173 @@
1
+ import type { KeyedMutator } from 'swr';
2
+
3
+ export type Tag = {
4
+ uuid: string;
5
+ display: string;
6
+ name: string;
7
+ description?: string;
8
+ retired: boolean;
9
+ links: Array<{
10
+ rel: string;
11
+ uri: string;
12
+ resourceAlias: string;
13
+ }>;
14
+ resourceVersion: string;
15
+ };
16
+
17
+ export type LocationFetchResponse = {
18
+ data: {
19
+ results: Array<Location>;
20
+ };
21
+ };
22
+
23
+ export type Location = {
24
+ uuid: string;
25
+ display: string;
26
+ name: string;
27
+ description: string | null;
28
+ address1: string | null;
29
+ address2: string | null;
30
+ cityVillage: string | null;
31
+ stateProvince: string | null;
32
+ country: string | null;
33
+ postalCode: string | null;
34
+ latitude: string | null;
35
+ longitude: string | null;
36
+ countyDistrict: string | null;
37
+ address3: string | null;
38
+ address4: string | null;
39
+ address5: string | null;
40
+ address6: string | null;
41
+ tags: Tag[];
42
+ parentLocation: Location;
43
+ childLocations: Location[];
44
+ retired: boolean;
45
+ auditInfo: {
46
+ creator: {
47
+ uuid: string;
48
+ display: string;
49
+ links: Array<{
50
+ rel: string;
51
+ uri: string;
52
+ resourceAlias: string;
53
+ }>;
54
+ };
55
+ dateCreated: string;
56
+ changedBy: null;
57
+ dateChanged: null;
58
+ };
59
+ address7: string | null;
60
+ address8: string | null;
61
+ address9: string | null;
62
+ address10: string | null;
63
+ address11: string | null;
64
+ address12: string | null;
65
+ address13: string | null;
66
+ address14: string | null;
67
+ address15: string | null;
68
+ links: Array<{
69
+ rel: string;
70
+ uri: string;
71
+ resourceAlias: string;
72
+ }>;
73
+ resourceVersion: string;
74
+ beds: Bed[];
75
+ };
76
+
77
+ export type BedFetchResponse = {
78
+ results: Array<Bed>;
79
+ };
80
+
81
+ export interface Bed {
82
+ id: number;
83
+ uuid: string;
84
+ bedNumber: string;
85
+ bedType?: BedType;
86
+ row: number;
87
+ column: number;
88
+ status: 'AVAILABLE' | 'OCCUPIED';
89
+ }
90
+
91
+ export interface BedWithLocation extends Bed {
92
+ location: {
93
+ display: string;
94
+ uuid: string;
95
+ };
96
+ }
97
+
98
+ export interface BedType {
99
+ uuid: string;
100
+ name: string;
101
+ displayName: string;
102
+ description: string;
103
+ resourceVersion: string;
104
+ }
105
+
106
+ export interface BedFormData extends BedWithLocation {
107
+ description: string;
108
+ }
109
+
110
+ export interface BedTypeData {
111
+ uuid: string;
112
+ name: string;
113
+ displayName: string;
114
+ description: string;
115
+ }
116
+
117
+ export interface BedTagData {
118
+ uuid: string;
119
+ name: string;
120
+ }
121
+
122
+ export interface BedPostPayload {
123
+ bedNumber: string;
124
+ bedType: string;
125
+ row: number;
126
+ column: number;
127
+ status: string;
128
+ locationUuid: string;
129
+ }
130
+
131
+ export interface BedTagPayload {
132
+ name: string;
133
+ }
134
+
135
+ export interface BedTypePayload {
136
+ name: string;
137
+ displayName: string;
138
+ description: string;
139
+ }
140
+
141
+ export type Mutator = KeyedMutator<{
142
+ data: {
143
+ results: Array<Location>;
144
+ };
145
+ }>;
146
+
147
+ export type AdmissionLocation = {
148
+ ward: {
149
+ uuid: string;
150
+ display: string;
151
+ name: string;
152
+ description: string;
153
+ };
154
+ totalBeds: number;
155
+ occupiedBeds: number;
156
+ bedLayouts: Array<BedDetails>;
157
+ };
158
+
159
+ export type MappedBedData = Array<{
160
+ id: number;
161
+ number: string;
162
+ name: string;
163
+ description: string;
164
+ status: string;
165
+ uuid: string;
166
+ }>;
167
+
168
+ export interface BedDetails extends Bed {
169
+ patient: null | {
170
+ uuid: string;
171
+ identifiers: Array<{ identifier: string }>;
172
+ };
173
+ }
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import { Layer, Tile } from '@carbon/react';
3
+ import styles from './ward-card.scss';
4
+
5
+ interface WardCardProps {
6
+ label: string;
7
+ value: number | string;
8
+ headerLabel: string;
9
+ children?: React.ReactNode;
10
+ service?: string;
11
+ serviceUuid?: string;
12
+ locationUuid?: string;
13
+ }
14
+
15
+ const WardCard: React.FC<WardCardProps> = ({ children, headerLabel, label, value }) => {
16
+ return (
17
+ <Layer className={`${children && styles.cardWithChildren} ${styles.container}`}>
18
+ <Tile className={styles.tileContainer}>
19
+ <div className={styles.tileHeader}>
20
+ <div className={styles.headerLabelContainer}>
21
+ <label className={styles.headerLabel}>{headerLabel}</label>
22
+ </div>
23
+ {children}
24
+ </div>
25
+ <div>
26
+ <label className={styles.totalsLabel}>{label}</label>
27
+ <p className={styles.totalsValue}>{value}</p>
28
+ </div>
29
+ </Tile>
30
+ </Layer>
31
+ );
32
+ };
33
+
34
+ export default WardCard;
@@ -0,0 +1,51 @@
1
+ @use '@carbon/colors';
2
+ @use '@carbon/layout';
3
+ @use '@carbon/type';
4
+
5
+ .container {
6
+ flex-grow: 1;
7
+ }
8
+
9
+ .tileContainer {
10
+ border: 1px solid colors.$gray-20;
11
+ height: 7.875rem;
12
+ padding: layout.$spacing-05;
13
+ margin: layout.$spacing-03 layout.$spacing-03;
14
+ }
15
+
16
+ .tileHeader {
17
+ display: flex;
18
+ justify-content: space-between;
19
+ align-items: baseline;
20
+ margin-bottom: layout.$spacing-03;
21
+ }
22
+
23
+ .headerLabel {
24
+ @include type.type-style('heading-compact-01');
25
+ color: colors.$gray-70;
26
+ }
27
+
28
+ .totalsLabel {
29
+ @include type.type-style('label-01');
30
+ color: colors.$gray-70;
31
+ }
32
+
33
+ .totalsValue {
34
+ @include type.type-style('heading-04');
35
+ color: colors.$gray-100;
36
+ }
37
+
38
+ .headerLabelContainer {
39
+ margin-bottom: 1rem;
40
+ }
41
+
42
+ .link {
43
+ text-decoration: none;
44
+ display: flex;
45
+ align-items: center;
46
+ color: colors.$blue-60;
47
+
48
+ svg {
49
+ margin-left: layout.$spacing-03;
50
+ }
51
+ }