@trackunit/react-core-hooks 1.3.70 → 1.3.72

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
@@ -377,6 +377,165 @@ const OemBrandingContextProvider = (props) => {
377
377
  return jsxRuntime.jsx(OEMBrandingService.Provider, { ...props });
378
378
  };
379
379
 
380
+ /**
381
+ * The usePrevious hook is a useful tool for tracking the previous value of a variable in a functional component. This can be particularly handy in scenarios where it is necessary to compare the current value with the previous one, such as triggering actions or rendering based on changes.
382
+ *
383
+ * @example
384
+ * const [color, setColor] = React.useState(getRandomColor());
385
+ const previousColor = usePrevious(color);
386
+ */
387
+ const usePrevious = (value) => {
388
+ const ref = react.useRef(undefined);
389
+ react.useEffect(() => {
390
+ ref.current = value;
391
+ }, [value]);
392
+ const wrapper = {
393
+ get previous() {
394
+ return ref.current;
395
+ },
396
+ };
397
+ return wrapper.previous;
398
+ };
399
+
400
+ /**
401
+ * Validates the state object using a Zod schema.
402
+ *
403
+ * @template TState - The type of the state.
404
+ * @param {ValidateStateOptions<TState>} params - The parameters for the validateState function.
405
+ */
406
+ const validateState = ({ state, schema, onValidationFailed, onValidationSuccessful, defaultState, }) => {
407
+ try {
408
+ const parsedState = schema.parse(state);
409
+ onValidationSuccessful?.(parsedState);
410
+ return parsedState;
411
+ }
412
+ catch (error) {
413
+ // eslint-disable-next-line no-console
414
+ console.error("Failed to parse and validate the state from local storage.", error);
415
+ onValidationFailed?.(error);
416
+ return defaultState;
417
+ }
418
+ };
419
+
420
+ /**
421
+ * Initializes the state from local storage, parsing and validating it if a Zod schema is provided.
422
+ *
423
+ * @template TState - The type of the state stored in local storage.
424
+ * @param {Omit<LocalStorageParams<TState>, "state">} params - The parameters for initializing the local storage state.
425
+ * @returns {TState} - The initialized state.
426
+ */
427
+ const initLocalStorageState = ({ key, defaultState, schema, }) => {
428
+ const localStorageItem = localStorage.getItem(key);
429
+ if (!localStorageItem) {
430
+ return defaultState;
431
+ }
432
+ const localStorageItemJSON = JSON.parse(localStorageItem);
433
+ if (!schema) {
434
+ return localStorageItemJSON;
435
+ }
436
+ return validateState({ state: localStorageItemJSON, defaultState, schema });
437
+ };
438
+
439
+ /**
440
+ * Sets a value in the local storage with the specified key.
441
+ * Thin wrapper around localStorage.setItem() that is slightly more type safe
442
+ * Stringifies value automatically.
443
+ * Useful if you for some reason can't use the useLocalStorage hook for React lifecycle reasons
444
+ *
445
+ * @template TValue - The type of value to be stored.
446
+ * @param {string} key - The key under which to store the value.
447
+ * @param {TValue} value - The value to store in the local storage.
448
+ */
449
+ const setLocalStorage = (key, value) => {
450
+ localStorage.setItem(key, JSON.stringify(value));
451
+ };
452
+
453
+ /**
454
+ * Custom hook for synchronizing a state variable with local storage,
455
+ * with optional schema validation and callbacks.
456
+ *
457
+ * @template TState - The type of the state variable.
458
+ * @param {LocalStorageParams<TState> & LocalStorageCallbacks & { state: TState }} params - The parameters for the useLocalStorageEffect hook.
459
+ */
460
+ const useLocalStorageEffect = ({ key, state, defaultState, schema, onValidationFailed, onValidationSuccessful, }) => {
461
+ const prevState = usePrevious(state);
462
+ react.useEffect(() => {
463
+ if (JSON.stringify(prevState) === JSON.stringify(state)) {
464
+ return;
465
+ }
466
+ if (schema) {
467
+ validateState({
468
+ state,
469
+ schema,
470
+ defaultState,
471
+ onValidationFailed: error => {
472
+ // eslint-disable-next-line no-console
473
+ console.error(`State validation failed. Resetting local storage to default state: ${defaultState}.`, error);
474
+ localStorage.removeItem(key);
475
+ onValidationFailed?.(error);
476
+ },
477
+ onValidationSuccessful: data => {
478
+ setLocalStorage(key, data);
479
+ onValidationSuccessful?.(data);
480
+ },
481
+ });
482
+ }
483
+ else {
484
+ const stringifiedState = JSON.stringify(state);
485
+ localStorage.setItem(key, stringifiedState);
486
+ }
487
+ }, [state, key, schema, defaultState, prevState, onValidationFailed, onValidationSuccessful]);
488
+ };
489
+
490
+ /**
491
+ * Works like a normal useState, but saves to local storage and has optional schema validation.
492
+ *
493
+ * @template TState - The type of the value stored in local storage.
494
+ * @param {Omit<LocalStorageParams<TState>, "state"> & LocalStorageCallbacks} options - The options for useLocalStorage.
495
+ * @returns {[TState, Dispatch<SetStateAction<TState>>, () => void]} - A tuple containing the current value, a function to update the value, and a function to remove the value from local storage.
496
+ */
497
+ const useLocalStorage = ({ key, defaultState, schema, onValidationFailed, onValidationSuccessful, }) => {
498
+ if (!key) {
499
+ throw new Error("useLocalStorage key may not be falsy");
500
+ }
501
+ const [state, setState] = react.useState(initLocalStorageState({ key, defaultState, schema }));
502
+ const prevKey = usePrevious(key);
503
+ react.useEffect(() => {
504
+ if (key !== prevKey) {
505
+ setState(initLocalStorageState({ key, defaultState, schema }));
506
+ }
507
+ }, [key, prevKey, defaultState, schema]);
508
+ useLocalStorageEffect({
509
+ key,
510
+ state,
511
+ defaultState,
512
+ schema,
513
+ onValidationFailed,
514
+ onValidationSuccessful,
515
+ });
516
+ const reset = () => {
517
+ setState(defaultState);
518
+ };
519
+ return [state, setState, reset];
520
+ };
521
+
522
+ /**
523
+ * Works like a normal useReducer, but saves to local storage and has optional schema validation.
524
+ *
525
+ * @template TState - The type of the state.
526
+ * @template TAction - The type of the action.
527
+ * @param {LocalStorageParams<TState> & LocalStorageCallbacks} params - The parameters for the useLocalStorageReducer function.
528
+ * @returns {[TState, Dispatch<TAction>]} - A tuple containing the state and the dispatch function.
529
+ */
530
+ const useLocalStorageReducer = ({ key, defaultState, reducer, schema, onValidationFailed, onValidationSuccessful, }) => {
531
+ if (!key) {
532
+ throw new Error("useLocalStorage key may not be falsy");
533
+ }
534
+ const [state, dispatch] = react.useReducer(reducer, defaultState, () => initLocalStorageState({ key, defaultState, schema }));
535
+ useLocalStorageEffect({ key, state, defaultState, schema, onValidationFailed, onValidationSuccessful });
536
+ return [state, dispatch];
537
+ };
538
+
380
539
  const ModalDialogContext = react.createContext(null);
