@trackunit/react-core-hooks 1.12.43 → 1.12.44-alpha-57a40ea11fa.0

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/index.cjs.js CHANGED
@@ -379,64 +379,76 @@ const useModalDialogContext = () => {
379
379
  return modalDialogContext;
380
380
  };
381
381
 
382
- const isMultipleCriteriaOneOf = (options) => {
383
- return typeof options === "object" && "oneOf" in options;
384
- };
385
- const isMultipleCriteriaRequireAll = (options) => {
386
- return typeof options === "object" && "requireAll" in options;
382
+ const isMultipleCriteriaOneOf = (options) => typeof options === "object" && "oneOf" in options;
383
+ const isMultipleCriteriaRequireAll = (options) => typeof options === "object" && "requireAll" in options;
384
+ const resolveAccess = async (context, options) => {
385
+ if (isMultipleCriteriaOneOf(options) && isMultipleCriteriaRequireAll(options)) {
386
+ throw new Error("Multiple criteria are not allowed, use one of or require all - not both");
387
+ }
388
+ if (isMultipleCriteriaOneOf(options)) {
389
+ const results = await Promise.all(options.oneOf.map(option => context.hasAccessTo(option)));
390
+ return results.some(Boolean);
391
+ }
392
+ if (isMultipleCriteriaRequireAll(options)) {
393
+ const results = await Promise.all(options.requireAll.map(option => context.hasAccessTo(option)));
394
+ return results.every(Boolean);
395
+ }
396
+ return context.hasAccessTo(options);
387
397
  };
388
398
  /**
389
- * This is a hook to use the hasAccessTo in host.
390
- * You can use this to ensure the page you link to is available for the user to see.
399
+ * Hook to check if the current user has access to a navigation target.
400
+ * Useful for conditionally rendering links based on user permissions.
391
401
  *
392
402
  * @requires NavigationContext
393
403
  * @example
394
404
  * import { useHasAccessTo } from "@trackunit/react-core-hooks";
395
405
  * useHasAccessTo({ assetId: assetInfo?.assetId, page: "movement" })
396
- * @see (@link NavigationRuntimeApi)
397
- * @see (@link HasAccessToOptions)
398
- * @see (@link HasAccessToOptions.assetId)
399
- * @see (@link HasAccessToOptions.page)
400
- * @see (@link HasAccessToOptions.siteId)
401
- * @see (@link NavigationRuntimeApi)
406
+ * @see {@link NavigationRuntimeApi}
407
+ * @see {@link HasAccessToOptions}
402
408
  */
403
409
  const useHasAccessTo = (options) => {
404
410
  const context = react.useContext(reactCoreContextsApi.NavigationContext);
405
- if (!context) {
406
- throw new Error("useHasAccessTo must be used within an NavigationContext");
407
- }
411
+ const [stableOptions, setStableOptions] = react.useState(options);
408
412
  const [hasAccess, setHasAccess] = react.useState();
409
413
  const [loading, setLoading] = react.useState(true);
410
414
  const [error, setError] = react.useState();
415
+ if (JSON.stringify(stableOptions) !== JSON.stringify(options)) {
416
+ setStableOptions(options);
417
+ }
411
418
  react.useEffect(() => {
412
- async function checkAccess() {
419
+ if (!context)
420
+ return;
421
+ let cancelled = false;
422
+ setLoading(true);
423
+ setError(undefined);
424
+ const checkAccess = async () => {
413
425
  try {
414
- if (isMultipleCriteriaOneOf(options) && isMultipleCriteriaRequireAll(options)) {
415
- throw new Error("Multiple criteria are not allowed, use one of or require all - not both");
416
- }
417
- if (isMultipleCriteriaOneOf(options)) {
418
- const doHaveAccess = await Promise.all(options.oneOf.map(option => context?.hasAccessTo(option)));
419
- setHasAccess(doHaveAccess.some(access => access));
420
- }
421
- else if (isMultipleCriteriaRequireAll(options)) {
422
- const doHaveAccess = await Promise.all(options.requireAll.map(option => context?.hasAccessTo(option)));
423
- setHasAccess(doHaveAccess.every(access => access));
424
- }
425
- else {
426
- const doHaveAccess = await context?.hasAccessTo(options);
427
- setHasAccess(doHaveAccess);
426
+ const accessResult = await resolveAccess(context, stableOptions);
427
+ if (!cancelled) {
428
+ setHasAccess(accessResult);
428
429
  }
429
430
  }
430
431
  catch (e) {
431
- setError(new Error("Failed to check access", { cause: e }));
432
+ if (!cancelled) {
433
+ setError(new Error("Failed to check access", { cause: e }));
434
+ }
432
435
  }
433
436
  finally {
434
- setLoading(false);
437
+ if (!cancelled) {
438
+ setLoading(false);
439
+ }
435
440
  }
436
- }
441
+ };
437
442
  void checkAccess();
438
- }, [context, options]);
439
- return react.useMemo(() => ({ hasAccess, loading, error }), [hasAccess, loading, error]);
443
+ return () => {
444
+ cancelled = true;
445
+ };
446
+ }, [context, stableOptions]);
447
+ const result = react.useMemo(() => ({ hasAccess, loading, error }), [hasAccess, loading, error]);
448
+ if (!context) {
449
+ throw new Error("useHasAccessTo must be used within a NavigationContext");
450
+ }
451
+ return result;
440
452
  };
