@openmrs/esm-react-utils 10.0.1-pre.5542 → 10.0.1-pre.5561
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 +1 -1
- package/dist/UserHasAccess.d.ts.map +1 -1
- package/dist/UserHasAccess.js +10 -5
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/public.d.ts +0 -1
- package/dist/public.d.ts.map +1 -1
- package/dist/public.js +0 -1
- package/dist/useLocations.d.ts.map +1 -1
- package/dist/useLocations.js +16 -15
- package/dist/useVisitTypes.d.ts +0 -1
- package/dist/useVisitTypes.d.ts.map +1 -1
- package/dist/useVisitTypes.js +5 -10
- package/mock-jest.tsx +0 -2
- package/mock.tsx +0 -2
- package/package.json +23 -25
- package/src/UserHasAccess.test.tsx +62 -46
- package/src/UserHasAccess.tsx +10 -5
- package/src/index.ts +0 -1
- package/src/public.ts +0 -1
- package/src/useLocations.tsx +16 -15
- package/src/useVisitTypes.ts +6 -16
- package/dist/useConnectivity.d.ts +0 -18
- package/dist/useConnectivity.d.ts.map +0 -1
- package/dist/useConnectivity.js +0 -23
- package/src/useConnectivity.ts +0 -28
package/.turbo/turbo-build.log
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserHasAccess.d.ts","sourceRoot":"","sources":["../src/UserHasAccess.tsx"],"names":[],"mappings":"AAGA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAEnD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC7B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,
|
|
1
|
+
{"version":3,"file":"UserHasAccess.d.ts","sourceRoot":"","sources":["../src/UserHasAccess.tsx"],"names":[],"mappings":"AAGA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAEnD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC7B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAoBtD,CAAC"}
|
package/dist/UserHasAccess.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @module @category API */ import {
|
|
1
|
+
/** @module @category API */ import { getSessionStore, userHasAccess } from "@openmrs/esm-api";
|
|
2
2
|
import React, { useEffect, useState } from "react";
|
|
3
3
|
/**
|
|
4
4
|
* A React component that renders its children only if the current user exists and has the privilege(s)
|
|
@@ -30,10 +30,15 @@ import React, { useEffect, useState } from "react";
|
|
|
30
30
|
*/ export const UserHasAccess = ({ privilege, fallback, children })=>{
|
|
31
31
|
const [user, setUser] = useState(null);
|
|
32
32
|
useEffect(()=>{
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
const store = getSessionStore();
|
|
34
|
+
const unsubscribe = store.subscribe(({ loaded, session })=>{
|
|
35
|
+
setUser(loaded ? session?.user ?? null : null);
|
|
36
|
+
});
|
|
37
|
+
const { loaded, session } = store.getState();
|
|
38
|
+
if (loaded) {
|
|
39
|
+
setUser(session?.user ?? null);
|
|
40
|
+
}
|
|
41
|
+
return unsubscribe;
|
|
37
42
|
}, []);
|
|
38
43
|
if (user && userHasAccess(privilege, user)) {
|
|
39
44
|
return /*#__PURE__*/ React.createElement(React.Fragment, null, children);
|
package/dist/index.d.ts
CHANGED
|
@@ -16,7 +16,6 @@ export * from './useAttachments';
|
|
|
16
16
|
export * from './useBodyScrollLock';
|
|
17
17
|
export * from './useConfig';
|
|
18
18
|
export * from './useConnectedExtensions';
|
|
19
|
-
export * from './useConnectivity';
|
|
20
19
|
export * from './useDebounce';
|
|
21
20
|
export * from './useDefineAppContext';
|
|
22
21
|
export * from './useEmrConfiguration';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,kBAAkB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACzF,OAAO,EAAE,oBAAoB,EAAE,KAAK,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAC/F,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC;AAC7B,cAAc,gCAAgC,CAAC;AAC/C,cAAc,2BAA2B,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,6 @@ export * from "./useAttachments.js";
|
|
|
16
16
|
export * from "./useBodyScrollLock.js";
|
|
17
17
|
export * from "./useConfig.js";
|
|
18
18
|
export * from "./useConnectedExtensions.js";
|
|
19
|
-
export * from "./useConnectivity.js";
|
|
20
19
|
export * from "./useDebounce.js";
|
|
21
20
|
export * from "./useDefineAppContext.js";
|
|
22
21
|
export * from "./useEmrConfiguration.js";
|
package/dist/public.d.ts
CHANGED
|
@@ -12,7 +12,6 @@ export * from './useAttachments';
|
|
|
12
12
|
export * from './useBodyScrollLock';
|
|
13
13
|
export * from './useConfig';
|
|
14
14
|
export * from './useConnectedExtensions';
|
|
15
|
-
export * from './useConnectivity';
|
|
16
15
|
export * from './useDebounce';
|
|
17
16
|
export * from './useDefineAppContext';
|
|
18
17
|
export * from './useEmrConfiguration';
|
package/dist/public.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../src/public.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../src/public.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,kBAAkB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACzF,OAAO,EAAE,oBAAoB,EAAE,KAAK,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAC/F,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC;AAC7B,cAAc,gCAAgC,CAAC;AAC/C,cAAc,2BAA2B,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC"}
|
package/dist/public.js
CHANGED
|
@@ -12,7 +12,6 @@ export * from "./useAttachments.js";
|
|
|
12
12
|
export * from "./useBodyScrollLock.js";
|
|
13
13
|
export * from "./useConfig.js";
|
|
14
14
|
export * from "./useConnectedExtensions.js";
|
|
15
|
-
export * from "./useConnectivity.js";
|
|
16
15
|
export * from "./useDebounce.js";
|
|
17
16
|
export * from "./useDefineAppContext.js";
|
|
18
17
|
export * from "./useEmrConfiguration.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLocations.d.ts","sourceRoot":"","sources":["../src/useLocations.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"useLocations.d.ts","sourceRoot":"","sources":["../src/useLocations.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAKrD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,YAAY,CAAC,aAAa,GAAE,MAAM,GAAG,IAAW,EAAE,KAAK,GAAE,MAAM,GAAG,IAAW,GAAG,KAAK,CAAC,QAAQ,CAAC,CAc9G"}
|
package/dist/useLocations.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
/** @module @category API */ import {
|
|
2
|
-
import {
|
|
1
|
+
/** @module @category API */ import { restBaseUrl } from "@openmrs/esm-api";
|
|
2
|
+
import { useOpenmrsFetchAll } from "./useOpenmrsFetchAll.js";
|
|
3
|
+
const noLocations = [];
|
|
3
4
|
/**
|
|
4
5
|
* A React hook that fetches and returns locations from the OpenMRS server.
|
|
5
6
|
* Locations can be filtered by a tag UUID/name and/or a search query string.
|
|
@@ -24,17 +25,17 @@ import { getLocations } from "@openmrs/esm-emr-api";
|
|
|
24
25
|
* }
|
|
25
26
|
* ```
|
|
26
27
|
*/ export function useLocations(tagUuidOrName = null, query = null) {
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return
|
|
28
|
+
const params = new URLSearchParams();
|
|
29
|
+
if (tagUuidOrName) {
|
|
30
|
+
params.set('tag', tagUuidOrName);
|
|
31
|
+
}
|
|
32
|
+
if (query) {
|
|
33
|
+
params.set('q', query);
|
|
34
|
+
}
|
|
35
|
+
const queryString = params.toString();
|
|
36
|
+
const url = `${restBaseUrl}/location${queryString ? '?' + queryString : ''}`;
|
|
37
|
+
const { data } = useOpenmrsFetchAll(url, {
|
|
38
|
+
immutable: true
|
|
39
|
+
});
|
|
40
|
+
return data ?? noLocations;
|
|
40
41
|
}
|
package/dist/useVisitTypes.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useVisitTypes.d.ts","sourceRoot":"","sources":["../src/useVisitTypes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useVisitTypes.d.ts","sourceRoot":"","sources":["../src/useVisitTypes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgC,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAIpF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,aAAa,gBAG5B"}
|
package/dist/useVisitTypes.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
/** @module @category API */ import
|
|
2
|
-
import {
|
|
1
|
+
/** @module @category API */ import useSWRImmutable from "swr/immutable";
|
|
2
|
+
import { getVisitTypes, visitTypesUrl } from "@openmrs/esm-emr-api";
|
|
3
|
+
const noVisitTypes = [];
|
|
3
4
|
/**
|
|
4
5
|
* A React hook that fetches and returns all available visit types from the
|
|
5
6
|
* OpenMRS server. The data is fetched once when the component mounts.
|
|
@@ -22,12 +23,6 @@ import { useEffect, useState } from "react";
|
|
|
22
23
|
* }
|
|
23
24
|
* ```
|
|
24
25
|
*/ export function useVisitTypes() {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
const visitTypesSub = getVisitTypes().subscribe((visitTypes)=>{
|
|
28
|
-
setVisitTypes(visitTypes);
|
|
29
|
-
}, (error)=>console.error(error));
|
|
30
|
-
return ()=>visitTypesSub.unsubscribe();
|
|
31
|
-
}, []);
|
|
32
|
-
return visitTypes;
|
|
26
|
+
const { data } = useSWRImmutable(visitTypesUrl, getVisitTypes);
|
|
27
|
+
return data ?? noVisitTypes;
|
|
33
28
|
}
|
package/mock-jest.tsx
CHANGED
|
@@ -142,8 +142,6 @@ export const useAppContext = jest.fn();
|
|
|
142
142
|
|
|
143
143
|
export const useAssignedExtensionIds = jest.fn();
|
|
144
144
|
|
|
145
|
-
export const useConnectivity = jest.fn();
|
|
146
|
-
|
|
147
145
|
export const useDefineAppContext = jest.fn();
|
|
148
146
|
|
|
149
147
|
export const useExtensionSlot = jest.fn();
|
package/mock.tsx
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmrs/esm-react-utils",
|
|
3
|
-
"version": "10.0.1-pre.
|
|
3
|
+
"version": "10.0.1-pre.5561",
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
5
|
"description": "React utilities for OpenMRS.",
|
|
6
6
|
"type": "module",
|
|
@@ -60,37 +60,36 @@
|
|
|
60
60
|
"single-spa-react": "^6.0.2"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
|
-
"@openmrs/esm-api": "^10.0.1-pre.
|
|
64
|
-
"@openmrs/esm-config": "^10.0.1-pre.
|
|
65
|
-
"@openmrs/esm-context": "^10.0.1-pre.
|
|
66
|
-
"@openmrs/esm-emr-api": "^10.0.1-pre.
|
|
67
|
-
"@openmrs/esm-error-handling": "^10.0.1-pre.
|
|
68
|
-
"@openmrs/esm-extensions": "^10.0.1-pre.
|
|
69
|
-
"@openmrs/esm-feature-flags": "^10.0.1-pre.
|
|
70
|
-
"@openmrs/esm-globals": "^10.0.1-pre.
|
|
71
|
-
"@openmrs/esm-navigation": "^10.0.1-pre.
|
|
72
|
-
"@openmrs/esm-state": "^10.0.1-pre.
|
|
73
|
-
"@openmrs/esm-utils": "^10.0.1-pre.
|
|
63
|
+
"@openmrs/esm-api": "^10.0.1-pre.5561",
|
|
64
|
+
"@openmrs/esm-config": "^10.0.1-pre.5561",
|
|
65
|
+
"@openmrs/esm-context": "^10.0.1-pre.5561",
|
|
66
|
+
"@openmrs/esm-emr-api": "^10.0.1-pre.5561",
|
|
67
|
+
"@openmrs/esm-error-handling": "^10.0.1-pre.5561",
|
|
68
|
+
"@openmrs/esm-extensions": "^10.0.1-pre.5561",
|
|
69
|
+
"@openmrs/esm-feature-flags": "^10.0.1-pre.5561",
|
|
70
|
+
"@openmrs/esm-globals": "^10.0.1-pre.5561",
|
|
71
|
+
"@openmrs/esm-navigation": "^10.0.1-pre.5561",
|
|
72
|
+
"@openmrs/esm-state": "^10.0.1-pre.5561",
|
|
73
|
+
"@openmrs/esm-utils": "^10.0.1-pre.5561",
|
|
74
74
|
"dayjs": "1.x",
|
|
75
75
|
"i18next": "25.x",
|
|
76
76
|
"react": "18.x",
|
|
77
77
|
"react-dom": "18.x",
|
|
78
78
|
"react-i18next": "16.x",
|
|
79
|
-
"rxjs": "6.x",
|
|
80
79
|
"swr": "2.x"
|
|
81
80
|
},
|
|
82
81
|
"devDependencies": {
|
|
83
|
-
"@openmrs/esm-api": "10.0.1-pre.
|
|
84
|
-
"@openmrs/esm-config": "10.0.1-pre.
|
|
85
|
-
"@openmrs/esm-context": "10.0.1-pre.
|
|
86
|
-
"@openmrs/esm-emr-api": "10.0.1-pre.
|
|
87
|
-
"@openmrs/esm-error-handling": "10.0.1-pre.
|
|
88
|
-
"@openmrs/esm-extensions": "10.0.1-pre.
|
|
89
|
-
"@openmrs/esm-feature-flags": "10.0.1-pre.
|
|
90
|
-
"@openmrs/esm-globals": "10.0.1-pre.
|
|
91
|
-
"@openmrs/esm-navigation": "10.0.1-pre.
|
|
92
|
-
"@openmrs/esm-state": "10.0.1-pre.
|
|
93
|
-
"@openmrs/esm-utils": "10.0.1-pre.
|
|
82
|
+
"@openmrs/esm-api": "10.0.1-pre.5561",
|
|
83
|
+
"@openmrs/esm-config": "10.0.1-pre.5561",
|
|
84
|
+
"@openmrs/esm-context": "10.0.1-pre.5561",
|
|
85
|
+
"@openmrs/esm-emr-api": "10.0.1-pre.5561",
|
|
86
|
+
"@openmrs/esm-error-handling": "10.0.1-pre.5561",
|
|
87
|
+
"@openmrs/esm-extensions": "10.0.1-pre.5561",
|
|
88
|
+
"@openmrs/esm-feature-flags": "10.0.1-pre.5561",
|
|
89
|
+
"@openmrs/esm-globals": "10.0.1-pre.5561",
|
|
90
|
+
"@openmrs/esm-navigation": "10.0.1-pre.5561",
|
|
91
|
+
"@openmrs/esm-state": "10.0.1-pre.5561",
|
|
92
|
+
"@openmrs/esm-utils": "10.0.1-pre.5561",
|
|
94
93
|
"@swc/cli": "0.8.1",
|
|
95
94
|
"@swc/core": "1.15.21",
|
|
96
95
|
"@vitest/coverage-v8": "^4.1.2",
|
|
@@ -103,7 +102,6 @@
|
|
|
103
102
|
"react-dom": "^18.3.1",
|
|
104
103
|
"react-i18next": "^16.0.0",
|
|
105
104
|
"rimraf": "^6.1.3",
|
|
106
|
-
"rxjs": "^6.5.3",
|
|
107
105
|
"swr": "2.5.1",
|
|
108
106
|
"vitest": "^4.1.2"
|
|
109
107
|
},
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
2
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
3
3
|
import React from 'react';
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import type { LoggedInUser, Privilege, Role } from '@openmrs/esm-api';
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
|
6
|
+
import { getSessionStore, userHasAccess } from '@openmrs/esm-api';
|
|
6
7
|
import { UserHasAccess } from './UserHasAccess';
|
|
7
8
|
|
|
8
|
-
// Mock
|
|
9
|
-
const
|
|
9
|
+
// Mock getSessionStore and userHasAccess
|
|
10
|
+
const mockGetSessionStore = vi.fn();
|
|
10
11
|
const mockUserHasAccess = vi.fn();
|
|
11
12
|
|
|
12
13
|
vi.mock('@openmrs/esm-api', () => ({
|
|
13
|
-
|
|
14
|
+
getSessionStore: (...args: Parameters<typeof getSessionStore>) => mockGetSessionStore(...args),
|
|
14
15
|
userHasAccess: (...args: Parameters<typeof userHasAccess>) => mockUserHasAccess(...args),
|
|
15
16
|
}));
|
|
16
17
|
|
|
@@ -40,6 +41,37 @@ function createMockUser(privileges: string[] = [], roles: string[] = []): Logged
|
|
|
40
41
|
};
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
type SessionState = { loaded: boolean; session: { authenticated: boolean; sessionId: string; user?: LoggedInUser } };
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Builds a minimal stand-in for the session store {@link UserHasAccess} consumes:
|
|
48
|
+
* `getState()` returns the current state synchronously and `subscribe()` registers
|
|
49
|
+
* a listener and returns an unsubscribe function. `emit()` lets tests push updates.
|
|
50
|
+
*/
|
|
51
|
+
function createFakeStore(user: LoggedInUser | null, unsubscribe: () => void = vi.fn()) {
|
|
52
|
+
const listeners = new Set<(state: SessionState) => void>();
|
|
53
|
+
let state: SessionState = {
|
|
54
|
+
loaded: true,
|
|
55
|
+
session: user ? { authenticated: true, sessionId: 'test-session', user } : { authenticated: false, sessionId: '' },
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
getState: () => state,
|
|
59
|
+
subscribe: vi.fn((listener: (state: SessionState) => void) => {
|
|
60
|
+
listeners.add(listener);
|
|
61
|
+
return unsubscribe;
|
|
62
|
+
}),
|
|
63
|
+
emit(nextUser: LoggedInUser | null) {
|
|
64
|
+
state = {
|
|
65
|
+
loaded: true,
|
|
66
|
+
session: nextUser
|
|
67
|
+
? { authenticated: true, sessionId: 'test-session', user: nextUser }
|
|
68
|
+
: { authenticated: false, sessionId: '' },
|
|
69
|
+
};
|
|
70
|
+
listeners.forEach((listener) => listener(state));
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
43
75
|
describe('UserHasAccess', () => {
|
|
44
76
|
beforeEach(() => {
|
|
45
77
|
vi.clearAllMocks();
|
|
@@ -53,7 +85,7 @@ describe('UserHasAccess', () => {
|
|
|
53
85
|
it('should render children for single privilege', () => {
|
|
54
86
|
const user = createMockUser(['Edit Patients']);
|
|
55
87
|
|
|
56
|
-
|
|
88
|
+
mockGetSessionStore.mockReturnValue(createFakeStore(user));
|
|
57
89
|
mockUserHasAccess.mockReturnValue(true);
|
|
58
90
|
|
|
59
91
|
render(
|
|
@@ -69,7 +101,7 @@ describe('UserHasAccess', () => {
|
|
|
69
101
|
it('should render children for multiple privileges', () => {
|
|
70
102
|
const user = createMockUser(['Edit Patients', 'Delete Patients']);
|
|
71
103
|
|
|
72
|
-
|
|
104
|
+
mockGetSessionStore.mockReturnValue(createFakeStore(user));
|
|
73
105
|
mockUserHasAccess.mockReturnValue(true);
|
|
74
106
|
|
|
75
107
|
render(
|
|
@@ -85,7 +117,7 @@ describe('UserHasAccess', () => {
|
|
|
85
117
|
it('should render multiple children', () => {
|
|
86
118
|
const user = createMockUser(['Edit Patients']);
|
|
87
119
|
|
|
88
|
-
|
|
120
|
+
mockGetSessionStore.mockReturnValue(createFakeStore(user));
|
|
89
121
|
mockUserHasAccess.mockReturnValue(true);
|
|
90
122
|
|
|
91
123
|
render(
|
|
@@ -104,7 +136,7 @@ describe('UserHasAccess', () => {
|
|
|
104
136
|
it('should render nothing when no fallback provided', () => {
|
|
105
137
|
const user = createMockUser(['View Patients']);
|
|
106
138
|
|
|
107
|
-
|
|
139
|
+
mockGetSessionStore.mockReturnValue(createFakeStore(user));
|
|
108
140
|
mockUserHasAccess.mockReturnValue(false);
|
|
109
141
|
|
|
110
142
|
const { container } = render(
|
|
@@ -121,7 +153,7 @@ describe('UserHasAccess', () => {
|
|
|
121
153
|
it('should render fallback when provided', () => {
|
|
122
154
|
const user = createMockUser(['View Patients']);
|
|
123
155
|
|
|
124
|
-
|
|
156
|
+
mockGetSessionStore.mockReturnValue(createFakeStore(user));
|
|
125
157
|
mockUserHasAccess.mockReturnValue(false);
|
|
126
158
|
|
|
127
159
|
render(
|
|
@@ -137,7 +169,7 @@ describe('UserHasAccess', () => {
|
|
|
137
169
|
it('should render fallback for missing privilege in array', () => {
|
|
138
170
|
const user = createMockUser(['Edit Patients']); // Has one but not both
|
|
139
171
|
|
|
140
|
-
|
|
172
|
+
mockGetSessionStore.mockReturnValue(createFakeStore(user));
|
|
141
173
|
mockUserHasAccess.mockReturnValue(false);
|
|
142
174
|
|
|
143
175
|
render(
|
|
@@ -153,7 +185,7 @@ describe('UserHasAccess', () => {
|
|
|
153
185
|
|
|
154
186
|
describe('when user is not logged in', () => {
|
|
155
187
|
it('should render nothing when no fallback provided', () => {
|
|
156
|
-
|
|
188
|
+
mockGetSessionStore.mockReturnValue(createFakeStore(null));
|
|
157
189
|
mockUserHasAccess.mockReturnValue(false);
|
|
158
190
|
|
|
159
191
|
const { container } = render(
|
|
@@ -168,7 +200,7 @@ describe('UserHasAccess', () => {
|
|
|
168
200
|
});
|
|
169
201
|
|
|
170
202
|
it('should render fallback when provided', () => {
|
|
171
|
-
|
|
203
|
+
mockGetSessionStore.mockReturnValue(createFakeStore(null));
|
|
172
204
|
mockUserHasAccess.mockReturnValue(false);
|
|
173
205
|
|
|
174
206
|
render(
|
|
@@ -182,18 +214,12 @@ describe('UserHasAccess', () => {
|
|
|
182
214
|
});
|
|
183
215
|
});
|
|
184
216
|
|
|
185
|
-
describe('
|
|
186
|
-
it('should subscribe to
|
|
217
|
+
describe('session subscription management', () => {
|
|
218
|
+
it('should subscribe to the session store on mount', () => {
|
|
187
219
|
const user = createMockUser(['Edit Patients']);
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
new Observable((subscriber) => {
|
|
192
|
-
subscribeMock();
|
|
193
|
-
subscriber.next(user);
|
|
194
|
-
return () => {};
|
|
195
|
-
}),
|
|
196
|
-
);
|
|
220
|
+
const store = createFakeStore(user);
|
|
221
|
+
|
|
222
|
+
mockGetSessionStore.mockReturnValue(store);
|
|
197
223
|
mockUserHasAccess.mockReturnValue(true);
|
|
198
224
|
|
|
199
225
|
render(
|
|
@@ -202,20 +228,16 @@ describe('UserHasAccess', () => {
|
|
|
202
228
|
</UserHasAccess>,
|
|
203
229
|
);
|
|
204
230
|
|
|
205
|
-
expect(
|
|
206
|
-
expect(
|
|
231
|
+
expect(mockGetSessionStore).toHaveBeenCalled();
|
|
232
|
+
expect(store.subscribe).toHaveBeenCalled();
|
|
207
233
|
});
|
|
208
234
|
|
|
209
|
-
it('should unsubscribe from
|
|
235
|
+
it('should unsubscribe from the session store on unmount', () => {
|
|
210
236
|
const user = createMockUser(['Edit Patients']);
|
|
211
237
|
const unsubscribeMock = vi.fn();
|
|
238
|
+
const store = createFakeStore(user, unsubscribeMock);
|
|
212
239
|
|
|
213
|
-
|
|
214
|
-
new Observable((subscriber) => {
|
|
215
|
-
subscriber.next(user);
|
|
216
|
-
return unsubscribeMock;
|
|
217
|
-
}),
|
|
218
|
-
);
|
|
240
|
+
mockGetSessionStore.mockReturnValue(store);
|
|
219
241
|
mockUserHasAccess.mockReturnValue(true);
|
|
220
242
|
|
|
221
243
|
const { unmount } = render(
|
|
@@ -231,23 +253,17 @@ describe('UserHasAccess', () => {
|
|
|
231
253
|
});
|
|
232
254
|
|
|
233
255
|
describe('user updates', () => {
|
|
234
|
-
it('should update when
|
|
256
|
+
it('should update when the session changes', async () => {
|
|
235
257
|
const user1 = createMockUser(['View Patients']);
|
|
236
258
|
const user2 = createMockUser(['Edit Patients']);
|
|
259
|
+
const store = createFakeStore(user1);
|
|
237
260
|
|
|
238
|
-
|
|
239
|
-
mockGetCurrentUser.mockReturnValue(
|
|
240
|
-
new Observable((sub) => {
|
|
241
|
-
subscriber = sub;
|
|
242
|
-
sub.next(user1);
|
|
243
|
-
return () => {};
|
|
244
|
-
}),
|
|
245
|
-
);
|
|
261
|
+
mockGetSessionStore.mockReturnValue(store);
|
|
246
262
|
|
|
247
263
|
// Initially user doesn't have access
|
|
248
264
|
mockUserHasAccess.mockReturnValue(false);
|
|
249
265
|
|
|
250
|
-
|
|
266
|
+
render(
|
|
251
267
|
<UserHasAccess privilege="Edit Patients" fallback={<div>No Access</div>}>
|
|
252
268
|
<div>Protected Content</div>
|
|
253
269
|
</UserHasAccess>,
|
|
@@ -258,7 +274,7 @@ describe('UserHasAccess', () => {
|
|
|
258
274
|
|
|
259
275
|
// User gains access
|
|
260
276
|
mockUserHasAccess.mockReturnValue(true);
|
|
261
|
-
(
|
|
277
|
+
store.emit(user2);
|
|
262
278
|
|
|
263
279
|
await waitFor(() => {
|
|
264
280
|
expect(screen.queryByText('No Access')).not.toBeInTheDocument();
|
|
@@ -271,7 +287,7 @@ describe('UserHasAccess', () => {
|
|
|
271
287
|
it('should handle empty children gracefully', () => {
|
|
272
288
|
const user = createMockUser(['Edit Patients']);
|
|
273
289
|
|
|
274
|
-
|
|
290
|
+
mockGetSessionStore.mockReturnValue(createFakeStore(user));
|
|
275
291
|
mockUserHasAccess.mockReturnValue(true);
|
|
276
292
|
|
|
277
293
|
const { container } = render(<UserHasAccess privilege="Edit Patients" />);
|
|
@@ -284,7 +300,7 @@ describe('UserHasAccess', () => {
|
|
|
284
300
|
it('should handle complex fallback component', () => {
|
|
285
301
|
const user = createMockUser(['View Patients']);
|
|
286
302
|
|
|
287
|
-
|
|
303
|
+
mockGetSessionStore.mockReturnValue(createFakeStore(user));
|
|
288
304
|
mockUserHasAccess.mockReturnValue(false);
|
|
289
305
|
|
|
290
306
|
render(
|
package/src/UserHasAccess.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @module @category API */
|
|
2
2
|
import type { LoggedInUser } from '@openmrs/esm-api';
|
|
3
|
-
import {
|
|
3
|
+
import { getSessionStore, userHasAccess } from '@openmrs/esm-api';
|
|
4
4
|
import React, { useEffect, useState } from 'react';
|
|
5
5
|
|
|
6
6
|
export interface UserHasAccessProps {
|
|
@@ -41,10 +41,15 @@ export const UserHasAccess: React.FC<UserHasAccessProps> = ({ privilege, fallbac
|
|
|
41
41
|
const [user, setUser] = useState<LoggedInUser | null>(null);
|
|
42
42
|
|
|
43
43
|
useEffect(() => {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
const store = getSessionStore();
|
|
45
|
+
const unsubscribe = store.subscribe(({ loaded, session }) => {
|
|
46
|
+
setUser(loaded ? session?.user ?? null : null);
|
|
47
|
+
});
|
|
48
|
+
const { loaded, session } = store.getState();
|
|
49
|
+
if (loaded) {
|
|
50
|
+
setUser(session?.user ?? null);
|
|
51
|
+
}
|
|
52
|
+
return unsubscribe;
|
|
48
53
|
}, []);
|
|
49
54
|
|
|
50
55
|
if (user && userHasAccess(privilege, user)) {
|
package/src/index.ts
CHANGED
|
@@ -16,7 +16,6 @@ export * from './useAttachments';
|
|
|
16
16
|
export * from './useBodyScrollLock';
|
|
17
17
|
export * from './useConfig';
|
|
18
18
|
export * from './useConnectedExtensions';
|
|
19
|
-
export * from './useConnectivity';
|
|
20
19
|
export * from './useDebounce';
|
|
21
20
|
export * from './useDefineAppContext';
|
|
22
21
|
export * from './useEmrConfiguration';
|
package/src/public.ts
CHANGED
|
@@ -12,7 +12,6 @@ export * from './useAttachments';
|
|
|
12
12
|
export * from './useBodyScrollLock';
|
|
13
13
|
export * from './useConfig';
|
|
14
14
|
export * from './useConnectedExtensions';
|
|
15
|
-
export * from './useConnectivity';
|
|
16
15
|
export * from './useDebounce';
|
|
17
16
|
export * from './useDefineAppContext';
|
|
18
17
|
export * from './useEmrConfiguration';
|
package/src/useLocations.tsx
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/** @module @category API */
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { restBaseUrl } from '@openmrs/esm-api';
|
|
3
|
+
import { type Location } from '@openmrs/esm-emr-api';
|
|
4
|
+
import { useOpenmrsFetchAll } from './useOpenmrsFetchAll';
|
|
5
|
+
|
|
6
|
+
const noLocations: Array<Location> = [];
|
|
4
7
|
|
|
5
8
|
/**
|
|
6
9
|
* A React hook that fetches and returns locations from the OpenMRS server.
|
|
@@ -27,19 +30,17 @@ import { getLocations, type Location } from '@openmrs/esm-emr-api';
|
|
|
27
30
|
* ```
|
|
28
31
|
*/
|
|
29
32
|
export function useLocations(tagUuidOrName: string | null = null, query: string | null = null): Array<Location> {
|
|
30
|
-
const
|
|
33
|
+
const params = new URLSearchParams();
|
|
34
|
+
if (tagUuidOrName) {
|
|
35
|
+
params.set('tag', tagUuidOrName);
|
|
36
|
+
}
|
|
37
|
+
if (query) {
|
|
38
|
+
params.set('q', query);
|
|
39
|
+
}
|
|
40
|
+
const queryString = params.toString();
|
|
31
41
|
|
|
32
|
-
|
|
33
|
-
const locationSub = getLocations(tagUuidOrName, query).subscribe(
|
|
34
|
-
(locations) => {
|
|
35
|
-
setLocations(locations);
|
|
36
|
-
},
|
|
37
|
-
(error) => {
|
|
38
|
-
console.error(error);
|
|
39
|
-
},
|
|
40
|
-
);
|
|
41
|
-
return () => locationSub.unsubscribe();
|
|
42
|
-
}, [tagUuidOrName, query]);
|
|
42
|
+
const url = `${restBaseUrl}/location${queryString ? '?' + queryString : ''}`;
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
const { data } = useOpenmrsFetchAll<Location>(url, { immutable: true });
|
|
45
|
+
return data ?? noLocations;
|
|
45
46
|
}
|
package/src/useVisitTypes.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/** @module @category API */
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
2
|
+
import useSWRImmutable from 'swr/immutable';
|
|
3
|
+
import { getVisitTypes, visitTypesUrl, type VisitType } from '@openmrs/esm-emr-api';
|
|
4
|
+
|
|
5
|
+
const noVisitTypes: Array<VisitType> = [];
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* A React hook that fetches and returns all available visit types from the
|
|
@@ -25,18 +27,6 @@ import { useEffect, useState } from 'react';
|
|
|
25
27
|
* ```
|
|
26
28
|
*/
|
|
27
29
|
export function useVisitTypes() {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
useEffect(() => {
|
|
31
|
-
const visitTypesSub = getVisitTypes().subscribe(
|
|
32
|
-
(visitTypes) => {
|
|
33
|
-
setVisitTypes(visitTypes);
|
|
34
|
-
},
|
|
35
|
-
(error) => console.error(error),
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
return () => visitTypesSub.unsubscribe();
|
|
39
|
-
}, []);
|
|
40
|
-
|
|
41
|
-
return visitTypes;
|
|
30
|
+
const { data } = useSWRImmutable(visitTypesUrl, getVisitTypes);
|
|
31
|
+
return data ?? noVisitTypes;
|
|
42
32
|
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A React hook that returns the current online/offline status and automatically
|
|
3
|
-
* updates when connectivity changes. Useful for showing offline indicators or
|
|
4
|
-
* conditionally rendering UI based on network availability.
|
|
5
|
-
*
|
|
6
|
-
* @returns `true` if the browser is online, `false` if offline.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```tsx
|
|
10
|
-
* import { useConnectivity } from '@openmrs/esm-framework';
|
|
11
|
-
* function NetworkStatus() {
|
|
12
|
-
* const isOnline = useConnectivity();
|
|
13
|
-
* return <span>{isOnline ? 'Online' : 'Offline'}</span>;
|
|
14
|
-
* }
|
|
15
|
-
* ```
|
|
16
|
-
*/
|
|
17
|
-
export declare function useConnectivity(): boolean;
|
|
18
|
-
//# sourceMappingURL=useConnectivity.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useConnectivity.d.ts","sourceRoot":"","sources":["../src/useConnectivity.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,YAM9B"}
|
package/dist/useConnectivity.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/** @module @category Offline */ import { subscribeConnectivityChanged } from "@openmrs/esm-globals";
|
|
2
|
-
import { isOnline as isOnlineFn } from "@openmrs/esm-utils";
|
|
3
|
-
import { useEffect, useState } from "react";
|
|
4
|
-
/**
|
|
5
|
-
* A React hook that returns the current online/offline status and automatically
|
|
6
|
-
* updates when connectivity changes. Useful for showing offline indicators or
|
|
7
|
-
* conditionally rendering UI based on network availability.
|
|
8
|
-
*
|
|
9
|
-
* @returns `true` if the browser is online, `false` if offline.
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```tsx
|
|
13
|
-
* import { useConnectivity } from '@openmrs/esm-framework';
|
|
14
|
-
* function NetworkStatus() {
|
|
15
|
-
* const isOnline = useConnectivity();
|
|
16
|
-
* return <span>{isOnline ? 'Online' : 'Offline'}</span>;
|
|
17
|
-
* }
|
|
18
|
-
* ```
|
|
19
|
-
*/ export function useConnectivity() {
|
|
20
|
-
let [isOnline, setIsOnline] = useState(isOnlineFn());
|
|
21
|
-
useEffect(()=>subscribeConnectivityChanged(({ online })=>setIsOnline(online)), []);
|
|
22
|
-
return isOnline;
|
|
23
|
-
}
|
package/src/useConnectivity.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/** @module @category Offline */
|
|
2
|
-
import { subscribeConnectivityChanged } from '@openmrs/esm-globals';
|
|
3
|
-
import { isOnline as isOnlineFn } from '@openmrs/esm-utils';
|
|
4
|
-
import { useEffect, useState } from 'react';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* A React hook that returns the current online/offline status and automatically
|
|
8
|
-
* updates when connectivity changes. Useful for showing offline indicators or
|
|
9
|
-
* conditionally rendering UI based on network availability.
|
|
10
|
-
*
|
|
11
|
-
* @returns `true` if the browser is online, `false` if offline.
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```tsx
|
|
15
|
-
* import { useConnectivity } from '@openmrs/esm-framework';
|
|
16
|
-
* function NetworkStatus() {
|
|
17
|
-
* const isOnline = useConnectivity();
|
|
18
|
-
* return <span>{isOnline ? 'Online' : 'Offline'}</span>;
|
|
19
|
-
* }
|
|
20
|
-
* ```
|
|
21
|
-
*/
|
|
22
|
-
export function useConnectivity() {
|
|
23
|
-
let [isOnline, setIsOnline] = useState(isOnlineFn());
|
|
24
|
-
|
|
25
|
-
useEffect(() => subscribeConnectivityChanged(({ online }) => setIsOnline(online)), []);
|
|
26
|
-
|
|
27
|
-
return isOnline;
|
|
28
|
-
}
|