381
540
  /**
382
541
  * This is a provider for the ModalDialogContext.
@@ -705,6 +864,33 @@ const useUserSubscription = () => {
705
864
  return context;
706
865
  };
707
866
 
867
+ const TimeRangeContext = react.createContext(null);
868
+ /**
869
+ * This is a hook to use the TimeRangeProvider.
870
+ *
871
+ * @requires TimeRangeProvider
872
+ * @example
873
+ * import { useTimeRange } from "@trackunit/react-core-hooks";
874
+ *
875
+ * export const useTimeRange = () => {
876
+ * const { timeRange } = useTimeRange();
877
+ *
878
+ * ...
879
+ * };
880
+ * @see {@link TimeRangeContext}
881
+ */
882
+ const useTimeRange = () => {
883
+ const context = react.useContext(TimeRangeContext);
884
+ if (!context) {
885
+ throw new Error("useTimeRange must be used within the TimeRangeContext");
886
+ }
887
+ return context;
888
+ };
889
+ /**
890
+ * This is a provider for the TimeRangeContext.
891
+ */
892
+ const TimeRangeProvider = (props) => jsxRuntime.jsx(TimeRangeContext.Provider, { ...props });
893
+
708
894
  const ToastContext = react.createContext(null);
709
895
  /**
710
896
  * This is a provider for the ToastContext.
@@ -735,27 +921,6 @@ const useToast = () => {
735
921
  return toastContext;
736
922
  };
737
923
 
738
- /**
739
- * Hook for filtering a list of items by text search, client side search in a list.
740
- *
741
- * @template TSearchableItem
742
- * @param items The list of items to filter.
743
- * @param props The properties to search in each item.
744
- * @returns {[TSearchableItem[], string, Dispatch<string>]} A tuple with the filtered items, the search text and a setter for the search text.
745
- * @example
746
- * const [result, searchText, setSearchText] = useTextSearch(items, item => [item.name, item.description]);
747
- */
748
- function useTextSearch(items, props) {
749
- const [searchText, setSearchText] = react.useState("");
750
- const result = react.useMemo(() => {
751
- if (!searchText) {
752
- return items;
753
- }
754
- return sharedUtils.filterByMultiple(items, props, searchText);
755
- }, [items, props, searchText]);
756
- return [result, searchText, setSearchText];
757
- }
758
-
759
924
  const CurrentUserPreferenceContext = react.createContext(null);