441
453
 
442
454
  /**
package/index.esm.js CHANGED
@@ -377,64 +377,76 @@ const useModalDialogContext = () => {
377
377
  return modalDialogContext;
378
378
  };
379
379
 
380
- const isMultipleCriteriaOneOf = (options) => {
381
- return typeof options === "object" && "oneOf" in options;
382
- };
383
- const isMultipleCriteriaRequireAll = (options) => {
384
- return typeof options === "object" && "requireAll" in options;
380
+ const isMultipleCriteriaOneOf = (options) => typeof options === "object" && "oneOf" in options;
381
+ const isMultipleCriteriaRequireAll = (options) => typeof options === "object" && "requireAll" in options;
382
+ const resolveAccess = async (context, options) => {
383
+ if (isMultipleCriteriaOneOf(options) && isMultipleCriteriaRequireAll(options)) {
384
+ throw new Error("Multiple criteria are not allowed, use one of or require all - not both");
385
+ }
386
+ if (isMultipleCriteriaOneOf(options)) {
387
+ const results = await Promise.all(options.oneOf.map(option => context.hasAccessTo(option)));
388
+ return results.some(Boolean);
389
+ }
390
+ if (isMultipleCriteriaRequireAll(options)) {
391
+ const results = await Promise.all(options.requireAll.map(option => context.hasAccessTo(option)));
392
+ return results.every(Boolean);
393
+ }
394
+ return context.hasAccessTo(options);
385
395
  };
386
396
  /**
387
- * This is a hook to use the hasAccessTo in host.
388
- * You can use this to ensure the page you link to is available for the user to see.
397
+ * Hook to check if the current user has access to a navigation target.
398
+ * Useful for conditionally rendering links based on user permissions.
389
399
  *
390
400
  * @requires NavigationContext
391
401
  * @example
392
402
  * import { useHasAccessTo } from "@trackunit/react-core-hooks";
393
403
  * useHasAccessTo({ assetId: assetInfo?.assetId, page: "movement" })
394
- * @see (@link NavigationRuntimeApi)
395
- * @see (@link HasAccessToOptions)
396
- * @see (@link HasAccessToOptions.assetId)
397
- * @see (@link HasAccessToOptions.page)
398
- * @see (@link HasAccessToOptions.siteId)
399
- * @see (@link NavigationRuntimeApi)
404
+ * @see {@link NavigationRuntimeApi}
405
+ * @see {@link HasAccessToOptions}
400
406
  */
401
407
  const useHasAccessTo = (options) => {
402
408
  const context = useContext(NavigationContext);
403
- if (!context) {
404
- throw new Error("useHasAccessTo must be used within an NavigationContext");
405
- }
409
+ const [stableOptions, setStableOptions] = useState(options);
406
410
  const [hasAccess, setHasAccess] = useState();
407
411
  const [loading, setLoading] = useState(true);
408
412
  const [error, setError] = useState();
413
+ if (JSON.stringify(stableOptions) !== JSON.stringify(options)) {
414
+ setStableOptions(options);
415
+ }
409
416
  useEffect(() => {
410
- async function checkAccess() {
417
+ if (!context)
418
+ return;
419
+ let cancelled = false;
420
+ setLoading(true);
421
+ setError(undefined);
422
+ const checkAccess = async () => {
411
423
  try {
412
- if (isMultipleCriteriaOneOf(options) && isMultipleCriteriaRequireAll(options)) {
413
- throw new Error("Multiple criteria are not allowed, use one of or require all - not both");
414
- }
415
- if (isMultipleCriteriaOneOf(options)) {
416
- const doHaveAccess = await Promise.all(options.oneOf.map(option => context?.hasAccessTo(option)));
417
- setHasAccess(doHaveAccess.some(access => access));
418
- }
419
- else if (isMultipleCriteriaRequireAll(options)) {
420
- const doHaveAccess = await Promise.all(options.requireAll.map(option => context?.hasAccessTo(option)));
421
- setHasAccess(doHaveAccess.every(access => access));
422
- }
423
- else {
424
- const doHaveAccess = await context?.hasAccessTo(options);
425
- setHasAccess(doHaveAccess);
424
+ const accessResult = await resolveAccess(context, stableOptions);
425
+ if (!cancelled) {
426
+ setHasAccess(accessResult);
426
427
  }
427
428
  }
428
429
  catch (e) {
429
- setError(new Error("Failed to check access", { cause: e }));
430
+ if (!cancelled) {
431
+ setError(new Error("Failed to check access", { cause: e }));
432
+ }
430
433
  }
431
434
  finally {
432
- setLoading(false);
435
+ if (!cancelled) {
436
+ setLoading(false);
437
+ }
433
438
  }
434
- }
439
+ };
435
440
  void checkAccess();
436
- }, [context, options]);
437
- return useMemo(() => ({ hasAccess, loading, error }), [hasAccess, loading, error]);
441
+ return () => {
442
+ cancelled = true;
443
+ };
444
+ }, [context, stableOptions]);
445
+ const result = useMemo(() => ({ hasAccess, loading, error }), [hasAccess, loading, error]);
446
+ if (!context) {
447
+ throw new Error("useHasAccessTo must be used within a NavigationContext");
448
+ }
449
+ return result;
438
450
  };
