@openmrs/esm-react-utils 10.0.1-pre.5542 → 10.0.1-pre.5545

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.
@@ -1,3 +1,3 @@
1
- [0] Successfully compiled: 56 files with swc (199.77ms)
1
+ [0] Successfully compiled: 55 files with swc (164.81ms)
2
2
  [0] swc --strip-leading-paths src -d dist exited with code 0
3
3
  [1] tsc --project tsconfig.build.json exited with code 0
@@ -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,CAetD,CAAC"}
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"}
@@ -1,4 +1,4 @@
1
- /** @module @category API */ import { getCurrentUser, userHasAccess } from "@openmrs/esm-api";
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 subscription = getCurrentUser({
34
- includeAuthStatus: false
35
- }).subscribe(setUser);
36
- return ()=>subscription.unsubscribe();
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';
@@ -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,mBAAmB,CAAC;AAClC,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"}
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';
@@ -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,mBAAmB,CAAC;AAClC,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"}
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,EAAgB,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,YAAY,CAAC,aAAa,GAAE,MAAM,GAAG,IAAW,EAAE,KAAK,GAAE,MAAM,GAAG,IAAW,GAAG,KAAK,CAAC,QAAQ,CAAC,CAgB9G"}
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"}
@@ -1,5 +1,6 @@
1
- /** @module @category API */ import { useState, useEffect } from "react";
2
- import { getLocations } from "@openmrs/esm-emr-api";
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 [locations, setLocations] = useState([]);
28
- useEffect(()=>{
29
- const locationSub = getLocations(tagUuidOrName, query).subscribe((locations)=>{
30
- setLocations(locations);
31
- }, (error)=>{
32
- console.error(error);
33
- });
34
- return ()=>locationSub.unsubscribe();
35
- }, [
36
- tagUuidOrName,
37
- query
38
- ]);
39
- return locations;
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
  }
@@ -1,4 +1,3 @@
1
- /** @module @category API */
2
1
  import { type VisitType } from '@openmrs/esm-emr-api';