760
925
  /**
761
926
  *
@@ -879,163 +1044,25 @@ const useCurrentUser = () => {
879
1044
  };
880
1045
 
881
1046
  /**
882
- * The usePrevious hook is a useful tool for tracking the previous value of a variable in a functional component. This can be particularly handy in scenarios where it is necessary to compare the current value with the previous one, such as triggering actions or rendering based on changes.
1047
+ * Hook for filtering a list of items by text search, client side search in a list.
883
1048
  *
1049
+ * @template TSearchableItem
1050
+ * @param items The list of items to filter.
1051
+ * @param props The properties to search in each item.
1052
+ * @returns {[TSearchableItem[], string, Dispatch<string>]} A tuple with the filtered items, the search text and a setter for the search text.
884
1053
  * @example
885
- * const [color, setColor] = React.useState(getRandomColor());
886
- const previousColor = usePrevious(color);
887
- */
888
- const usePrevious = (value) => {
889
- const ref = react.useRef(undefined);
890
- react.useEffect(() => {
891
- ref.current = value;
892
- }, [value]);
893
- const wrapper = {
894
- get previous() {
895
- return ref.current;
896
- },
897
- };
898
- return wrapper.previous;
899
- };
900
-
901
- /**
902
- * Validates the state object using a Zod schema.
903
- *
904
- * @template TState - The type of the state.
905
- * @param {ValidateStateOptions<TState>} params - The parameters for the validateState function.
906
- */
907
- const validateState = ({ state, schema, onValidationFailed, onValidationSuccessful, defaultState, }) => {
908
- try {
909
- const parsedState = schema.parse(state);
910
- onValidationSuccessful?.(parsedState);
911
- return parsedState;
912
- }
913
- catch (error) {
914
- // eslint-disable-next-line no-console
915
- console.error("Failed to parse and validate the state from local storage.", error);
916
- onValidationFailed?.(error);
917
- return defaultState;
918
- }
919
- };
920
-
921
- /**
922
- * Initializes the state from local storage, parsing and validating it if a Zod schema is provided.
923
- *
924
- * @template TState - The type of the state stored in local storage.
925
- * @param {Omit<LocalStorageParams<TState>, "state">} params - The parameters for initializing the local storage state.
926
- * @returns {TState} - The initialized state.
927
- */
928
- const initLocalStorageState = ({ key, defaultState, schema, }) => {
929
- const localStorageItem = localStorage.getItem(key);
930
- if (!localStorageItem) {
931
- return defaultState;
932
- }
933
- const localStorageItemJSON = JSON.parse(localStorageItem);
934
- if (!schema) {
935
- return localStorageItemJSON;
936
- }
937
- return validateState({ state: localStorageItemJSON, defaultState, schema });
938
- };
939
-
940
- /**
941
- * Sets a value in the local storage with the specified key.
942
- * Thin wrapper around localStorage.setItem() that is slightly more type safe
943
- * Stringifies value automatically.
944
- * Useful if you for some reason can't use the useLocalStorage hook for React lifecycle reasons
945
- *
946
- * @template TValue - The type of value to be stored.
947
- * @param {string} key - The key under which to store the value.
948
- * @param {TValue} value - The value to store in the local storage.
949
- */
950
- const setLocalStorage = (key, value) => {
951
- localStorage.setItem(key, JSON.stringify(value));
952
- };
953
-
954
- /**
955
- * Custom hook for synchronizing a state variable with local storage,
956
- * with optional schema validation and callbacks.
957
- *
958
- * @template TState - The type of the state variable.
959
- * @param {LocalStorageParams<TState> & LocalStorageCallbacks & { state: TState }} params - The parameters for the useLocalStorageEffect hook.
960
- */
961
- const useLocalStorageEffect = ({ key, state, defaultState, schema, onValidationFailed, onValidationSuccessful, }) => {
962
- const prevState = usePrevious(state);
963
- react.useEffect(() => {
964
- if (JSON.stringify(prevState) === JSON.stringify(state)) {
965
- return;
966
- }
967
- if (schema) {
968
- validateState({
969
- state,
970
- schema,
971
- defaultState,
972
- onValidationFailed: error => {
973
- // eslint-disable-next-line no-console
974
- console.error(`State validation failed. Resetting local storage to default state: ${defaultState}.`, error);
975
- localStorage.removeItem(key);
976
- onValidationFailed?.(error);
977
- },
978
- onValidationSuccessful: data => {
979
- setLocalStorage(key, data);
980
- onValidationSuccessful?.(data);
981
- },
982
- });
983
- }
984
- else {
985
- const stringifiedState = JSON.stringify(state);
986
- localStorage.setItem(key, stringifiedState);
987
- }
988
- }, [state, key, schema, defaultState, prevState, onValidationFailed, onValidationSuccessful]);
989
- };
990
-
991
- /**
992
- * Works like a normal useState, but saves to local storage and has optional schema validation.
993
- *
994
- * @template TState - The type of the value stored in local storage.
995
- * @param {Omit<LocalStorageParams<TState>, "state"> & LocalStorageCallbacks} options - The options for useLocalStorage.
996
- * @returns {[TState, Dispatch<SetStateAction<TState>>, () => void]} - A tuple containing the current value, a function to update the value, and a function to remove the value from local storage.
1054
+ * const [result, searchText, setSearchText] = useTextSearch(items, item => [item.name, item.description]);
997
1055
  */