439
451
 
440
452
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/react-core-hooks",
3
- "version": "1.12.43",
3
+ "version": "1.12.44-alpha-57a40ea11fa.0",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "engines": {
@@ -8,9 +8,9 @@
8
8
  },
9
9
  "dependencies": {
10
10
  "react": "19.0.0",
11
- "@trackunit/iris-app-runtime-core": "1.13.41",
12
- "@trackunit/iris-app-runtime-core-api": "1.12.39",
13
- "@trackunit/react-core-contexts-api": "1.13.39"
11
+ "@trackunit/iris-app-runtime-core": "1.13.42-alpha-57a40ea11fa.0",
12
+ "@trackunit/iris-app-runtime-core-api": "1.12.40-alpha-57a40ea11fa.0",
13
+ "@trackunit/react-core-contexts-api": "1.13.40-alpha-57a40ea11fa.0"
14
14
  },
15
15
  "module": "./index.esm.js",
16
16
  "main": "./index.cjs.js",
@@ -1,27 +1,26 @@
1
- import { HasAccessToOptions } from "@trackunit/iris-app-runtime-core-api";
2
- export interface MultipleCriteriaOneOf {
3
- oneOf: Array<HasAccessToOptions>;
4
- }
5
- export interface MultipleCriteriaRequireAll {
6
- requireAll: Array<HasAccessToOptions>;
7
- }
1
+ import type { HasAccessToOptions } from "@trackunit/iris-app-runtime-core-api";
2
+ export type MultipleCriteriaOneOf = {
3
+ readonly oneOf: Array<HasAccessToOptions>;
4
+ };
5
+ export type MultipleCriteriaRequireAll = {
6
+ readonly requireAll: Array<HasAccessToOptions>;
7
+ };
8
+ type AccessOptions = HasAccessToOptions | MultipleCriteriaOneOf | MultipleCriteriaRequireAll;
9
+ type UseHasAccessToResult = {
10
+ readonly hasAccess: boolean | undefined;
11
+ readonly loading: boolean;
12
+ readonly error: Error | undefined;
13
+ };
8
14
  /**
9
- * This is a hook to use the hasAccessTo in host.
10
- * You can use this to ensure the page you link to is available for the user to see.
15
+ * Hook to check if the current user has access to a navigation target.
16
+ * Useful for conditionally rendering links based on user permissions.
11
17
  *
12
18
  * @requires NavigationContext
13
19
  * @example
14
20
  * import { useHasAccessTo } from "@trackunit/react-core-hooks";
15
21
  * useHasAccessTo({ assetId: assetInfo?.assetId, page: "movement" })
16
- * @see (@link NavigationRuntimeApi)
17
- * @see (@link HasAccessToOptions)
18
- * @see (@link HasAccessToOptions.assetId)
19
- * @see (@link HasAccessToOptions.page)
20
- * @see (@link HasAccessToOptions.siteId)
21
- * @see (@link NavigationRuntimeApi)
22
+ * @see {@link NavigationRuntimeApi}
23
+ * @see {@link HasAccessToOptions}
22
24
  */
23
- export declare const useHasAccessTo: (options: HasAccessToOptions | MultipleCriteriaOneOf | MultipleCriteriaRequireAll) => {
24
- hasAccess: boolean | undefined;
25
- loading: boolean;
26
- error: Error | undefined;
27
- };
25
+ export declare const useHasAccessTo: (options: AccessOptions) => UseHasAccessToResult;
26
+ export {};