3
2
  /**
4
3
  * A React hook that fetches and returns all available visit types from the
@@ -1 +1 @@
1
- {"version":3,"file":"useVisitTypes.d.ts","sourceRoot":"","sources":["../src/useVisitTypes.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAC5B,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGrE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,aAAa,gBAe5B"}
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"}
@@ -1,5 +1,6 @@
1
- /** @module @category API */ import { getVisitTypes } from "@openmrs/esm-emr-api";
2
- import { useEffect, useState } from "react";
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 [visitTypes, setVisitTypes] = useState([]);
26
- useEffect(()=>{
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
@@ -147,8 +147,6 @@ export const useAppContext = vi.fn();
147
147
 
148
148
  export const useAssignedExtensionIds = vi.fn();
149
149
 
150
- export const useConnectivity = vi.fn();
151
-
152
150
  export const useDefineAppContext = vi.fn();
153
151
 
154
152
  export const useExtensionSlot = vi.fn();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-react-utils",
3
- "version": "10.0.1-pre.5542",
3
+ "version": "10.0.1-pre.5545",
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.5542",
64
- "@openmrs/esm-config": "^10.0.1-pre.5542",
65
- "@openmrs/esm-context": "^10.0.1-pre.5542",
66
- "@openmrs/esm-emr-api": "^10.0.1-pre.5542",
67
- "@openmrs/esm-error-handling": "^10.0.1-pre.5542",
68
- "@openmrs/esm-extensions": "^10.0.1-pre.5542",
69
- "@openmrs/esm-feature-flags": "^10.0.1-pre.5542",
70
- "@openmrs/esm-globals": "^10.0.1-pre.5542",
71
- "@openmrs/esm-navigation": "^10.0.1-pre.5542",
72
- "@openmrs/esm-state": "^10.0.1-pre.5542",
73
- "@openmrs/esm-utils": "^10.0.1-pre.5542",
63
+ "@openmrs/esm-api": "^10.0.1-pre.5545",
64
+ "@openmrs/esm-config": "^10.0.1-pre.5545",
65
+ "@openmrs/esm-context": "^10.0.1-pre.5545",
66
+ "@openmrs/esm-emr-api": "^10.0.1-pre.5545",
67
+ "@openmrs/esm-error-handling": "^10.0.1-pre.5545",
68
+ "@openmrs/esm-extensions": "^10.0.1-pre.5545",
69
+ "@openmrs/esm-feature-flags": "^10.0.1-pre.5545",
70
+ "@openmrs/esm-globals": "^10.0.1-pre.5545",
71
+ "@openmrs/esm-navigation": "^10.0.1-pre.5545",
72
+ "@openmrs/esm-state": "^10.0.1-pre.5545",
73
+ "@openmrs/esm-utils": "^10.0.1-pre.5545",
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.5542",
84
- "@openmrs/esm-config": "10.0.1-pre.5542",
85
- "@openmrs/esm-context": "10.0.1-pre.5542",
86
- "@openmrs/esm-emr-api": "10.0.1-pre.5542",
87
- "@openmrs/esm-error-handling": "10.0.1-pre.5542",
88
- "@openmrs/esm-extensions": "10.0.1-pre.5542",
89
- "@openmrs/esm-feature-flags": "10.0.1-pre.5542",
90
- "@openmrs/esm-globals": "10.0.1-pre.5542",
91
- "@openmrs/esm-navigation": "10.0.1-pre.5542",
92
- "@openmrs/esm-state": "10.0.1-pre.5542",
93
- "@openmrs/esm-utils": "10.0.1-pre.5542",
82
+ "@openmrs/esm-api": "10.0.1-pre.5545",
83
+ "@openmrs/esm-config": "10.0.1-pre.5545",
84
+ "@openmrs/esm-context": "10.0.1-pre.5545",
85
+ "@openmrs/esm-emr-api": "10.0.1-pre.5545",
86
+ "@openmrs/esm-error-handling": "10.0.1-pre.5545",
87
+ "@openmrs/esm-extensions": "10.0.1-pre.5545",
88
+ "@openmrs/esm-feature-flags": "10.0.1-pre.5545",
89
+ "@openmrs/esm-globals": "10.0.1-pre.5545",
90
+ "@openmrs/esm-navigation": "10.0.1-pre.5545",
91
+ "@openmrs/esm-state": "10.0.1-pre.5545",
92
+ "@openmrs/esm-utils": "10.0.1-pre.5545",
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 { Observable, type Subscriber } from 'rxjs';
5
- import type { LoggedInUser, Privilege, Role, getCurrentUser, userHasAccess } from '@openmrs/esm-api';
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 getCurrentUser and userHasAccess
9
- const mockGetCurrentUser = vi.fn();
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
- getCurrentUser: (...args: Parameters<typeof getCurrentUser>) => mockGetCurrentUser(...args),
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
- mockGetCurrentUser.mockReturnValue(new Observable((subscriber) => subscriber.next(user)));
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
- mockGetCurrentUser.mockReturnValue(new Observable((subscriber) => subscriber.next(user)));
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
- mockGetCurrentUser.mockReturnValue(new Observable((subscriber) => subscriber.next(user)));
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
- mockGetCurrentUser.mockReturnValue(new Observable((subscriber) => subscriber.next(user)));
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
- mockGetCurrentUser.mockReturnValue(new Observable((subscriber) => subscriber.next(user)));
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
- mockGetCurrentUser.mockReturnValue(new Observable((subscriber) => subscriber.next(user)));
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
- mockGetCurrentUser.mockReturnValue(new Observable((subscriber) => subscriber.next(null)));
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
- mockGetCurrentUser.mockReturnValue(new Observable((subscriber) => subscriber.next(null)));
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('observable subscription management', () => {
186
- it('should subscribe to getCurrentUser on mount', () => {
217
+ describe('session subscription management', () => {
218
+ it('should subscribe to the session store on mount', () => {
187
219
  const user = createMockUser(['Edit Patients']);
188
- const subscribeMock = vi.fn();
189
-
190
- mockGetCurrentUser.mockReturnValue(
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(mockGetCurrentUser).toHaveBeenCalledWith({ includeAuthStatus: false });
206
- expect(subscribeMock).toHaveBeenCalled();
231
+ expect(mockGetSessionStore).toHaveBeenCalled();
232
+ expect(store.subscribe).toHaveBeenCalled();
207
233
  });
208
234
 
209
- it('should unsubscribe from getCurrentUser on unmount', () => {
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
- mockGetCurrentUser.mockReturnValue(
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 user changes', async () => {
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
- let subscriber: Subscriber<unknown> | undefined = undefined;
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
- const { rerender } = render(
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
- (subscriber as unknown as Subscriber<unknown>)?.next(user2);
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
- mockGetCurrentUser.mockReturnValue(new Observable((subscriber) => subscriber.next(user)));
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
- mockGetCurrentUser.mockReturnValue(new Observable((subscriber) => subscriber.next(user)));
303
+ mockGetSessionStore.mockReturnValue(createFakeStore(user));
288
304
  mockUserHasAccess.mockReturnValue(false);
289
305
 
290
306
  render(
@@ -1,6 +1,6 @@
1
1
  /** @module @category API */
2
2
  import type { LoggedInUser } from '@openmrs/esm-api';
3
- import { getCurrentUser, userHasAccess } from '@openmrs/esm-api';
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 subscription = getCurrentUser({
45
- includeAuthStatus: false,
46
- }).subscribe(setUser);
47
- return () => subscription.unsubscribe();
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';
@@ -1,6 +1,9 @@
1
1
  /** @module @category API */
2
- import { useState, useEffect } from 'react';
3
- import { getLocations, type Location } from '@openmrs/esm-emr-api';
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 [locations, setLocations] = useState<Array<Location>>([]);
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
- useEffect(() => {
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
- return locations;
44
+ const { data } = useOpenmrsFetchAll<Location>(url, { immutable: true });
45
+ return data ?? noLocations;
45
46
  }
@@ -1,6 +1,8 @@
1
1
  /** @module @category API */
2
- import { getVisitTypes, type VisitType } from '@openmrs/esm-emr-api';
3
- import { useEffect, useState } from 'react';
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 [visitTypes, setVisitTypes] = useState<Array<VisitType>>([]);
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"}
@@ -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
- }
@@ -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
- }