998
- const useLocalStorage = ({ key, defaultState, schema, onValidationFailed, onValidationSuccessful, }) => {
999
- if (!key) {
1000
- throw new Error("useLocalStorage key may not be falsy");
1001
- }
1002
- const [state, setState] = react.useState(initLocalStorageState({ key, defaultState, schema }));
1003
- const prevKey = usePrevious(key);
1004
- react.useEffect(() => {
1005
- if (key !== prevKey) {
1006
- setState(initLocalStorageState({ key, defaultState, schema }));
1056
+ function useTextSearch(items, props) {
1057
+ const [searchText, setSearchText] = react.useState("");
1058
+ const result = react.useMemo(() => {
1059
+ if (!searchText) {
1060
+ return items;
1007
1061
  }
1008
- }, [key, prevKey, defaultState, schema]);
1009
- useLocalStorageEffect({
1010
- key,
1011
- state,
1012
- defaultState,
1013
- schema,
1014
- onValidationFailed,
1015
- onValidationSuccessful,
1016
- });
1017
- const reset = () => {
1018
- setState(defaultState);
1019
- };
1020
- return [state, setState, reset];
1021
- };
1022
-
1023
- /**
1024
- * Works like a normal useReducer, but saves to local storage and has optional schema validation.
1025
- *
1026
- * @template TState - The type of the state.
1027
- * @template TAction - The type of the action.
1028
- * @param {LocalStorageParams<TState> & LocalStorageCallbacks} params - The parameters for the useLocalStorageReducer function.
1029
- * @returns {[TState, Dispatch<TAction>]} - A tuple containing the state and the dispatch function.
1030
- */
1031
- const useLocalStorageReducer = ({ key, defaultState, reducer, schema, onValidationFailed, onValidationSuccessful, }) => {
1032
- if (!key) {
1033
- throw new Error("useLocalStorage key may not be falsy");
1034
- }
1035
- const [state, dispatch] = react.useReducer(reducer, defaultState, () => initLocalStorageState({ key, defaultState, schema }));
1036
- useLocalStorageEffect({ key, state, defaultState, schema, onValidationFailed, onValidationSuccessful });
1037
- return [state, dispatch];
1038
- };
1062
+ return sharedUtils.filterByMultiple(items, props, searchText);
1063
+ }, [items, props, searchText]);
1064
+ return [result, searchText, setSearchText];
1065
+ }
1039
1066
 
1040
1067
  exports.AnalyticsContext = AnalyticsContext;
1041
1068
  exports.AnalyticsContextProvider = AnalyticsContextProvider;
@@ -1050,6 +1077,7 @@ exports.FilterBarProvider = FilterBarProvider;
1050
1077
  exports.ModalDialogContextProvider = ModalDialogContextProvider;
1051
1078
  exports.NavigationContextProvider = NavigationContextProvider;
1052
1079
  exports.OemBrandingContextProvider = OemBrandingContextProvider;
1080
+ exports.TimeRangeProvider = TimeRangeProvider;
1053
1081
  exports.ToastProvider = ToastProvider;
1054
1082
  exports.TokenProvider = TokenProvider;
1055
1083
  exports.UserSubscriptionProvider = UserSubscriptionProvider;
@@ -1081,6 +1109,7 @@ exports.useOemBrandingContext = useOemBrandingContext;
1081
1109
  exports.usePrevious = usePrevious;
1082
1110
  exports.useSiteRuntime = useSiteRuntime;
1083
1111
  exports.useTextSearch = useTextSearch;
1112
+ exports.useTimeRange = useTimeRange;
1084
1113
  exports.useToast = useToast;
1085
1114
  exports.useToken = useToken;
1086
1115
  exports.useUserSubscription = useUserSubscription;
package/index.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createContext, useContext, useMemo, useState, useCallback, useEffect, useRef, useReducer } from 'react';
1
+ import { createContext, useContext, useMemo, useState, useCallback, useRef, useEffect, useReducer } from 'react';
2
2
  import { jsx } from 'react/jsx-runtime';
3
3
  import { AssetRuntime, CustomerRuntime, EventRuntime, ParamsRuntime, SiteRuntime } from '@trackunit/iris-app-runtime-core';
4
4
  import { filterByMultiple } from '@trackunit/shared-utils';
@@ -375,6 +375,165 @@ const OemBrandingContextProvider = (props) => {
375
375
  return jsx(OEMBrandingService.Provider, { ...props });
376
376
  };
377
377
 
