@thrustdevs/esm-medical-supply-orders-app 1.0.2-pre.6

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 (109) hide show
  1. package/.turbo/turbo-build.log +40 -0
  2. package/README.md +7 -0
  3. package/dist/144.js +2 -0
  4. package/dist/144.js.LICENSE.txt +19 -0
  5. package/dist/144.js.map +1 -0
  6. package/dist/197.js +1 -0
  7. package/dist/205.js +1 -0
  8. package/dist/205.js.map +1 -0
  9. package/dist/216.js +2 -0
  10. package/dist/216.js.LICENSE.txt +9 -0
  11. package/dist/216.js.map +1 -0
  12. package/dist/258.js +1 -0
  13. package/dist/258.js.map +1 -0
  14. package/dist/300.js +1 -0
  15. package/dist/335.js +1 -0
  16. package/dist/349.js +1 -0
  17. package/dist/349.js.map +1 -0
  18. package/dist/373.js +2 -0
  19. package/dist/373.js.LICENSE.txt +5 -0
  20. package/dist/373.js.map +1 -0
  21. package/dist/41.js +2 -0
  22. package/dist/41.js.LICENSE.txt +9 -0
  23. package/dist/41.js.map +1 -0
  24. package/dist/470.js +1 -0
  25. package/dist/470.js.map +1 -0
  26. package/dist/479.js +1 -0
  27. package/dist/479.js.map +1 -0
  28. package/dist/480.js +1 -0
  29. package/dist/495.js +1 -0
  30. package/dist/495.js.map +1 -0
  31. package/dist/506.js +2 -0
  32. package/dist/506.js.LICENSE.txt +39 -0
  33. package/dist/506.js.map +1 -0
  34. package/dist/530.js +1 -0
  35. package/dist/530.js.map +1 -0
  36. package/dist/537.js +1 -0
  37. package/dist/537.js.map +1 -0
  38. package/dist/547.js +2 -0
  39. package/dist/547.js.LICENSE.txt +5 -0
  40. package/dist/547.js.map +1 -0
  41. package/dist/55.js +1 -0
  42. package/dist/652.js +1 -0
  43. package/dist/706.js +2 -0
  44. package/dist/706.js.LICENSE.txt +29 -0
  45. package/dist/706.js.map +1 -0
  46. package/dist/716.js +1 -0
  47. package/dist/716.js.map +1 -0
  48. package/dist/746.js +2 -0
  49. package/dist/746.js.LICENSE.txt +5 -0
  50. package/dist/746.js.map +1 -0
  51. package/dist/876.js +1 -0
  52. package/dist/876.js.map +1 -0
  53. package/dist/883.js +1 -0
  54. package/dist/883.js.map +1 -0
  55. package/dist/89.js +1 -0
  56. package/dist/89.js.map +1 -0
  57. package/dist/913.js +2 -0
  58. package/dist/913.js.LICENSE.txt +32 -0
  59. package/dist/913.js.map +1 -0
  60. package/dist/928.js +2 -0
  61. package/dist/928.js.LICENSE.txt +5 -0
  62. package/dist/928.js.map +1 -0
  63. package/dist/99.js +2 -0
  64. package/dist/99.js.LICENSE.txt +5 -0
  65. package/dist/99.js.map +1 -0
  66. package/dist/994.js +1 -0
  67. package/dist/994.js.map +1 -0
  68. package/dist/kenyaemr-esm-medical-supply-orders-app.js +1 -0
  69. package/dist/kenyaemr-esm-medical-supply-orders-app.js.buildmanifest.json +930 -0
  70. package/dist/kenyaemr-esm-medical-supply-orders-app.js.map +1 -0
  71. package/dist/main.js +2 -0
  72. package/dist/main.js.LICENSE.txt +15 -0
  73. package/dist/main.js.map +1 -0
  74. package/dist/routes.json +1 -0
  75. package/jest.config.js +8 -0
  76. package/package.json +58 -0
  77. package/src/config-schema.ts +39 -0
  78. package/src/constants.ts +1 -0
  79. package/src/declarations.d.ts +6 -0
  80. package/src/form/add-medical-supply-order/api.ts +215 -0
  81. package/src/form/add-medical-supply-order/medical-supply-order/add-medical-supply-order.scss +44 -0
  82. package/src/form/add-medical-supply-order/medical-supply-order/add-medical-supply-order.workspace.tsx +67 -0
  83. package/src/form/add-medical-supply-order/medical-supply-order/medical-supply-form.component.tsx +304 -0
  84. package/src/form/add-medical-supply-order/medical-supply-order/medical-supply-form.scss +80 -0
  85. package/src/form/add-medical-supply-order/medical-supply-order/medical-supply-order.resource.ts +32 -0
  86. package/src/form/add-medical-supply-order/medical-supply-order/medical-supply-order.ts +22 -0
  87. package/src/form/add-medical-supply-order/medical-supply-order/medical-supply-type-search.scss +115 -0
  88. package/src/form/add-medical-supply-order/medical-supply-order/medical-supply-type-search.tsx +253 -0
  89. package/src/form/add-medical-supply-order/medical-supply-order-basket-panel/medical-supply-icon.component.tsx +33 -0
  90. package/src/form/add-medical-supply-order/medical-supply-order-basket-panel/medical-supply-order-basket-item-tile.component.tsx +100 -0
  91. package/src/form/add-medical-supply-order/medical-supply-order-basket-panel/medical-supply-order-basket-item-tile.scss +72 -0
  92. package/src/form/add-medical-supply-order/medical-supply-order-basket-panel/medical-supply-order-basket-panel.extension.tsx +196 -0
  93. package/src/form/add-medical-supply-order/medical-supply-order-basket-panel/medical-supply-order-basket-panel.scss +74 -0
  94. package/src/form/add-medical-supply-order/medical-supply-order-basket-panel/medical-supply-order-basket.scss +55 -0
  95. package/src/hooks/useMedicalSupplyTypes.ts +33 -0
  96. package/src/index.ts +21 -0
  97. package/src/root.component.tsx +21 -0
  98. package/src/root.scss +15 -0
  99. package/src/routes.json +31 -0
  100. package/src/setup-tests.ts +1 -0
  101. package/src/types/index.ts +48 -0
  102. package/translations/am.json +24 -0
  103. package/translations/en.json +17 -0
  104. package/translations/es.json +24 -0
  105. package/translations/fr.json +24 -0
  106. package/translations/he.json +24 -0
  107. package/translations/km.json +24 -0
  108. package/tsconfig.json +5 -0
  109. package/webpack.config.js +1 -0
