@openmrs/esm-react-utils 5.3.3-pre.1237 → 5.3.3-pre.1247
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 +2 -2
- package/__mocks__/openmrs-esm-state.mock.ts +8 -20
- package/dist/openmrs-esm-react-utils.js.map +1 -1
- package/jest.config.js +9 -11
- package/package.json +7 -7
- package/src/ComponentContext.ts +2 -2
- package/src/ConfigurableLink.test.tsx +19 -23
- package/src/ConfigurableLink.tsx +5 -19
- package/src/Extension.tsx +36 -76
- package/src/ExtensionSlot.tsx +15 -24
- package/src/UserHasAccess.tsx +3 -7
- package/src/extensions.test.tsx +100 -179
- package/src/getLifecycle.ts +8 -18
- package/src/index.ts +31 -31
- package/src/openmrsComponentDecorator.test.tsx +12 -12
- package/src/openmrsComponentDecorator.tsx +12 -26
- package/src/public.ts +27 -27
- package/src/setup-tests.js +4 -4
- package/src/useAbortController.test.tsx +8 -8
- package/src/useAbortController.ts +1 -1
- package/src/useAssignedExtensionIds.ts +4 -5
- package/src/useAssignedExtensions.ts +3 -7
- package/src/useBodyScrollLock.ts +2 -2
- package/src/useConfig.test.tsx +96 -112
- package/src/useConfig.ts +15 -43
- package/src/useConnectedExtensions.ts +8 -17
- package/src/useConnectivity.ts +3 -6
- package/src/useDebounce.ts +1 -1
- package/src/useExtensionInternalStore.ts +3 -8
- package/src/useExtensionSlot.ts +5 -7
- package/src/useExtensionSlotMeta.ts +5 -11
- package/src/useExtensionStore.ts +3 -5
- package/src/useFeatureFlag.ts +4 -4
- package/src/useForceUpdate.ts +1 -1
- package/src/useLayoutType.ts +12 -13
- package/src/useLocations.tsx +3 -3
- package/src/useOnClickOutside.test.tsx +10 -10
- package/src/useOnClickOutside.ts +2 -5
- package/src/useOpenmrsSWR.ts +9 -9
- package/src/usePagination.ts +6 -18
- package/src/usePatient.ts +9 -13
- package/src/useSession.test.tsx +35 -43
- package/src/useSession.ts +9 -13
- package/src/useStore.test.ts +11 -13
- package/src/useStore.ts +10 -31
- package/src/useVisit.ts +14 -37
- package/src/useVisitTypes.ts +3 -3
- package/webpack.config.js +14 -14
package/src/useConfig.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** @module @category Config */
|
|
2
|
-
import { useContext, useEffect, useMemo, useState } from
|
|
2
|
+
import { useContext, useEffect, useMemo, useState } from 'react';
|
|
3
3
|
import {
|
|
4
4
|
getConfigStore,
|
|
5
5
|
getExtensionsConfigStore,
|
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
ConfigObject,
|
|
8
8
|
ExtensionsConfigStore,
|
|
9
9
|
getExtensionConfigFromStore,
|
|
10
|
-
} from
|
|
11
|
-
import type { StoreApi } from
|
|
12
|
-
import isEqual from
|
|
13
|
-
import { ComponentContext, ExtensionData } from
|
|
10
|
+
} from '@openmrs/esm-config';
|
|
11
|
+
import type { StoreApi } from 'zustand';
|
|
12
|
+
import isEqual from 'lodash-es/isEqual';
|
|
13
|
+
import { ComponentContext, ExtensionData } from './ComponentContext';
|
|
14
14
|
|
|
15
15
|
const promises: Record<string, Promise<ConfigObject>> = {};
|
|
16
16
|
const errorMessage = `No ComponentContext has been provided. This should come from "openmrsComponentDecorator".
|
|
@@ -28,18 +28,11 @@ function readInitialConfig(store: StoreApi<ConfigStore>) {
|
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
function readInitialExtensionConfig(
|
|
32
|
-
store: StoreApi<ExtensionsConfigStore>,
|
|
33
|
-
extension: ExtensionData | undefined
|
|
34
|
-
) {
|
|
31
|
+
function readInitialExtensionConfig(store: StoreApi<ExtensionsConfigStore>, extension: ExtensionData | undefined) {
|
|
35
32
|
if (extension) {
|
|
36
33
|
return () => {
|
|
37
34
|
const state = store.getState();
|
|
38
|
-
const extConfig = getExtensionConfigFromStore(
|
|
39
|
-
state,
|
|
40
|
-
extension.extensionSlotName,
|
|
41
|
-
extension.extensionId
|
|
42
|
-
);
|
|
35
|
+
const extConfig = getExtensionConfigFromStore(state, extension.extensionSlotName, extension.extensionId);
|
|
43
36
|
if (extConfig.loaded && extConfig.config) {
|
|
44
37
|
return extConfig.config;
|
|
45
38
|
}
|
|
@@ -59,17 +52,10 @@ function createConfigPromise(store: StoreApi<ConfigStore>) {
|
|
|
59
52
|
});
|
|
60
53
|
}
|
|
61
54
|
|
|
62
|
-
function createExtensionConfigPromise(
|
|
63
|
-
store: StoreApi<ExtensionsConfigStore>,
|
|
64
|
-
extension: ExtensionData
|
|
65
|
-
) {
|
|
55
|
+
function createExtensionConfigPromise(store: StoreApi<ExtensionsConfigStore>, extension: ExtensionData) {
|
|
66
56
|
return new Promise<ConfigObject>((resolve) => {
|
|
67
57
|
const unsubscribe = store.subscribe((state) => {
|
|
68
|
-
const extConfig = getExtensionConfigFromStore(
|
|
69
|
-
state,
|
|
70
|
-
extension.extensionSlotName,
|
|
71
|
-
extension.extensionId
|
|
72
|
-
);
|
|
58
|
+
const extConfig = getExtensionConfigFromStore(state, extension.extensionSlotName, extension.extensionId);
|
|
73
59
|
if (extConfig.loaded && extConfig.config) {
|
|
74
60
|
resolve(extConfig.config);
|
|
75
61
|
unsubscribe();
|
|
@@ -92,27 +78,14 @@ function useConfigStore(store: StoreApi<ConfigStore>) {
|
|
|
92
78
|
return state;
|
|
93
79
|
}
|
|
94
80
|
|
|
95
|
-
function useExtensionConfigStore(
|
|
96
|
-
store
|
|
97
|
-
extension: ExtensionData | undefined
|
|
98
|
-
) {
|
|
99
|
-
const [config, setConfig] = useState<ConfigObject | null>(
|
|
100
|
-
readInitialExtensionConfig(store, extension)
|
|
101
|
-
);
|
|
81
|
+
function useExtensionConfigStore(store: StoreApi<ExtensionsConfigStore>, extension: ExtensionData | undefined) {
|
|
82
|
+
const [config, setConfig] = useState<ConfigObject | null>(readInitialExtensionConfig(store, extension));
|
|
102
83
|
|
|
103
84
|
useEffect(() => {
|
|
104
85
|
if (extension) {
|
|
105
86
|
return store.subscribe((state) => {
|
|
106
|
-
const extConfig = getExtensionConfigFromStore(
|
|
107
|
-
|
|
108
|
-
extension.extensionSlotName,
|
|
109
|
-
extension.extensionId
|
|
110
|
-
);
|
|
111
|
-
if (
|
|
112
|
-
extConfig.loaded &&
|
|
113
|
-
extConfig.config &&
|
|
114
|
-
!isEqual(extConfig.config, config)
|
|
115
|
-
) {
|
|
87
|
+
const extConfig = getExtensionConfigFromStore(state, extension.extensionSlotName, extension.extensionId);
|
|
88
|
+
if (extConfig.loaded && extConfig.config && !isEqual(extConfig.config, config)) {
|
|
116
89
|
setConfig(extConfig.config);
|
|
117
90
|
}
|
|
118
91
|
});
|
|
@@ -172,8 +145,7 @@ export function useConfig<T = Record<string, any>>(options?: UseConfigOptions) {
|
|
|
172
145
|
// This hook uses the config of the MF defining the component.
|
|
173
146
|
// If the component is used in an extension slot then the slot
|
|
174
147
|
// may override (part of) its configuration.
|
|
175
|
-
const { moduleName: contextModuleName, extension } =
|
|
176
|
-
useContext(ComponentContext);
|
|
148
|
+
const { moduleName: contextModuleName, extension } = useContext(ComponentContext);
|
|
177
149
|
const moduleName = options?.externalModuleName ?? contextModuleName;
|
|
178
150
|
|
|
179
151
|
if (!moduleName && !extension) {
|
|
@@ -187,7 +159,7 @@ export function useConfig<T = Record<string, any>>(options?: UseConfigOptions) {
|
|
|
187
159
|
options?.externalModuleName && moduleName === options.externalModuleName
|
|
188
160
|
? { ...normalConfig }
|
|
189
161
|
: { ...normalConfig, ...extensionConfig },
|
|
190
|
-
[moduleName, options?.externalModuleName, normalConfig, extensionConfig]
|
|
162
|
+
[moduleName, options?.externalModuleName, normalConfig, extensionConfig],
|
|
191
163
|
);
|
|
192
164
|
|
|
193
165
|
return config as T;
|
|
@@ -1,22 +1,17 @@
|
|
|
1
1
|
/** @module @category Extension */
|
|
2
|
-
import { useMemo } from
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
} from
|
|
7
|
-
import {
|
|
8
|
-
import { useAssignedExtensions } from "./useAssignedExtensions";
|
|
9
|
-
import { useStore } from "./useStore";
|
|
10
|
-
import { featureFlagsStore } from "@openmrs/esm-feature-flags";
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { ConnectedExtension, getConnectedExtensions } from '@openmrs/esm-extensions';
|
|
4
|
+
import { useConnectivity } from './useConnectivity';
|
|
5
|
+
import { useAssignedExtensions } from './useAssignedExtensions';
|
|
6
|
+
import { useStore } from './useStore';
|
|
7
|
+
import { featureFlagsStore } from '@openmrs/esm-feature-flags';
|
|
11
8
|
|
|
12
9
|
/**
|
|
13
10
|
* Gets the assigned extension for a given extension slot name.
|
|
14
11
|
* Considers if offline or online, and what feature flags are enabled.
|
|
15
12
|
* @param slotName The name of the slot to get the assigned extensions for.
|
|
16
13
|
*/
|
|
17
|
-
export function useConnectedExtensions(
|
|
18
|
-
slotName: string
|
|
19
|
-
): Array<ConnectedExtension> {
|
|
14
|
+
export function useConnectedExtensions(slotName: string): Array<ConnectedExtension> {
|
|
20
15
|
const online = useConnectivity();
|
|
21
16
|
const assignedExtensions = useAssignedExtensions(slotName);
|
|
22
17
|
const featureFlagStore = useStore(featureFlagsStore);
|
|
@@ -28,11 +23,7 @@ export function useConnectedExtensions(
|
|
|
28
23
|
}, [featureFlagStore.flags]);
|
|
29
24
|
|
|
30
25
|
const connectedExtensions = useMemo(() => {
|
|
31
|
-
return getConnectedExtensions(
|
|
32
|
-
assignedExtensions,
|
|
33
|
-
online,
|
|
34
|
-
enabledFeatureFlags
|
|
35
|
-
);
|
|
26
|
+
return getConnectedExtensions(assignedExtensions, online, enabledFeatureFlags);
|
|
36
27
|
}, [assignedExtensions, online, enabledFeatureFlags]);
|
|
37
28
|
|
|
38
29
|
return connectedExtensions;
|
package/src/useConnectivity.ts
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
/** @module @category Offline */
|
|
2
|
-
import { subscribeConnectivityChanged } from
|
|
3
|
-
import { useEffect, useState } from
|
|
2
|
+
import { subscribeConnectivityChanged } from '@openmrs/esm-globals';
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
4
|
|
|
5
5
|
export function useConnectivity() {
|
|
6
6
|
let [isOnline, setIsOnline] = useState(window.navigator.onLine);
|
|
7
7
|
|
|
8
|
-
useEffect(
|
|
9
|
-
() => subscribeConnectivityChanged(({ online }) => setIsOnline(online)),
|
|
10
|
-
[]
|
|
11
|
-
);
|
|
8
|
+
useEffect(() => subscribeConnectivityChanged(({ online }) => setIsOnline(online)), []);
|
|
12
9
|
|
|
13
10
|
return isOnline;
|
|
14
11
|
}
|
package/src/useDebounce.ts
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
getExtensionInternalStore,
|
|
4
|
-
} from "@openmrs/esm-extensions";
|
|
5
|
-
import { createUseStore } from "./useStore";
|
|
1
|
+
import { ExtensionInternalStore, getExtensionInternalStore } from '@openmrs/esm-extensions';
|
|
2
|
+
import { createUseStore } from './useStore';
|
|
6
3
|
|
|
7
4
|
/** @internal
|
|
8
5
|
* @deprecated Use `useStore(getExtensionInternalStore())`
|
|
9
6
|
*/
|
|
10
|
-
export const useExtensionInternalStore = createUseStore<ExtensionInternalStore>(
|
|
11
|
-
getExtensionInternalStore()
|
|
12
|
-
);
|
|
7
|
+
export const useExtensionInternalStore = createUseStore<ExtensionInternalStore>(getExtensionInternalStore());
|
package/src/useExtensionSlot.ts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import { useContext, useEffect } from
|
|
2
|
-
import { registerExtensionSlot } from
|
|
3
|
-
import { ComponentContext } from
|
|
4
|
-
import { useConnectedExtensions } from
|
|
1
|
+
import { useContext, useEffect } from 'react';
|
|
2
|
+
import { registerExtensionSlot } from '@openmrs/esm-extensions';
|
|
3
|
+
import { ComponentContext } from './ComponentContext';
|
|
4
|
+
import { useConnectedExtensions } from './useConnectedExtensions';
|
|
5
5
|
|
|
6
6
|
/** @internal */
|
|
7
7
|
export function useExtensionSlot(slotName: string) {
|
|
8
8
|
const { moduleName } = useContext(ComponentContext);
|
|
9
9
|
|
|
10
10
|
if (!moduleName) {
|
|
11
|
-
throw Error(
|
|
12
|
-
"ComponentContext has not been provided. This should come from @openmrs/esm-react-utils."
|
|
13
|
-
);
|
|
11
|
+
throw Error('ComponentContext has not been provided. This should come from @openmrs/esm-react-utils.');
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
useEffect(() => {
|
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
/** @module @category Extension */
|
|
2
|
-
import { ExtensionMeta } from
|
|
3
|
-
import { useMemo } from
|
|
4
|
-
import { useConnectedExtensions } from
|
|
2
|
+
import { ExtensionMeta } from '@openmrs/esm-extensions';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import { useConnectedExtensions } from './useConnectedExtensions';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Extract meta data from all extension for a given extension slot.
|
|
8
8
|
* @param extensionSlotName
|
|
9
9
|
*/
|
|
10
|
-
export function useExtensionSlotMeta<T = ExtensionMeta>(
|
|
11
|
-
extensionSlotName: string
|
|
12
|
-
) {
|
|
10
|
+
export function useExtensionSlotMeta<T = ExtensionMeta>(extensionSlotName: string) {
|
|
13
11
|
const extensions = useConnectedExtensions(extensionSlotName);
|
|
14
12
|
|
|
15
|
-
return useMemo(
|
|
16
|
-
() =>
|
|
17
|
-
Object.fromEntries(extensions.map((ext) => [ext.name, ext.meta as T])),
|
|
18
|
-
[extensions]
|
|
19
|
-
);
|
|
13
|
+
return useMemo(() => Object.fromEntries(extensions.map((ext) => [ext.name, ext.meta as T])), [extensions]);
|
|
20
14
|
}
|
package/src/useExtensionStore.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/** @module @category Extension */
|
|
2
|
-
import { ExtensionStore, getExtensionStore } from
|
|
3
|
-
import { createUseStore } from
|
|
2
|
+
import { ExtensionStore, getExtensionStore } from '@openmrs/esm-extensions';
|
|
3
|
+
import { createUseStore } from './useStore';
|
|
4
4
|
|
|
5
|
-
export const useExtensionStore = createUseStore<ExtensionStore>(
|
|
6
|
-
getExtensionStore()
|
|
7
|
-
);
|
|
5
|
+
export const useExtensionStore = createUseStore<ExtensionStore>(getExtensionStore());
|
package/src/useFeatureFlag.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @module @category Feature Flags */
|
|
2
|
-
import { useEffect } from
|
|
3
|
-
import { useStore } from
|
|
4
|
-
import { featureFlagsStore } from
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
import { useStore } from './useStore';
|
|
4
|
+
import { featureFlagsStore } from '@openmrs/esm-feature-flags';
|
|
5
5
|
|
|
6
6
|
/** Use this function to tell whether a feature flag is toggled on or off.
|
|
7
7
|
*
|
|
@@ -22,7 +22,7 @@ export function useFeatureFlag(flagName: string) {
|
|
|
22
22
|
useEffect(() => {
|
|
23
23
|
if (!flags[flagName]) {
|
|
24
24
|
console.error(
|
|
25
|
-
`useFeatureFlag: Attempted to get value of non-existent flag "${flagName}". Did you forget to call registerFeatureFlag
|
|
25
|
+
`useFeatureFlag: Attempted to get value of non-existent flag "${flagName}". Did you forget to call registerFeatureFlag?`,
|
|
26
26
|
);
|
|
27
27
|
}
|
|
28
28
|
}, [flags[flagName]]);
|
package/src/useForceUpdate.ts
CHANGED
package/src/useLayoutType.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
/** @module @category UI */
|
|
2
|
-
import { useEffect, useState } from
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
3
|
|
|
4
|
-
export type LayoutType =
|
|
4
|
+
export type LayoutType = 'phone' | 'tablet' | 'small-desktop' | 'large-desktop';
|
|
5
5
|
|
|
6
6
|
function getLayout() {
|
|
7
|
-
let layout: LayoutType =
|
|
7
|
+
let layout: LayoutType = 'tablet';
|
|
8
8
|
|
|
9
9
|
document.body.classList.forEach((cls) => {
|
|
10
10
|
switch (cls) {
|
|
11
|
-
case
|
|
12
|
-
layout =
|
|
11
|
+
case 'omrs-breakpoint-lt-tablet':
|
|
12
|
+
layout = 'phone';
|
|
13
13
|
break;
|
|
14
|
-
case
|
|
15
|
-
layout =
|
|
14
|
+
case 'omrs-breakpoint-gt-small-desktop':
|
|
15
|
+
layout = 'large-desktop';
|
|
16
16
|
break;
|
|
17
|
-
case
|
|
18
|
-
layout =
|
|
17
|
+
case 'omrs-breakpoint-gt-tablet':
|
|
18
|
+
layout = 'small-desktop';
|
|
19
19
|
break;
|
|
20
20
|
}
|
|
21
21
|
});
|
|
@@ -30,12 +30,11 @@ export function useLayoutType() {
|
|
|
30
30
|
const handler = () => {
|
|
31
31
|
setType(getLayout());
|
|
32
32
|
};
|
|
33
|
-
window.addEventListener(
|
|
34
|
-
return () => window.removeEventListener(
|
|
33
|
+
window.addEventListener('resize', handler);
|
|
34
|
+
return () => window.removeEventListener('resize', handler);
|
|
35
35
|
}, []);
|
|
36
36
|
|
|
37
37
|
return type;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
export const isDesktop = (layout: LayoutType) =>
|
|
41
|
-
layout === "small-desktop" || layout === "large-desktop";
|
|
40
|
+
export const isDesktop = (layout: LayoutType) => layout === 'small-desktop' || layout === 'large-desktop';
|
package/src/useLocations.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @module @category API */
|
|
2
|
-
import { getLocations, Location } from
|
|
3
|
-
import { useState, useEffect } from
|
|
2
|
+
import { getLocations, Location } from '@openmrs/esm-api';
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
4
|
|
|
5
5
|
export function useLocations() {
|
|
6
6
|
const [locations, setLocations] = useState<Array<Location>>([]);
|
|
@@ -12,7 +12,7 @@ export function useLocations() {
|
|
|
12
12
|
},
|
|
13
13
|
(error) => {
|
|
14
14
|
console.error(error);
|
|
15
|
-
}
|
|
15
|
+
},
|
|
16
16
|
);
|
|
17
17
|
return () => locationSub.unsubscribe();
|
|
18
18
|
}, []);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import React, { PropsWithChildren } from
|
|
2
|
-
import { render, fireEvent } from
|
|
3
|
-
import { useOnClickOutside } from
|
|
1
|
+
import React, { PropsWithChildren } from 'react';
|
|
2
|
+
import { render, fireEvent } from '@testing-library/react';
|
|
3
|
+
import { useOnClickOutside } from './useOnClickOutside';
|
|
4
4
|
|
|
5
|
-
describe(
|
|
5
|
+
describe('useOnClickOutside', () => {
|
|
6
6
|
const handler: (e: Event) => void = jest.fn();
|
|
7
7
|
afterEach(() => (handler as jest.Mock).mockClear());
|
|
8
8
|
|
|
9
|
-
it(
|
|
9
|
+
it('should call the handler when clicking outside', () => {
|
|
10
10
|
// setup
|
|
11
11
|
const Component: React.FC<PropsWithChildren> = ({ children }) => {
|
|
12
12
|
const ref = useOnClickOutside<HTMLDivElement>(handler);
|
|
@@ -21,7 +21,7 @@ describe("useOnClickOutside", () => {
|
|
|
21
21
|
expect(handler).toHaveBeenCalledTimes(1);
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
-
it(
|
|
24
|
+
it('should not call the handler when clicking on the element', () => {
|
|
25
25
|
// setup
|
|
26
26
|
const Component: React.FC<PropsWithChildren> = ({ children }) => {
|
|
27
27
|
const ref = useOnClickOutside<HTMLDivElement>(handler);
|
|
@@ -31,7 +31,7 @@ describe("useOnClickOutside", () => {
|
|
|
31
31
|
render(
|
|
32
32
|
<Component>
|
|
33
33
|
<div ref={mutableRef}></div>
|
|
34
|
-
</Component
|
|
34
|
+
</Component>,
|
|
35
35
|
);
|
|
36
36
|
|
|
37
37
|
// act
|
|
@@ -43,19 +43,19 @@ describe("useOnClickOutside", () => {
|
|
|
43
43
|
expect(handler).not.toHaveBeenCalled();
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
-
it(
|
|
46
|
+
it('should unregister the event listener when unmounted', () => {
|
|
47
47
|
// setup
|
|
48
48
|
const Component: React.FC<PropsWithChildren> = ({ children }) => {
|
|
49
49
|
const ref = useOnClickOutside<HTMLDivElement>(handler);
|
|
50
50
|
return <div ref={ref}>{children}</div>;
|
|
51
51
|
};
|
|
52
52
|
const ref = render(<Component />);
|
|
53
|
-
const spy = jest.spyOn(window,
|
|
53
|
+
const spy = jest.spyOn(window, 'removeEventListener');
|
|
54
54
|
|
|
55
55
|
// act
|
|
56
56
|
ref.unmount();
|
|
57
57
|
|
|
58
58
|
// verify
|
|
59
|
-
expect(spy).toHaveBeenCalledWith(
|
|
59
|
+
expect(spy).toHaveBeenCalledWith('click', expect.any(Function));
|
|
60
60
|
});
|
|
61
61
|
});
|
package/src/useOnClickOutside.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
/** @module @category UI */
|
|
2
|
-
import { useRef, useEffect } from
|
|
2
|
+
import { useRef, useEffect } from 'react';
|
|
3
3
|
|
|
4
|
-
export function useOnClickOutside<T extends HTMLElement = HTMLElement>(
|
|
5
|
-
handler: (event: Event) => void,
|
|
6
|
-
active = true
|
|
7
|
-
) {
|
|
4
|
+
export function useOnClickOutside<T extends HTMLElement = HTMLElement>(handler: (event: Event) => void, active = true) {
|
|
8
5
|
const ref = useRef<T>(null);
|
|
9
6
|
|
|
10
7
|
useEffect(() => {
|
package/src/useOpenmrsSWR.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/** @module @category Utility */
|
|
2
|
-
import { useCallback, useMemo } from
|
|
3
|
-
import useSWR, { SWRConfiguration } from
|
|
4
|
-
import { type FetchConfig, openmrsFetch } from
|
|
5
|
-
import useAbortController from
|
|
2
|
+
import { useCallback, useMemo } from 'react';
|
|
3
|
+
import useSWR, { SWRConfiguration } from 'swr';
|
|
4
|
+
import { type FetchConfig, openmrsFetch } from '@openmrs/esm-api';
|
|
5
|
+
import useAbortController from './useAbortController';
|
|
6
6
|
|
|
7
7
|
export type ArgumentsTuple = [any, ...unknown[]];
|
|
8
8
|
export type Key = string | ArgumentsTuple | undefined | null;
|
|
@@ -15,15 +15,15 @@ export type UseOpenmrsSWROptions = {
|
|
|
15
15
|
|
|
16
16
|
function getUrl(key: Key, url?: string | ((key: Key) => string)): string {
|
|
17
17
|
if (url) {
|
|
18
|
-
return typeof url ===
|
|
18
|
+
return typeof url === 'function' ? url(key) : url;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
if (typeof key ===
|
|
21
|
+
if (typeof key === 'string') {
|
|
22
22
|
return key;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
throw new Error(
|
|
26
|
-
`When using useOpenmrsSWR with a key that is not a string, you must provide a url() function that converts the key to a valid url. The key for this hook is ${key}
|
|
26
|
+
`When using useOpenmrsSWR with a key that is not a string, you must provide a url() function that converts the key to a valid url. The key for this hook is ${key}.`,
|
|
27
27
|
);
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -71,7 +71,7 @@ export function useOpenmrsSWR(key: Key, options: UseOpenmrsSWROptions = {}) {
|
|
|
71
71
|
const ac = useAbortController();
|
|
72
72
|
const abortSignal = useMemo<AbortSignal>(
|
|
73
73
|
() => fetchInit?.signal ?? abortController?.signal ?? ac.signal,
|
|
74
|
-
[abortController?.signal, fetchInit?.signal, ac.signal]
|
|
74
|
+
[abortController?.signal, fetchInit?.signal, ac.signal],
|
|
75
75
|
);
|
|
76
76
|
|
|
77
77
|
const fetcher = useCallback(
|
|
@@ -79,7 +79,7 @@ export function useOpenmrsSWR(key: Key, options: UseOpenmrsSWROptions = {}) {
|
|
|
79
79
|
const url_ = getUrl(key, url);
|
|
80
80
|
return openmrsFetch(url_, { ...fetchInit, signal: abortSignal });
|
|
81
81
|
},
|
|
82
|
-
[abortSignal, fetchInit, url]
|
|
82
|
+
[abortSignal, fetchInit, url],
|
|
83
83
|
);
|
|
84
84
|
|
|
85
85
|
return useSWR(key, fetcher, swrConfig);
|
package/src/usePagination.ts
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
/** @module @category UI */
|
|
2
|
-
import { useCallback, useMemo, useState } from
|
|
2
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
3
3
|
|
|
4
4
|
const defaultResultsPerPage = 10;
|
|
5
5
|
|
|
6
|
-
export function usePagination<T>(
|
|
7
|
-
data: Array<T> = [],
|
|
8
|
-
resultsPerPage = defaultResultsPerPage
|
|
9
|
-
) {
|
|
6
|
+
export function usePagination<T>(data: Array<T> = [], resultsPerPage = defaultResultsPerPage) {
|
|
10
7
|
const [page, setPage] = useState(1);
|
|
11
8
|
const totalPages = useMemo(
|
|
12
9
|
() =>
|
|
13
|
-
typeof resultsPerPage ===
|
|
10
|
+
typeof resultsPerPage === 'number' && resultsPerPage > 0
|
|
14
11
|
? Math.max(1, Math.ceil(data.length / resultsPerPage))
|
|
15
12
|
: 1,
|
|
16
|
-
[data.length, resultsPerPage]
|
|
13
|
+
[data.length, resultsPerPage],
|
|
17
14
|
);
|
|
18
15
|
|
|
19
16
|
const results = useMemo(() => {
|
|
@@ -26,7 +23,7 @@ export function usePagination<T>(
|
|
|
26
23
|
(page: number) => {
|
|
27
24
|
setPage(Math.max(1, Math.min(totalPages, page)));
|
|
28
25
|
},
|
|
29
|
-
[setPage, totalPages]
|
|
26
|
+
[setPage, totalPages],
|
|
30
27
|
);
|
|
31
28
|
const goToNext = useCallback(() => {
|
|
32
29
|
if (page < totalPages) {
|
|
@@ -52,16 +49,7 @@ export function usePagination<T>(
|
|
|
52
49
|
goToNext,
|
|
53
50
|
goToPrevious,
|
|
54
51
|
}),
|
|
55
|
-
[
|
|
56
|
-
results,
|
|
57
|
-
totalPages,
|
|
58
|
-
data.length,
|
|
59
|
-
resultsPerPage,
|
|
60
|
-
page,
|
|
61
|
-
goTo,
|
|
62
|
-
goToNext,
|
|
63
|
-
goToPrevious,
|
|
64
|
-
]
|
|
52
|
+
[results, totalPages, data.length, resultsPerPage, page, goTo, goToNext, goToPrevious],
|
|
65
53
|
);
|
|
66
54
|
|
|
67
55
|
return memoisedPaginatedData;
|
package/src/usePatient.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @module @category API */
|
|
2
|
-
import { useEffect, useReducer } from
|
|
3
|
-
import { fetchCurrentPatient, PatientUuid } from
|
|
2
|
+
import { useEffect, useReducer } from 'react';
|
|
3
|
+
import { fetchCurrentPatient, PatientUuid } from '@openmrs/esm-api';
|
|
4
4
|
|
|
5
5
|
export type NullablePatient = fhir.Patient | null;
|
|
6
6
|
|
|
@@ -30,9 +30,9 @@ interface PatientLoadError {
|
|
|
30
30
|
type Action = LoadPatient | NewPatient | PatientLoadError;
|
|
31
31
|
|
|
32
32
|
enum ActionTypes {
|
|
33
|
-
loadPatient =
|
|
34
|
-
newPatient =
|
|
35
|
-
loadError =
|
|
33
|
+
loadPatient = 'loadPatient',
|
|
34
|
+
newPatient = 'newPatient',
|
|
35
|
+
loadError = 'patientLoadError',
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
const initialState: CurrentPatientState = {
|
|
@@ -48,10 +48,7 @@ function getPatientUuidFromUrl(): PatientUuid {
|
|
|
48
48
|
return match && match[1];
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
function reducer(
|
|
52
|
-
state: CurrentPatientState,
|
|
53
|
-
action: Action
|
|
54
|
-
): CurrentPatientState {
|
|
51
|
+
function reducer(state: CurrentPatientState, action: Action): CurrentPatientState {
|
|
55
52
|
switch (action.type) {
|
|
56
53
|
case ActionTypes.loadPatient:
|
|
57
54
|
return {
|
|
@@ -124,7 +121,7 @@ export function usePatient(patientUuid?: string) {
|
|
|
124
121
|
dispatch({
|
|
125
122
|
err,
|
|
126
123
|
type: ActionTypes.loadError,
|
|
127
|
-
})
|
|
124
|
+
}),
|
|
128
125
|
);
|
|
129
126
|
}
|
|
130
127
|
return () => {
|
|
@@ -142,9 +139,8 @@ export function usePatient(patientUuid?: string) {
|
|
|
142
139
|
});
|
|
143
140
|
}
|
|
144
141
|
};
|
|
145
|
-
window.addEventListener(
|
|
146
|
-
return () =>
|
|
147
|
-
window.removeEventListener("single-spa:routing-event", handleRouteUpdate);
|
|
142
|
+
window.addEventListener('single-spa:routing-event', handleRouteUpdate);
|
|
143
|
+
return () => window.removeEventListener('single-spa:routing-event', handleRouteUpdate);
|
|
148
144
|
}, [state.patientUuid]);
|
|
149
145
|
|
|
150
146
|
return {
|