378
+ /**
379
+ * The usePrevious hook is a useful tool for tracking the previous value of a variable in a functional component. This can be particularly handy in scenarios where it is necessary to compare the current value with the previous one, such as triggering actions or rendering based on changes.
380
+ *
381
+ * @example
382
+ * const [color, setColor] = React.useState(getRandomColor());
383
+ const previousColor = usePrevious(color);
384
+ */
385
+ const usePrevious = (value) => {
386
+ const ref = useRef(undefined);
387
+ useEffect(() => {
388
+ ref.current = value;
389
+ }, [value]);
390
+ const wrapper = {
391
+ get previous() {
392
+ return ref.current;
393
+ },
394
+ };
395
+ return wrapper.previous;
396
+ };
397
+
398
+ /**
399
+ * Validates the state object using a Zod schema.
400
+ *
401
+ * @template TState - The type of the state.
402
+ * @param {ValidateStateOptions<TState>} params - The parameters for the validateState function.
403
+ */
404
+ const validateState = ({ state, schema, onValidationFailed, onValidationSuccessful, defaultState, }) => {
405
+ try {
406
+ const parsedState = schema.parse(state);
407
+ onValidationSuccessful?.(parsedState);
408
+ return parsedState;
409
+ }
410
+ catch (error) {
411
+ // eslint-disable-next-line no-console
412
+ console.error("Failed to parse and validate the state from local storage.", error);
413
+ onValidationFailed?.(error);
414
+ return defaultState;
415
+ }
416
+ };
417
+
418
+ /**
419
+ * Initializes the state from local storage, parsing and validating it if a Zod schema is provided.
420
+ *
421
+ * @template TState - The type of the state stored in local storage.
422
+ * @param {Omit<LocalStorageParams<TState>, "state">} params - The parameters for initializing the local storage state.
423
+ * @returns {TState} - The initialized state.
424
+ */
425
+ const initLocalStorageState = ({ key, defaultState, schema, }) => {
426
+ const localStorageItem = localStorage.getItem(key);
427
+ if (!localStorageItem) {
428
+ return defaultState;
429
+ }
430
+ const localStorageItemJSON = JSON.parse(localStorageItem);
431
+ if (!schema) {
432
+ return localStorageItemJSON;
433
+ }
434
+ return validateState({ state: localStorageItemJSON, defaultState, schema });
435
+ };
436
+
437
+ /**
438
+ * Sets a value in the local storage with the specified key.
439
+ * Thin wrapper around localStorage.setItem() that is slightly more type safe
440
+ * Stringifies value automatically.
441
+ * Useful if you for some reason can't use the useLocalStorage hook for React lifecycle reasons
442
+ *
443
+ * @template TValue - The type of value to be stored.
444
+ * @param {string} key - The key under which to store the value.
445
+ * @param {TValue} value - The value to store in the local storage.
446
+ */
447
+ const setLocalStorage = (key, value) => {
448
+ localStorage.setItem(key, JSON.stringify(value));
449
+ };
450
+
451
+ /**
452
+ * Custom hook for synchronizing a state variable with local storage,
453
+ * with optional schema validation and callbacks.
454
+ *
455
+ * @template TState - The type of the state variable.
456
+ * @param {LocalStorageParams<TState> & LocalStorageCallbacks & { state: TState }} params - The parameters for the useLocalStorageEffect hook.
457
+ */
458
+ const useLocalStorageEffect = ({ key, state, defaultState, schema, onValidationFailed, onValidationSuccessful, }) => {
459
+ const prevState = usePrevious(state);
460
+ useEffect(() => {
461
+ if (JSON.stringify(prevState) === JSON.stringify(state)) {
462
+ return;
463
+ }
464
+ if (schema) {
465
+ validateState({
466
+ state,
467
+ schema,
468
+ defaultState,
469
+ onValidationFailed: error => {
470
+ // eslint-disable-next-line no-console
471
+ console.error(`State validation failed. Resetting local storage to default state: ${defaultState}.`, error);
472
+ localStorage.removeItem(key);
473
+ onValidationFailed?.(error);
474
+ },
475
+ onValidationSuccessful: data => {
476
+ setLocalStorage(key, data);
477
+ onValidationSuccessful?.(data);
478
+ },
479
+ });
480
+ }
481
+ else {
482
+ const stringifiedState = JSON.stringify(state);
483
+ localStorage.setItem(key, stringifiedState);
484
+ }
485
+ }, [state, key, schema, defaultState, prevState, onValidationFailed, onValidationSuccessful]);
486
+ };
487
+
488
+ /**
489
+ * Works like a normal useState, but saves to local storage and has optional schema validation.
490
+ *
491
+ * @template TState - The type of the value stored in local storage.
492
+ * @param {Omit<LocalStorageParams<TState>, "state"> & LocalStorageCallbacks} options - The options for useLocalStorage.
493
+ * @returns {[TState, Dispatch<SetStateAction<TState>>, () => void]} - A tuple containing the current value, a function to update the value, and a function to remove the value from local storage.
494
+ */
495
+ const useLocalStorage = ({ key, defaultState, schema, onValidationFailed, onValidationSuccessful, }) => {
496
+ if (!key) {
497
+ throw new Error("useLocalStorage key may not be falsy");
498
+ }
499
+ const [state, setState] = useState(initLocalStorageState({ key, defaultState, schema }));
500
+ const prevKey = usePrevious(key);
501
+ useEffect(() => {
502
+ if (key !== prevKey) {
503
+ setState(initLocalStorageState({ key, defaultState, schema }));
504
+ }
505
+ }, [key, prevKey, defaultState, schema]);
506
+ useLocalStorageEffect({
507
+ key,
508
+ state,
509
+ defaultState,
510
+ schema,
511
+ onValidationFailed,
512
+ onValidationSuccessful,
513
+ });
514
+ const reset = () => {
515
+ setState(defaultState);
516
+ };
517
+ return [state, setState, reset];
518
+ };
519
+
520
+ /**
521
+ * Works like a normal useReducer, but saves to local storage and has optional schema validation.
522
+ *
523
+ * @template TState - The type of the state.
524
+ * @template TAction - The type of the action.
525
+ * @param {LocalStorageParams<TState> & LocalStorageCallbacks} params - The parameters for the useLocalStorageReducer function.
526
+ * @returns {[TState, Dispatch<TAction>]} - A tuple containing the state and the dispatch function.
527
+ */
528
+ const useLocalStorageReducer = ({ key, defaultState, reducer, schema, onValidationFailed, onValidationSuccessful, }) => {
529
+ if (!key) {
530
+ throw new Error("useLocalStorage key may not be falsy");
531
+ }
532
+ const [state, dispatch] = useReducer(reducer, defaultState, () => initLocalStorageState({ key, defaultState, schema }));
533
+ useLocalStorageEffect({ key, state, defaultState, schema, onValidationFailed, onValidationSuccessful });
534
+ return [state, dispatch];
535
+ };
536
+
378
537
  const ModalDialogContext = createContext(null);