package/jest.config.js ADDED
@@ -0,0 +1,8 @@
1
+ const rootConfig = require('../../jest.config.js');
2
+
3
+ const packageConfig = {
4
+ ...rootConfig,
5
+ collectCoverage: false,
6
+ };
7
+
8
+ module.exports = packageConfig;
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@thrustdevs/esm-medical-supply-orders-app",
3
+ "version": "1.0.2-pre.6",
4
+ "description": "Medical Supply Orders app for KenyaEMR",
5
+ "browser": "dist/kenyaemr-esm-medical-supply-orders-app.js",
6
+ "main": "src/index.ts",
7
+ "source": true,
8
+ "license": "MPL-2.0",
9
+ "homepage": "https://github.com/palladiumkenya/kenyaemr-esm-orders#readme",
10
+ "scripts": {
11
+ "start": "openmrs develop",
12
+ "serve": "webpack serve --mode=development",
13
+ "debug": "npm run serve",
14
+ "build": "webpack --mode production",
15
+ "analyze": "webpack --mode=production --env.analyze=true",
16
+ "lint": "eslint src --ext ts,tsx --ignore-pattern '**/*.test.ts' --ignore-pattern '**/*.test.tsx' --ignore-pattern '**/__tests__/**'",
17
+ "typescript": "tsc",
18
+ "extract-translations": "i18next 'src/**/*.component.tsx' 'src/index.ts' --config ../../tools/i18next-parser.config.js",
19
+ "test": "cross-env TZ=UTC jest --config jest.config.js --verbose false --passWithNoTests",
20
+ "test:watch": "cross-env TZ=UTC jest --watch --config jest.config.js",
21
+ "coverage": "yarn test --coverage"
22
+ },
23
+ "browserslist": [
24
+ "extends browserslist-config-openmrs"
25
+ ],
26
+ "keywords": [
27
+ "openmrs"
28
+ ],
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/palladiumkenya/kenyaemr-esm-orders#readme"
35
+ },
36
+ "bugs": {
37
+ "url": "git+https://github.com/palladiumkenya/kenyaemr-esm-orders#readme"
38
+ },
39
+ "dependencies": {
40
+ "fuzzy": "^0.1.3",
41
+ "lodash-es": "^4.17.15",
42
+ "react-to-print": "^2.14.13"
43
+ },
44
+ "peerDependencies": {
45
+ "@carbon/react": "^1.x",
46
+ "@openmrs/esm-framework": "6.x",
47
+ "@openmrs/esm-patient-common-lib": "9.x",
48
+ "react": "^18.1.0",
49
+ "react-i18next": "11.x",
50
+ "react-router-dom": "6.x",
51
+ "swr": "2.x"
52
+ },
53
+ "devDependencies": {
54
+ "@openmrs/esm-patient-common-lib": "^9.2.2",
55
+ "webpack": "^5.74.0"
56
+ },
57
+ "stableVersion": "1.0.1"
58
+ }
@@ -0,0 +1,39 @@
1
+ import { Type } from '@openmrs/esm-framework';
2
+
3
+ export const configSchema = {
4
+ medicalSupplyQuantityUnitsConceptSetUuid: {
5
+ _type: Type.String,
6
+ _description: 'Medical Supply Quantity Units Concept SET UUID',
7
+ _default: '162402AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
8
+ },
9
+ orders: {
10
+ medicalSupplyOrderTypeUuid: {
11
+ _type: Type.UUID,
12
+ _description: "UUID for the 'Medical Supply' order type",
13
+ _default: 'dab3ab30-2feb-48ec-b4af-8332a0831b49',
14
+ },
15
+ medicalSupplyOrderableConcepts: {
16
+ _type: Type.Array,
17
+ _description:
18
+ 'UUIDs of concepts that represent orderable medical supply. If an empty array `[]` is provided, every concept with class `Medical supply` will be considered orderable.',
19
+ _elements: {
20
+ _type: Type.UUID,
21
+ },
22
+ _default: [],
23
+ },
24
+ },
25
+ };
26
+
27
+ interface OrderReason {
28
+ medicalSupplyUuid: string;
29
+ required: boolean;
30
+ orderReasons: Array<string>;
31
+ }
32
+ export type MedicalSupplyConfig = {
33
+ medicalSupplyQuantityUnitsConceptSetUuid: string;
34
+ orders: {
35
+ medicalSupplyOrderableConcepts: Array<string>;
36
+ medicalSupplyOrderTypeUuid: string;
37
+ };
38
+ medicalSupplyWithOrderReasons: Array<OrderReason>;
39
+ };
@@ -0,0 +1 @@
1
+ export const moduleName = '@openmrs/esm-medical-supply-app';
@@ -0,0 +1,6 @@
1
+ declare module '@carbon/react';
2
+ declare module '*.css';
3
+ declare module '*.scss';
4
+ declare module '*.png';
5
+
6
+ declare type SideNavProps = object;
@@ -0,0 +1,215 @@
1
+ import useSWR from 'swr';
2
+ import { type FetchResponse, openmrsFetch, restBaseUrl, showSnackbar } from '@openmrs/esm-framework';
3
+ import type { OrderPost } from '@openmrs/esm-patient-common-lib';
4
+ import useSWRImmutable from 'swr/immutable';
5
+ import { type MedicalSupplyOrderBasketItem } from '../../types';
6
+
7
+ export const careSettingUuid = '6f0c9a92-6f24-11e3-af88-005056821db0';
8
+
9
+ export function useOrderReasons(conceptUuids: Array<string>) {
10
+ const shouldFetch = conceptUuids && conceptUuids.length > 0;
11
+ const url = shouldFetch ? getConceptReferenceUrls(conceptUuids) : null;
12
+ const { data, error, isLoading } = useSWRImmutable<FetchResponse<ConceptResponse>, Error>(
13
+ shouldFetch ? `${restBaseUrl}/${url[0]}` : null,
14
+ openmrsFetch,
15
+ );
16
+
17
+ const ob = data?.data;
18
+ const orderReasons = ob
19
+ ? Object.entries(ob).map(([key, value]) => ({
20
+ uuid: value.uuid,
21
+ display: value.display,
22
+ }))
23
+ : [];
24
+
25
+ if (error) {
26
+ showSnackbar({
27
+ title: error.name,
28
+ subtitle: error.message,
29
+ kind: 'error',
30
+ });
31
+ }
32
+
33
+ return { orderReasons: orderReasons, isLoading };
34
+ }
35
+
36
+ export interface MedicalSupplyOrderPost extends OrderPost {
37
+ quantity?: number;
38
+ quantityUnits?: string;
39
+ }
40
+
41
+ export function prepMedicalSupplyOrderPostData(
42
+ order: MedicalSupplyOrderBasketItem,
43
+ patientUuid: string,
44
+ encounterUuid: string,
45
+ ): MedicalSupplyOrderPost {
46
+ let payload = {};
47
+ if (order.action === 'NEW' || order.action === 'RENEW') {
48
+ payload = {
49
+ action: 'NEW',
50
+ type: 'medicalsupplyorder',
51
+ patient: patientUuid,
52
+ careSetting: careSettingUuid,
53
+ orderer: order.orderer,
54
+ encounter: encounterUuid,
55
+ concept: order.testType.conceptUuid,
56
+ instructions: order.instructions,
57
+ urgency: order.urgency,
58
+ quantity: order.quantity,
59
+ quantityUnits: order.quantityUnits,
60
+ brandName: order.brandName,
61
+ };
62
+ return payload;
63
+ } else if (order.action === 'REVISE') {
64
+ payload = {
65
+ action: 'REVISE',
66
+ type: 'medicalsupplyorder',
67
+ patient: patientUuid,
68
+ careSetting: order.careSetting,
69
+ orderer: order.orderer,
70
+ encounter: encounterUuid,
71
+ concept: order.testType.conceptUuid,
72
+ instructions: order.instructions,
73
+ urgency: order.urgency,
74
+ quantity: order.quantity,
75
+ quantityUnits: order.quantityUnits,
76
+ brandName: order.brandName,
77
+ previousOrder: order.previousOrder,
78
+ };
79
+ return payload;
80
+ } else if (order.action === 'DISCONTINUE') {
81
+ payload = {
82
+ action: 'DISCONTINUE',
83
+ type: 'medicalsupplyorder',
84
+ patient: patientUuid,
85
+ careSetting: order.careSetting,
86
+ orderer: order.orderer,
87
+ encounter: encounterUuid,
88
+ concept: order.testType.conceptUuid,
89
+ previousOrder: order.previousOrder,
90
+ };
91
+ return payload;
92
+ } else {
93
+ throw new Error(`Unknown order action: ${order.action}.`);
94
+ }
95
+ }
96
+ const chunkSize = 10;
97
+ export function getConceptReferenceUrls(conceptUuids: Array<string>) {
98
+ const accumulator = [];
99
+ for (let i = 0; i < conceptUuids.length; i += chunkSize) {
100
+ accumulator.push(conceptUuids.slice(i, i + chunkSize));
101
+ }
102
+
103
+ return accumulator.map((partition) => `conceptreferences?references=${partition.join(',')}&v=custom:(uuid,display)`);
104
+ }
105
+
106
+ export type PostDataPrepMedicalSupplyOrderFunction = (
107
+ order: MedicalSupplyOrderBasketItem,
108
+ patientUuid: string,
109
+ encounterUuid: string,
110
+ ) => OrderPost;
111
+
112
+ export interface ConceptAnswers {
113
+ display: string;
114
+ uuid: string;
115
+ }
116
+ export interface ConceptResponse {
117
+ uuid: string;
118
+ display: string;
119
+ datatype: {
120
+ uuid: string;
121
+ display: string;
122
+ };
123
+ answers: Array<ConceptAnswers>;
124
+ setMembers: Array<ConceptAnswers>;
125
+ }
126
+
127
+ export interface OpenmrsObject {
128
+ uuid: string;
129
+ }
130
+
131
+ export type BaseOpenmrsObject = OpenmrsObject;
132
+
133
+ export interface SessionPriviledge {
134
+ uuid: string;
135
+ name: string;
136
+ }
137
+
138
+ export interface Person {
139
+ uuid: string;
140
+ display: string;
141
+ }
142
+
143
+ export interface Role {
144
+ role: string;
145
+ display: string;
146
+ }
147
+ export interface User {
148
+ uuid: string;
149
+ display: string;
150
+ givenName: string;
151
+ familyName: string;
152
+ firstName: string;
153
+ lastName: string;
154
+ person?: Person;
155
+ roles?: Role[];
156
+ privileges: SessionPriviledge[];
157
+ }
158
+ export interface Auditable extends OpenmrsObject {
159
+ creator: User;
160
+ dateCreated: Date;
161
+ changedBy: User;
162
+ dateChanged: Date;
163
+ }
164
+ export interface Retireable extends OpenmrsObject {
165
+ retired: boolean;
166
+ dateRetired: Date;
167
+ retiredBy: User;
168
+ retireReason: string;
169
+ }
170
+
171
+ export interface ConceptName extends BaseOpenmrsObject {
172
+ conceptNameId: number;
173
+ concept: Concept;
174
+ name: string;
175
+ localePreferred: boolean;
176
+ short: boolean;
177
+ preferred: boolean;
178
+ indexTerm: boolean;
179
+ synonym: boolean;
180
+ fullySpecifiedName: boolean;
181
+ }
182
+ export interface Concept extends BaseOpenmrsObject, Auditable, Retireable {
183
+ conceptId: number;
184
+ display: string;
185
+ set: boolean;
186
+ version: string;
187
+ names: ConceptName[];
188
+ name: ConceptName;
189
+ numeric: boolean;
190
+ complex: boolean;
191
+ shortNames: ConceptName[];
192
+ indexTerms: ConceptName[];
193
+ synonyms: ConceptName[];
194
+ setMembers: Concept[];
195
+ possibleValues: Concept[];
196
+ preferredName: ConceptName;
197
+ shortName: ConceptName;
198
+ fullySpecifiedName: ConceptName;
199
+ answers: Concept[];
200
+ }
201
+
202
+ export function useConceptById(id: string) {
203
+ const apiUrl = `ws/rest/v1/concept/${id}`;
204
+ const { data, error, isLoading } = useSWR<
205
+ {
206
+ data: Concept;
207
+ },
208
+ Error
209
+ >(apiUrl, openmrsFetch);
210
+ return {
211
+ items: data?.data || <Concept>{},
212
+ isLoading,
213
+ isError: error,
214
+ };
215
+ }
@@ -0,0 +1,44 @@
1
+ @use '@carbon/styles/scss/type';
2
+ @use '@carbon/styles/scss/spacing';
3
+ @use '@openmrs/esm-styleguide/src/vars' as vars;
4
+
5
+ .container {
6
+ position: relative;
7
+ min-height: var(--desktop-workspace-window-height);
8
+ background-color: white;
9
+ display: flex;
10
+ flex-direction: column;
11
+ }
12
+
13
+ .patientHeader {
14
+ padding: spacing.$spacing-03 spacing.$spacing-05 spacing.$spacing-06;
15
+ background-color: vars.$ui-01;
16
+
17
+ span:first-of-type {
18
+ margin-right: spacing.$spacing-03;
19
+ }
20
+
21
+ .text02 {
22
+ color: vars.$text-02;
23
+ }
24
+ }
25
+
26
+ .backButton {
27
+ padding: spacing.$spacing-03;
28
+
29
+ button {
30
+ display: flex;
31
+ padding-left: 0 !important;
32
+ margin: 0 spacing.$spacing-05;
33
+
34
+ svg {
35
+ order: 1;
36
+ margin-right: spacing.$spacing-03;
37
+ margin-left: 0 !important;
38
+ }
39
+
40
+ span {
41
+ order: 2;
42
+ }
43
+ }
44
+ }
@@ -0,0 +1,67 @@
1
+ import React, { useCallback, useState } from 'react';
2
+ import classNames from 'classnames';
3
+ import capitalize from 'lodash-es/capitalize';
4
+ import { useTranslation } from 'react-i18next';
5
+ import { Button } from '@carbon/react';
6
+ import { ArrowLeft } from '@carbon/react/icons';
7
+ import { age, formatDate, parseDate, useLayoutType, usePatient } from '@openmrs/esm-framework';
8
+ import { type DefaultPatientWorkspaceProps, launchPatientWorkspace } from '@openmrs/esm-patient-common-lib';
9
+ import { MedicalSupplyTypeSearch } from './medical-supply-type-search';
10
+ import { MedicalSupplyOrderForm } from './medical-supply-form.component';
11
+ import styles from './add-medical-supply-order.scss';
12
+ import { type MedicalSupplyOrderBasketItem } from '../../../types';
13
+
14
+ export interface AddMedicalSupplyOrderWorkspaceAdditionalProps {
15
+ order?: MedicalSupplyOrderBasketItem;
16
+ }
17
+
18
+ export interface AddMedicalSupplyOrderWorkspace
19
+ extends DefaultPatientWorkspaceProps,
20
+ AddMedicalSupplyOrderWorkspaceAdditionalProps {}
21
+
22
+ export default function AddMedicalSupplyOrderWorkspace({
23
+ order: initialOrder,
24
+ closeWorkspace,
25
+ closeWorkspaceWithSavedChanges,
26
+ promptBeforeClosing,
27
+ }: AddMedicalSupplyOrderWorkspace) {
28
+ const { t } = useTranslation();
29
+
30
+ const [currentMedicalSupplyOrder, setCurrentMedicalSupplyOrder] = useState(initialOrder);
31
+
32
+ const isTablet = useLayoutType() === 'tablet';
33
+
34
+ const cancelOrder = useCallback(() => {
35
+ closeWorkspace({
36
+ ignoreChanges: true,
37
+ onWorkspaceClose: () => launchPatientWorkspace('order-basket'),
38
+ });
39
+ }, [closeWorkspace]);
40
+
41
+ if (!currentMedicalSupplyOrder) {
42
+ return (
43
+ <>
44
+ <div className={styles.backButton}>
45
+ <Button
46
+ kind="ghost"
47
+ renderIcon={(props) => <ArrowLeft size={24} {...props} />}
48
+ iconDescription="Return to order basket"
49
+ size="sm"
50
+ onClick={cancelOrder}>
51
+ <span>{t('backToOrderBasket', 'Back to order basket')}</span>
52
+ </Button>
53
+ </div>
54
+ <MedicalSupplyTypeSearch openMedicalSupplyForm={setCurrentMedicalSupplyOrder} />
55
+ </>
56
+ );
57
+ } else {
58
+ return (
59
+ <MedicalSupplyOrderForm
60
+ initialOrder={currentMedicalSupplyOrder}
61
+ closeWorkspace={closeWorkspace}
62
+ closeWorkspaceWithSavedChanges={closeWorkspaceWithSavedChanges}
63
+ promptBeforeClosing={promptBeforeClosing}
64
+ />
65
+ );
66
+ }
67
+ }