@openmrs/esm-patient-orders-app 5.0.1-pre.2175

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 (71) hide show
  1. package/.turbo/turbo-build.log +36 -0
  2. package/LICENSE +401 -0
  3. package/README.md +4 -0
  4. package/dist/130.js +2 -0
  5. package/dist/130.js.LICENSE.txt +3 -0
  6. package/dist/130.js.map +1 -0
  7. package/dist/193.js +1 -0
  8. package/dist/193.js.map +1 -0
  9. package/dist/232.js +1 -0
  10. package/dist/232.js.map +1 -0
  11. package/dist/235.js +1 -0
  12. package/dist/235.js.map +1 -0
  13. package/dist/255.js +2 -0
  14. package/dist/255.js.LICENSE.txt +9 -0
  15. package/dist/255.js.map +1 -0
  16. package/dist/319.js +1 -0
  17. package/dist/37.js +1 -0
  18. package/dist/37.js.map +1 -0
  19. package/dist/442.js +2 -0
  20. package/dist/442.js.LICENSE.txt +14 -0
  21. package/dist/442.js.map +1 -0
  22. package/dist/47.js +1 -0
  23. package/dist/47.js.map +1 -0
  24. package/dist/574.js +1 -0
  25. package/dist/588.js +1 -0
  26. package/dist/588.js.map +1 -0
  27. package/dist/591.js +2 -0
  28. package/dist/591.js.LICENSE.txt +32 -0
  29. package/dist/591.js.map +1 -0
  30. package/dist/712.js +2 -0
  31. package/dist/712.js.LICENSE.txt +5 -0
  32. package/dist/712.js.map +1 -0
  33. package/dist/757.js +1 -0
  34. package/dist/784.js +2 -0
  35. package/dist/784.js.LICENSE.txt +9 -0
  36. package/dist/784.js.map +1 -0
  37. package/dist/788.js +1 -0
  38. package/dist/807.js +1 -0
  39. package/dist/833.js +1 -0
  40. package/dist/842.js +1 -0
  41. package/dist/842.js.map +1 -0
  42. package/dist/95.js +1 -0
  43. package/dist/95.js.map +1 -0
  44. package/dist/main.js +1 -0
  45. package/dist/main.js.map +1 -0
  46. package/dist/openmrs-esm-patient-orders-app.js +1 -0
  47. package/dist/openmrs-esm-patient-orders-app.js.buildmanifest.json +618 -0
  48. package/dist/openmrs-esm-patient-orders-app.js.map +1 -0
  49. package/dist/routes.json +1 -0
  50. package/jest.config.js +3 -0
  51. package/package.json +57 -0
  52. package/src/api/api.ts +137 -0
  53. package/src/config-schema.ts +13 -0
  54. package/src/declarations.d.ts +3 -0
  55. package/src/index.ts +28 -0
  56. package/src/order-basket/order-basket.scss +39 -0
  57. package/src/order-basket/order-basket.workspace.tsx +177 -0
  58. package/src/order-basket-action-button/order-basket-action-button.extension.tsx +56 -0
  59. package/src/order-basket-action-button/order-basket-action-button.scss +80 -0
  60. package/src/order-basket-action-button/order-basket-action-button.test.tsx +121 -0
  61. package/src/root.scss +67 -0
  62. package/src/routes.json +14 -0
  63. package/src/types/order.ts +5 -0
  64. package/translations/am.json +3 -0
  65. package/translations/en.json +3 -0
  66. package/translations/es.json +3 -0
  67. package/translations/fr.json +3 -0
  68. package/translations/he.json +3 -0
  69. package/translations/km.json +3 -0
  70. package/tsconfig.json +5 -0
  71. package/webpack.config.js +1 -0
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@openmrs/esm-patient-orders-app",
3
+ "version": "5.0.1-pre.2175",
4
+ "license": "MPL-2.0",
5
+ "description": "Microfrontend for the OpenMRS SPA providing the order basket for the patient chart",
6
+ "browser": "dist/openmrs-esm-patient-orders-app.js",
7
+ "main": "src/index.ts",
8
+ "source": true,
9
+ "scripts": {
10
+ "start": "openmrs develop",
11
+ "serve": "webpack serve --mode=development",
12
+ "debug": "npm run serve",
13
+ "build": "webpack --mode production",
14
+ "analyze": "webpack --mode=production --env analyze=true",
15
+ "lint": "cross-env TIMING=1 eslint src --ext tsx,ts --fix --max-warnings=0",
16
+ "test": "cross-env TZ=UTC jest --config jest.config.js --verbose false --passWithNoTests",
17
+ "test:watch": "cross-env TZ=UTC jest --watch --config jest.config.js",
18
+ "coverage": "yarn test --coverage",
19
+ "typescript": "tsc",
20
+ "extract-translations": "i18next 'src/**/*.component.tsx' 'src/index.ts' --config ../../tools/i18next-parser.config.js"
21
+ },
22
+ "browserslist": [
23
+ "extends browserslist-config-openmrs"
24
+ ],
25
+ "keywords": [
26
+ "openmrs"
27
+ ],
28
+ "homepage": "https://github.com/openmrs/openmrs-esm-patient-chart#readme",
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/openmrs/openmrs-esm-patient-chart.git"
35
+ },
36
+ "bugs": {
37
+ "url": "https://github.com/openmrs/openmrs-esm-patient-chart/issues"
38
+ },
39
+ "dependencies": {
40
+ "@carbon/react": "^1.12.0",
41
+ "@openmrs/esm-patient-common-lib": "^5.0.1-pre.2175",
42
+ "lodash-es": "^4.17.15"
43
+ },
44
+ "peerDependencies": {
45
+ "@openmrs/esm-framework": "5.x",
46
+ "@openmrs/esm-patient-common-lib": "5.x",
47
+ "dayjs": "1.x",
48
+ "react": "18.x",
49
+ "react-i18next": "11.x",
50
+ "react-router-dom": "6.x",
51
+ "rxjs": "6.x"
52
+ },
53
+ "devDependencies": {
54
+ "webpack": "^5.74.0"
55
+ },
56
+ "gitHead": "73d5cacb9bd7310f741583719a101e4382093ef0"
57
+ }
package/src/api/api.ts ADDED
@@ -0,0 +1,137 @@
1
+ import { useCallback, useMemo } from 'react';
2
+ import useSWR, { useSWRConfig } from 'swr';
3
+ import { FetchResponse, openmrsFetch, OpenmrsResource, parseDate, Visit } from '@openmrs/esm-framework';
4
+ import { OrderPost, useVisitOrOfflineVisit, useSystemVisitSetting } from '@openmrs/esm-patient-common-lib';
5
+
6
+ /**
7
+ * Returns a function which refreshes the patient orders cache. Uses SWR's mutate function.
8
+ * Refreshes patient orders for all kinds of orders.
9
+ *
10
+ * TODO: This isn't working. See https://github.com/vercel/swr/issues/2746
11
+ *
12
+ * @param patientUuid The UUID of the patient to get an order mutate function for.
13
+ */
14
+ export function useMutatePatientOrders(patientUuid: string) {
15
+ const { mutate } = useSWRConfig();
16
+ const mutateOrders = useCallback(
17
+ () =>
18
+ mutate((key) => {
19
+ return typeof key === 'string' && key.startsWith(`/ws/rest/v1/order?patient=${patientUuid}`);
20
+ }),
21
+ [patientUuid, mutate],
22
+ );
23
+
24
+ return {
25
+ mutate: mutateOrders,
26
+ };
27
+ }
28
+
29
+ export function getPatientEncounterId(patientUuid: string, abortController: AbortController) {
30
+ return openmrsFetch(`/ws/rest/v1/encounter?patient=${patientUuid}&order=desc&limit=1&v=custom:(uuid)`, {
31
+ signal: abortController.signal,
32
+ });
33
+ }
34
+
35
+ export function getMedicationByUuid(abortController: AbortController, orderUuid: string) {
36
+ return openmrsFetch(
37
+ `/ws/rest/v1/order/${orderUuid}?v=custom:(uuid,route:(uuid,display),action,urgency,display,drug:(display,strength),frequency:(display),dose,doseUnits:(display),orderer,dateStopped,dateActivated,previousOrder,numRefills,duration,durationUnits:(display),dosingInstructions)`,
38
+ {
39
+ signal: abortController.signal,
40
+ },
41
+ );
42
+ }
43
+
44
+ export function createEmptyEncounter(
45
+ patientUuid: string,
46
+ orderEncounterType: string,
47
+ activeVisit: Visit | null,
48
+ sessionLocationUuid: string,
49
+ abortController?: AbortController,
50
+ ) {
51
+ const now = new Date();
52
+ const visitStartDate = parseDate(activeVisit?.startDatetime);
53
+ const visitEndDate = parseDate(activeVisit?.stopDatetime);
54
+ let encounterDate: Date;
55
+ if (!activeVisit || (visitStartDate < now && (!visitEndDate || visitEndDate > now))) {
56
+ now;
57
+ } else {
58
+ console.warn(
59
+ 'createEmptyEncounter received an active visit that is not currently active. This is a programming error. Attempting to place the order using the visit start date.',
60
+ );
61
+ visitStartDate;
62
+ }
63
+ const emptyEncounter = {
64
+ patient: patientUuid,
65
+ location: sessionLocationUuid,
66
+ encounterType: orderEncounterType,
67
+ encounterDatetime: encounterDate,
68
+ visit: activeVisit?.uuid,
69
+ obs: [],
70
+ };
71
+
72
+ return openmrsFetch<OpenmrsResource>('/ws/rest/v1/encounter', {
73
+ headers: {
74
+ 'Content-Type': 'application/json',
75
+ },
76
+ method: 'POST',
77
+ body: emptyEncounter,
78
+ signal: abortController?.signal,
79
+ }).then((res) => res?.data?.uuid);
80
+ }
81
+
82
+ export function postOrder(body: OrderPost, abortController?: AbortController) {
83
+ return openmrsFetch(`/ws/rest/v1/order`, {
84
+ method: 'POST',
85
+ signal: abortController?.signal,
86
+ headers: { 'Content-Type': 'application/json' },
87
+ body,
88
+ });
89
+ }
90
+
91
+ export function useOrderEncounter(patientUuid: string): {
92
+ activeVisitRequired: boolean;
93
+ isLoading: boolean;
94
+ error: Error;
95
+ encounterUuid: string;
96
+ mutate: Function;
97
+ } {
98
+ const { systemVisitEnabled, isLoadingSystemVisitSetting, errorFetchingSystemVisitSetting } = useSystemVisitSetting();
99
+
100
+ const now = new Date();
101
+ const nowDateString = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`;
102
+ const todayEncounter = useSWR<FetchResponse<{ results: Array<OpenmrsResource> }>, Error>(
103
+ !isLoadingSystemVisitSetting && !systemVisitEnabled && patientUuid
104
+ ? `/ws/rest/v1/encounter?patient=${patientUuid}&fromdate=${nowDateString}&limit=1`
105
+ : null,
106
+ openmrsFetch,
107
+ );
108
+ const visit = useVisitOrOfflineVisit(patientUuid);
109
+
110
+ const results = useMemo(() => {
111
+ if (isLoadingSystemVisitSetting || errorFetchingSystemVisitSetting) {
112
+ return {
113
+ activeVisitRequired: false,
114
+ isLoading: isLoadingSystemVisitSetting,
115
+ error: errorFetchingSystemVisitSetting,
116
+ encounterUuid: null,
117
+ mutate: () => {},
118
+ };
119
+ }
120
+ return systemVisitEnabled
121
+ ? {
122
+ activeVisitRequired: true,
123
+ isLoading: visit?.isLoading,
124
+ encounterUuid: visit?.currentVisit?.encounters?.[0]?.uuid,
125
+ error: visit?.error,
126
+ mutate: visit?.mutate,
127
+ }
128
+ : {
129
+ activeVisitRequired: false,
130
+ isLoading: todayEncounter?.isLoading,
131
+ encounterUuid: todayEncounter?.data?.data?.results?.[0]?.uuid,
132
+ error: todayEncounter?.error,
133
+ mutate: todayEncounter?.mutate,
134
+ };
135
+ }, [isLoadingSystemVisitSetting, errorFetchingSystemVisitSetting, visit, todayEncounter, systemVisitEnabled]);
136
+ return results;
137
+ }
@@ -0,0 +1,13 @@
1
+ import { Type } from '@openmrs/esm-framework';
2
+
3
+ export const configSchema = {
4
+ orderEncounterType: {
5
+ _type: Type.UUID,
6
+ _description: 'The encounter type of the encounter encapsulating orders',
7
+ _default: '39da3525-afe4-45ff-8977-c53b7b359158',
8
+ },
9
+ };
10
+
11
+ export interface ConfigObject {
12
+ orderEncounterType: string;
13
+ }
@@ -0,0 +1,3 @@
1
+ declare module '*.css';
2
+ declare module '*.scss';
3
+ declare module '*.png';
package/src/index.ts ADDED
@@ -0,0 +1,28 @@
1
+ import { defineConfigSchema, getAsyncLifecycle } from '@openmrs/esm-framework';
2
+ import { registerWorkspace } from '@openmrs/esm-patient-common-lib';
3
+ import { configSchema } from './config-schema';
4
+
5
+ export const importTranslation = require.context('../translations', false, /.json$/, 'lazy');
6
+
7
+ const moduleName = '@openmrs/esm-patient-orders-app';
8
+
9
+ const options = {
10
+ featureName: 'patient-orders',
11
+ moduleName,
12
+ };
13
+
14
+ export function startupApp() {
15
+ defineConfigSchema(moduleName, configSchema);
16
+ }
17
+
18
+ registerWorkspace({
19
+ name: 'order-basket',
20
+ title: 'Order Basket',
21
+ load: getAsyncLifecycle(() => import('./order-basket/order-basket.workspace'), options),
22
+ type: 'order',
23
+ });
24
+
25
+ export const orderBasketActionMenu = getAsyncLifecycle(
26
+ () => import('./order-basket-action-button/order-basket-action-button.extension'),
27
+ options,
28
+ );
@@ -0,0 +1,39 @@
1
+ @use '@carbon/styles/scss/spacing';
2
+ @import "../root";
3
+
4
+ .container {
5
+ display: flex;
6
+ flex-direction: column;
7
+ justify-content: space-between;
8
+ height: calc(100vh - 9rem);
9
+ }
10
+
11
+ .orderBasketContainer {
12
+ margin: spacing.$spacing-05;
13
+ }
14
+
15
+ .orderBasketContainer :global(.cds--btn-set .cds--btn) {
16
+ max-width: 50%;
17
+ height: 4rem;
18
+ }
19
+
20
+ .tablet {
21
+ padding: 1.5rem 1rem;
22
+ background-color: $ui-02;
23
+ }
24
+
25
+ .desktop {
26
+ padding: 0rem;
27
+ }
28
+
29
+ .bottomButton {
30
+ height: 4rem;
31
+ display: flex;
32
+ align-content: flex-start;
33
+ align-items: baseline;
34
+ min-width: 50%;
35
+ }
36
+
37
+ .inlineNotification, .actionNotification {
38
+ max-width: unset !important;
39
+ }
@@ -0,0 +1,177 @@
1
+ import React, { useCallback, useState } from 'react';
2
+ import { TFunction, useTranslation } from 'react-i18next';
3
+ import { ActionableNotification, Button, ButtonSet, InlineNotification } from '@carbon/react';
4
+ import { ExtensionSlot, showModal, showToast, useConfig, useLayoutType, useSession } from '@openmrs/esm-framework';
5
+ import {
6
+ postOrders,
7
+ useOrderBasket,
8
+ useVisitOrOfflineVisit,
9
+ OrderBasketItem,
10
+ DefaultWorkspaceProps,
11
+ } from '@openmrs/esm-patient-common-lib';
12
+ import { ConfigObject } from '../config-schema';
13
+ import { createEmptyEncounter, useOrderEncounter, useMutatePatientOrders } from '../api/api';
14
+ import styles from './order-basket.scss';
15
+
16
+ const OrderBasket: React.FC<DefaultWorkspaceProps> = ({ patientUuid, closeWorkspace }) => {
17
+ const { t } = useTranslation();
18
+ const isTablet = useLayoutType() === 'tablet';
19
+ const config = useConfig() as ConfigObject;
20
+ const session = useSession();
21
+ const { activeVisit } = useVisitOrOfflineVisit(patientUuid);
22
+ const { orders, clearOrders } = useOrderBasket();
23
+ const {
24
+ activeVisitRequired,
25
+ isLoading: isLoadingEncounterUuid,
26
+ encounterUuid,
27
+ error: errorFetchingEncounterUuid,
28
+ mutate: mutateEncounterUuid,
29
+ } = useOrderEncounter(patientUuid);
30
+ const [creatingEncounterError, setCreatingEncounterError] = useState('');
31
+ const { mutate: mutateOrders } = useMutatePatientOrders(patientUuid);
32
+
33
+ const openStartVisitDialog = useCallback(() => {
34
+ const dispose = showModal('start-visit-dialog', {
35
+ patientUuid,
36
+ closeModal: () => dispose(),
37
+ });
38
+ }, [patientUuid]);
39
+
40
+ const handleSave = useCallback(async () => {
41
+ const abortController = new AbortController();
42
+ setCreatingEncounterError('');
43
+ let orderEncounterUuid = encounterUuid;
44
+ // If there's no encounter present, create an encounter for the order.
45
+ if (!orderEncounterUuid) {
46
+ try {
47
+ orderEncounterUuid = await createEmptyEncounter(
48
+ patientUuid,
49
+ config?.orderEncounterType,
50
+ activeVisitRequired ? activeVisit : null,
51
+ session?.sessionLocation?.uuid,
52
+ abortController,
53
+ );
54
+ mutateEncounterUuid();
55
+ } catch (e) {
56
+ setCreatingEncounterError(e);
57
+ console.error(e);
58
+ return; // don't try to create the orders if we couldn't create the encounter
59
+ }
60
+ }
61
+
62
+ const erroredItems = await postOrders(orderEncounterUuid, abortController);
63
+ clearOrders({ exceptThoseMatching: (item) => erroredItems.includes(item) });
64
+ mutateOrders();
65
+ if (erroredItems.length == 0) {
66
+ closeWorkspace();
67
+ showOrderSuccessToast(t, orders);
68
+ } else {
69
+ showOrderFailureToast(t);
70
+ }
71
+
72
+ return () => abortController.abort();
73
+ }, [
74
+ activeVisit,
75
+ activeVisitRequired,
76
+ clearOrders,
77
+ closeWorkspace,
78
+ config,
79
+ encounterUuid,
80
+ mutateEncounterUuid,
81
+ mutateOrders,
82
+ orders,
83
+ patientUuid,
84
+ session,
85
+ t,
86
+ ]);
87
+
88
+ const handleCancel = useCallback(() => {
89
+ clearOrders();
90
+ closeWorkspace();
91
+ }, [clearOrders, closeWorkspace]);
92
+
93
+ return (
94
+ <>
95
+ <div className={styles.container}>
96
+ <div className={styles.orderBasketContainer}>
97
+ <ExtensionSlot name="order-basket-slot" />
98
+ </div>
99
+
100
+ <div>
101
+ {(creatingEncounterError || errorFetchingEncounterUuid) && (
102
+ <InlineNotification
103
+ kind="error"
104
+ title={t('errorCreatingAnEncounter', 'Error when creating an encounter')}
105
+ subtitle={t('tryReopeningTheWorkspaceAgain', 'Please try launching the workspace again')}
106
+ lowContrast={true}
107
+ className={styles.inlineNotification}
108
+ inline
109
+ />
110
+ )}
111
+ <ButtonSet className={isTablet ? styles.tablet : styles.desktop}>
112
+ <Button className={styles.bottomButton} kind="secondary" onClick={handleCancel}>
113
+ {t('cancel', 'Cancel')}
114
+ </Button>
115
+ <Button
116
+ className={styles.bottomButton}
117
+ kind="primary"
118
+ onClick={handleSave}
119
+ disabled={!orders?.length || isLoadingEncounterUuid || (activeVisitRequired && !activeVisit)}
120
+ >
121
+ {t('signAndClose', 'Sign and close')}
122
+ </Button>
123
+ </ButtonSet>
124
+ </div>
125
+ </div>
126
+ {activeVisitRequired && !activeVisit && (
127
+ <ActionableNotification
128
+ kind="error"
129
+ actionButtonLabel={t('startVisit', 'Start visit')}
130
+ onActionButtonClick={openStartVisitDialog}
131
+ title={t('startAVisitToRecordOrders', 'Start a visit to order')}
132
+ subtitle={t('activeVisitRequired', 'An active visit is required to make orders')}
133
+ lowContrast={true}
134
+ inline
135
+ className={styles.actionNotification}
136
+ hasFocus
137
+ />
138
+ )}
139
+ </>
140
+ );
141
+ };
142
+
143
+ function showOrderSuccessToast(t: TFunction, patientOrderItems: OrderBasketItem[]) {
144
+ const orderedString = patientOrderItems
145
+ .filter((item) => ['NEW', 'RENEW'].includes(item.action))
146
+ .map((item) => item.drug?.display)
147
+ .join(', ');
148
+ const updatedString = patientOrderItems
149
+ .filter((item) => item.action === 'REVISE')
150
+ .map((item) => item.drug?.display)
151
+ .join(', ');
152
+ const discontinuedString = patientOrderItems
153
+ .filter((item) => item.action === 'DISCONTINUE')
154
+ .map((item) => item.drug?.display)
155
+ .join(', ');
156
+
157
+ showToast({
158
+ critical: true,
159
+ kind: 'success',
160
+ title: t('orderCompleted', 'Medications updated'),
161
+ description:
162
+ (orderedString && `${t('ordered', 'Placed order for')} ${orderedString}. `) +
163
+ (updatedString && `${t('updated', 'Updated')} ${updatedString}. `) +
164
+ (discontinuedString && `${t('discontinued', 'Discontinued')} ${discontinuedString}.`),
165
+ });
166
+ }
167
+
168
+ function showOrderFailureToast(t: TFunction) {
169
+ showToast({
170
+ critical: true,
171
+ kind: 'error',
172
+ title: t('error', 'Error'),
173
+ description: t('errorSavingMedicationOrder', 'There were errors saving some medication orders.'),
174
+ });
175
+ }
176
+
177
+ export default OrderBasket;
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { Button, Tag } from '@carbon/react';
4
+ import { ShoppingCart } from '@carbon/react/icons';
5
+ import { useLayoutType } from '@openmrs/esm-framework';
6
+ import { useLaunchWorkspaceRequiringVisit, useOrderBasket, useWorkspaces } from '@openmrs/esm-patient-common-lib';
7
+ import styles from './order-basket-action-button.scss';
8
+
9
+ const OrderBasketActionButton: React.FC = () => {
10
+ const layout = useLayoutType();
11
+ const { t } = useTranslation();
12
+ const { workspaces } = useWorkspaces();
13
+ const { orders } = useOrderBasket();
14
+ const isActiveWorkspace = workspaces?.[0]?.name?.match(/order-basket/i);
15
+ const launchOrderBasket = useLaunchWorkspaceRequiringVisit('order-basket');
16
+
17
+ if (layout === 'tablet') {
18
+ return (
19
+ <Button
20
+ kind="ghost"
21
+ className={`${styles.container} ${isActiveWorkspace ? styles.active : ''}`}
22
+ role="button"
23
+ tabIndex={0}
24
+ onClick={() => launchOrderBasket()}
25
+ >
26
+ <div className={styles.elementContainer}>
27
+ <ShoppingCart size={16} />
28
+ {orders?.length > 0 && <Tag className={styles.countTag}>{orders?.length}</Tag>}
29
+ </div>
30
+ <span>{t('orderBasket', 'Order basket')}</span>
31
+ </Button>
32
+ );
33
+ }
34
+
35
+ return (
36
+ <Button
37
+ className={isActiveWorkspace && styles.active}
38
+ kind="ghost"
39
+ size="sm"
40
+ renderIcon={(props) => (
41
+ <div className={styles.elementContainer}>
42
+ <ShoppingCart size={20} {...props} />{' '}
43
+ {orders?.length > 0 && <Tag className={styles.countTag}>{orders?.length}</Tag>}
44
+ </div>
45
+ )}
46
+ hasIconOnly
47
+ iconDescription={t('medications', 'Medications')}
48
+ enterDelayMs={1000}
49
+ tooltipAlignment="center"
50
+ tooltipPosition="left"
51
+ onClick={() => launchOrderBasket()}
52
+ />
53
+ );
54
+ };
55
+
56
+ export default OrderBasketActionButton;
@@ -0,0 +1,80 @@
1
+ @use '@carbon/styles/scss/spacing';
2
+ @use '@carbon/styles/scss/type';
3
+ @import '~@openmrs/esm-styleguide/src/vars';
4
+
5
+ .elementContainer {
6
+ display: flex;
7
+ align-items: center;
8
+ position: relative;
9
+
10
+ .countTag {
11
+ position: absolute;
12
+ transform: scale(0.7);
13
+ min-width: initial;
14
+ min-height: initial;
15
+ background-color: $carbon--red-50;
16
+ color: $ui-02;
17
+ right: -10px;
18
+ top: -15px;
19
+ }
20
+ }
21
+
22
+ .container {
23
+ display: flex;
24
+ flex-direction: column;
25
+ justify-content: center;
26
+ align-items: center;
27
+ height: 100%;
28
+ width: 100%;
29
+ color: $ui-05;
30
+ max-width: none;
31
+
32
+ &:hover {
33
+ color: $text-02;
34
+ }
35
+
36
+ & > span {
37
+ margin-top: spacing.$spacing-02;
38
+ @include type.type-style("body-compact-01");
39
+ color: $text-02;
40
+ }
41
+ }
42
+
43
+ /* Desktop */
44
+ :global(.omrs-breakpoint-gt-tablet) {
45
+ .active {
46
+ border: spacing.$spacing-01 solid;
47
+ @include brand-03(border-color);
48
+ border-radius: 50%;
49
+ background-color: $ui-02;
50
+
51
+ &:focus {
52
+ border-color: var(--brand-03) !important;
53
+ }
54
+ }
55
+
56
+ .elementContainer {
57
+ color: $text-02;
58
+ }
59
+ }
60
+
61
+ /* Tablet */
62
+ :global(.omrs-breakpoint-lt-desktop) {
63
+ .active {
64
+ background-color: $color-blue-10;
65
+ color: $interactive-01;
66
+
67
+ &:hover {
68
+ color: $interactive-01;
69
+ }
70
+
71
+ & > span {
72
+ color: $interactive-01;
73
+ @include type.type-style("heading-compact-01");
74
+ }
75
+
76
+ svg {
77
+ fill: $interactive-01;
78
+ }
79
+ }
80
+ }