379
538
  /**
380
539
  * This is a provider for the ModalDialogContext.
@@ -703,6 +862,33 @@ const useUserSubscription = () => {
703
862
  return context;
704
863
  };
705
864
 
865
+ const TimeRangeContext = createContext(null);
866
+ /**
867
+ * This is a hook to use the TimeRangeProvider.
868
+ *
869
+ * @requires TimeRangeProvider
870
+ * @example
871
+ * import { useTimeRange } from "@trackunit/react-core-hooks";
872
+ *
873
+ * export const useTimeRange = () => {
874
+ * const { timeRange } = useTimeRange();
875
+ *
876
+ * ...
877
+ * };
878
+ * @see {@link TimeRangeContext}
879
+ */
880
+ const useTimeRange = () => {
881
+ const context = useContext(TimeRangeContext);
882
+ if (!context) {
883
+ throw new Error("useTimeRange must be used within the TimeRangeContext");
884
+ }
885
+ return context;
886
+ };
887
+ /**
888
+ * This is a provider for the TimeRangeContext.
889
+ */
890
+ const TimeRangeProvider = (props) => jsx(TimeRangeContext.Provider, { ...props });
891
+
706
892
  const ToastContext = createContext(null);
707
893
  /**
708
894
  * This is a provider for the ToastContext.
@@ -733,27 +919,6 @@ const useToast = () => {
733
919
  return toastContext;
734
920
  };
735
921
 
736
- /**
737
- * Hook for filtering a list of items by text search, client side search in a list.
738
- *
739
- * @template TSearchableItem
740
- * @param items The list of items to filter.
741
- * @param props The properties to search in each item.
742
- * @returns {[TSearchableItem[], string, Dispatch<string>]} A tuple with the filtered items, the search text and a setter for the search text.
743
- * @example
744
- * const [result, searchText, setSearchText] = useTextSearch(items, item => [item.name, item.description]);
745
- */
746
- function useTextSearch(items, props) {
747
- const [searchText, setSearchText] = useState("");
748
- const result = useMemo(() => {
749
- if (!searchText) {
750
- return items;
751
- }
752
- return filterByMultiple(items, props, searchText);
753
- }, [items, props, searchText]);
754
- return [result, searchText, setSearchText];
755
- }
756
-
757
922
  const CurrentUserPreferenceContext = createContext(null);
758
923
  /**
759
924
  *
@@ -877,162 +1042,24 @@ const useCurrentUser = () => {
877
1042
  };
878
1043
 
879
1044
  /**
880
- * The usePrevious hook is a useful tool for tracking the previous value of a variable in a functional component. This can be particularly handy in scenarios where it is necessary to compare the current value with the previous one, such as triggering actions or rendering based on changes.
1045
+ * Hook for filtering a list of items by text search, client side search in a list.
881
1046
  *
1047
+ * @template TSearchableItem
1048
+ * @param items The list of items to filter.
1049
+ * @param props The properties to search in each item.
1050
+ * @returns {[TSearchableItem[], string, Dispatch<string>]} A tuple with the filtered items, the search text and a setter for the search text.
882
1051
  * @example
883
- * const [color, setColor] = React.useState(getRandomColor());
884
- const previousColor = usePrevious(color);
885
- */
886
- const usePrevious = (value) => {
887
- const ref = useRef(undefined);
888
- useEffect(() => {
889
- ref.current = value;
890
- }, [value]);
891
- const wrapper = {
892
- get previous() {
893
- return ref.current;
894
- },
895
- };
896
- return wrapper.previous;
897
- };
898
-
899
- /**
900
- * Validates the state object using a Zod schema.
901
- *
902
- * @template TState - The type of the state.
903
- * @param {ValidateStateOptions<TState>} params - The parameters for the validateState function.
904
- */
905
- const validateState = ({ state, schema, onValidationFailed, onValidationSuccessful, defaultState, }) => {
906
- try {
907
- const parsedState = schema.parse(state);
908
- onValidationSuccessful?.(parsedState);
909
- return parsedState;
910
- }
911
- catch (error) {
912
- // eslint-disable-next-line no-console
913
- console.error("Failed to parse and validate the state from local storage.", error);
914
- onValidationFailed?.(error);
915
- return defaultState;
916
- }
917
- };
918
-
919
- /**
920
- * Initializes the state from local storage, parsing and validating it if a Zod schema is provided.
921
- *
922
- * @template TState - The type of the state stored in local storage.
923
- * @param {Omit<LocalStorageParams<TState>, "state">} params - The parameters for initializing the local storage state.
924
- * @returns {TState} - The initialized state.
925
- */
926
- const initLocalStorageState = ({ key, defaultState, schema, }) => {
927
- const localStorageItem = localStorage.getItem(key);
928
- if (!localStorageItem) {
929
- return defaultState;
930
- }
931
- const localStorageItemJSON = JSON.parse(localStorageItem);
932
- if (!schema) {
933
- return localStorageItemJSON;
934
- }
935
- return validateState({ state: localStorageItemJSON, defaultState, schema });
936
- };
937
-
938
- /**
939
- * Sets a value in the local storage with the specified key.
940
- * Thin wrapper around localStorage.setItem() that is slightly more type safe
941
- * Stringifies value automatically.
942
- * Useful if you for some reason can't use the useLocalStorage hook for React lifecycle reasons
943
- *
944
- * @template TValue - The type of value to be stored.
945
- * @param {string} key - The key under which to store the value.
946
- * @param {TValue} value - The value to store in the local storage.
947
- */
948
- const setLocalStorage = (key, value) => {
949
- localStorage.setItem(key, JSON.stringify(value));
950
- };
951
-
952
- /**
953
- * Custom hook for synchronizing a state variable with local storage,
954
- * with optional schema validation and callbacks.
955
- *
956
- * @template TState - The type of the state variable.
957
- * @param {LocalStorageParams<TState> & LocalStorageCallbacks & { state: TState }} params - The parameters for the useLocalStorageEffect hook.
958
- */
959
- const useLocalStorageEffect = ({ key, state, defaultState, schema, onValidationFailed, onValidationSuccessful, }) => {
960
- const prevState = usePrevious(state);
961
- useEffect(() => {
962
- if (JSON.stringify(prevState) === JSON.stringify(state)) {
963
- return;
964
- }
965
- if (schema) {
966
- validateState({
967
- state,
968
- schema,
969
- defaultState,
970
- onValidationFailed: error => {
971
- // eslint-disable-next-line no-console
972
- console.error(`State validation failed. Resetting local storage to default state: ${defaultState}.`, error);
973
- localStorage.removeItem(key);
974
- onValidationFailed?.(error);
975
- },
976
- onValidationSuccessful: data => {
977
- setLocalStorage(key, data);
978
- onValidationSuccessful?.(data);
979
- },
980
- });
981
- }
982
- else {
983
- const stringifiedState = JSON.stringify(state);
984
- localStorage.setItem(key, stringifiedState);
985
- }
986
- }, [state, key, schema, defaultState, prevState, onValidationFailed, onValidationSuccessful]);
987
- };
988
-
989
- /**
990
- * Works like a normal useState, but saves to local storage and has optional schema validation.
991
- *
992
- * @template TState - The type of the value stored in local storage.
993
- * @param {Omit<LocalStorageParams<TState>, "state"> & LocalStorageCallbacks} options - The options for useLocalStorage.
994
- * @returns {[TState, Dispatch<SetStateAction<TState>>, () => void]} - A tuple containing the current value, a function to update the value, and a function to remove the value from local storage.
1052
+ * const [result, searchText, setSearchText] = useTextSearch(items, item => [item.name, item.description]);
995
1053
  */
996
- const useLocalStorage = ({ key, defaultState, schema, onValidationFailed, onValidationSuccessful, }) => {
997
- if (!key) {
998
- throw new Error("useLocalStorage key may not be falsy");
999
- }
1000
- const [state, setState] = useState(initLocalStorageState({ key, defaultState, schema }));
1001
- const prevKey = usePrevious(key);
1002
- useEffect(() => {
1003
- if (key !== prevKey) {
1004
- setState(initLocalStorageState({ key, defaultState, schema }));
1054
+ function useTextSearch(items, props) {
1055
+ const [searchText, setSearchText] = useState("");
1056
+ const result = useMemo(() => {
1057
+ if (!searchText) {
1058
+ return items;
1005
1059
  }
1006
- }, [key, prevKey, defaultState, schema]);
1007
- useLocalStorageEffect({
1008
- key,
1009
- state,
1010
- defaultState,
1011
- schema,
1012
- onValidationFailed,
1013
- onValidationSuccessful,
1014
- });
1015
- const reset = () => {
1016
- setState(defaultState);
1017
- };
1018
- return [state, setState, reset];
1019
- };
1020
-
1021
- /**
1022
- * Works like a normal useReducer, but saves to local storage and has optional schema validation.
1023
- *
1024
- * @template TState - The type of the state.
1025
- * @template TAction - The type of the action.
1026
- * @param {LocalStorageParams<TState> & LocalStorageCallbacks} params - The parameters for the useLocalStorageReducer function.
1027
- * @returns {[TState, Dispatch<TAction>]} - A tuple containing the state and the dispatch function.
1028
- */
1029
- const useLocalStorageReducer = ({ key, defaultState, reducer, schema, onValidationFailed, onValidationSuccessful, }) => {
1030
- if (!key) {
1031
- throw new Error("useLocalStorage key may not be falsy");
1032
- }
1033
- const [state, dispatch] = useReducer(reducer, defaultState, () => initLocalStorageState({ key, defaultState, schema }));
1034
- useLocalStorageEffect({ key, state, defaultState, schema, onValidationFailed, onValidationSuccessful });
1035
- return [state, dispatch];
1036
- };
1060
+ return filterByMultiple(items, props, searchText);
1061
+ }, [items, props, searchText]);
1062
+ return [result, searchText, setSearchText];
1063
+ }
1037
1064
 
1038
- export { AnalyticsContext, AnalyticsContextProvider, AssetSortingProvider, ConfirmationDialogProvider, CurrentUserPreferenceProvider, CurrentUserProvider, EnvironmentContextProvider, ErrorHandlingContext, ErrorHandlingContextProvider, FilterBarProvider, ModalDialogContextProvider, NavigationContextProvider, OemBrandingContextProvider, ToastProvider, TokenProvider, UserSubscriptionProvider, fetchAssetBlobUrl, useAnalytics, useAssetRuntime, useAssetSorting, useConfirmationDialog, useCurrentUser, useCurrentUserLanguage, useCurrentUserSystemOfMeasurement, useCurrentUserTimeZonePreference, useCustomerRuntime, useEnvironment, useErrorHandler, useEventRuntime, useFeatureBranchQueryString, useFilterBarContext, useHasAccessTo, useImageUploader, useIrisAppId, useIrisAppImage, useIrisAppName, useLocalStorage, useLocalStorageReducer, useModalDialogContext, useNavigateInHost, useOemBrandingContext, usePrevious, useSiteRuntime, useTextSearch, useToast, useToken, useUserSubscription };
1065
+ export { AnalyticsContext, AnalyticsContextProvider, AssetSortingProvider, ConfirmationDialogProvider, CurrentUserPreferenceProvider, CurrentUserProvider, EnvironmentContextProvider, ErrorHandlingContext, ErrorHandlingContextProvider, FilterBarProvider, ModalDialogContextProvider, NavigationContextProvider, OemBrandingContextProvider, TimeRangeProvider, ToastProvider, TokenProvider, UserSubscriptionProvider, fetchAssetBlobUrl, useAnalytics, useAssetRuntime, useAssetSorting, useConfirmationDialog, useCurrentUser, useCurrentUserLanguage, useCurrentUserSystemOfMeasurement, useCurrentUserTimeZonePreference, useCustomerRuntime, useEnvironment, useErrorHandler, useEventRuntime, useFeatureBranchQueryString, useFilterBarContext, useHasAccessTo, useImageUploader, useIrisAppId, useIrisAppImage, useIrisAppName, useLocalStorage, useLocalStorageReducer, useModalDialogContext, useNavigateInHost, useOemBrandingContext, usePrevious, useSiteRuntime, useTextSearch, useTimeRange, useToast, useToken, useUserSubscription };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/react-core-hooks",
3
- "version": "1.3.70",
3
+ "version": "1.3.72",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "engines": {
@@ -10,9 +10,9 @@
10
10
  "react": "19.0.0",
11
11
  "jest-fetch-mock": "^3.0.3",
12
12
  "zod": "3.22.4",
13
- "@trackunit/react-core-contexts-api": "1.4.68",
14
- "@trackunit/iris-app-runtime-core": "1.4.69",
15
- "@trackunit/shared-utils": "1.5.67"
13
+ "@trackunit/react-core-contexts-api": "1.4.70",
14
+ "@trackunit/iris-app-runtime-core": "1.4.71",
15
+ "@trackunit/shared-utils": "1.5.68"
16
16
  },
17
17
  "module": "./index.esm.js",
18
18
  "main": "./index.cjs.js",
package/src/index.d.ts CHANGED
@@ -8,6 +8,8 @@ export * from "./filter-bar/FilterBarProvider";
8
8
  export * from "./images/useImageUploader";
9
9
  export * from "./images/useIrisAppImage";
10
10
  export * from "./irisOemApp/IrisOemAppContextProvider";
11
+ export * from "./localStorage/useLocalStorage";
12
+ export * from "./localStorage/useLocalStorageReducer";
11
13
  export * from "./modalDialog/ModalDialogProvider";
12
14
  export * from "./navigation/NavigationContextProvider";
13
15
  export * from "./runtimes/useAssetRuntime";
@@ -16,12 +18,11 @@ export * from "./runtimes/useEventRuntime";
16
18
  export * from "./runtimes/useParamsRuntime";
17
19
  export * from "./runtimes/useSiteRuntime";
18
20
  export * from "./subscription/UserSubscriptionProvider";
21
+ export * from "./timeRange/TimeRangeProvider";
19
22
  export * from "./toast/ToastProvider";
20
23
  export * from "./token/TokenProvider";
21
24
  export * from "./useFeatureBranchQueryString";
22
- export * from "./useTextSearch";
25
+ export * from "./usePrevious";
23
26
  export * from "./user/CurrentUserPreferenceProvider";
24
27
  export * from "./user/CurrentUserProvider";
25
- export * from "./localStorage/useLocalStorage";
26
- export * from "./localStorage/useLocalStorageReducer";
27
- export * from "./usePrevious";
28
+ export * from "./useTextSearch";
@@ -0,0 +1,26 @@
1
+ import { TimeRangeContext as TimeRangeContextType } from "@trackunit/react-core-contexts-api";
2
+ import { ReactNode } from "react";
3
+ /**
4
+ * This is a hook to use the TimeRangeProvider.
5
+ *
6
+ * @requires TimeRangeProvider
7
+ * @example
8
+ * import { useTimeRange } from "@trackunit/react-core-hooks";
9
+ *
10
+ * export const useTimeRange = () => {
11
+ * const { timeRange } = useTimeRange();
12
+ *
13
+ * ...
14
+ * };
15
+ * @see {@link TimeRangeContext}
16
+ */
17
+ export declare const useTimeRange: () => TimeRangeContextType;
18
+ interface TimeRangeContextProps {
19
+ value: TimeRangeContextType;
20
+ children?: ReactNode;
21
+ }
22
+ /**
23
+ * This is a provider for the TimeRangeContext.
24
+ */
25
+ export declare const TimeRangeProvider: (props: TimeRangeContextProps) => import("react/jsx-runtime").JSX.Element;
26
+ export {};