@applicaster/zapp-react-native-utils 13.0.0-alpha.5928753399 → 13.0.0-alpha.5942605655

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.
Files changed (68) hide show
  1. package/actionsExecutor/ActionExecutorContext.tsx +159 -12
  2. package/actionsExecutor/consts.ts +4 -0
  3. package/appUtils/HooksManager/Hook.ts +4 -0
  4. package/appUtils/HooksManager/index.ts +2 -0
  5. package/appUtils/__tests__/__snapshots__/localizationsHelper.test.ts.snap +151 -0
  6. package/appUtils/__tests__/allZappLocales.ts +79 -0
  7. package/appUtils/__tests__/{localizationsHelper.test.js → localizationsHelper.test.ts} +11 -0
  8. package/appUtils/accessibilityManager/const.ts +18 -0
  9. package/appUtils/contextKeysManager/contextResolver.ts +1 -12
  10. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +2 -0
  11. package/appUtils/focusManager/index.ios.ts +14 -4
  12. package/appUtils/focusManager/index.ts +13 -0
  13. package/appUtils/focusManager/utils/__tests__/findChild.test.ts +35 -0
  14. package/appUtils/focusManager/utils/index.ts +5 -0
  15. package/appUtils/localizationsHelper.ts +31 -0
  16. package/appUtils/playerManager/playerHooks/usePlayerCurrentTime.tsx +11 -7
  17. package/appUtils/playerManager/usePlayerTitleSummaryOverlay.tsx +7 -1
  18. package/cellUtils/index.ts +9 -5
  19. package/componentsUtils/__tests__/isFirstComponentGallery.test.ts +33 -0
  20. package/componentsUtils/__tests__/isFirstComponentScreenPicker.test.ts +33 -0
  21. package/componentsUtils/__tests__/isGallery.test.ts +33 -0
  22. package/componentsUtils/__tests__/isScreenPicker.test.ts +33 -0
  23. package/componentsUtils/index.ts +39 -0
  24. package/dateUtils/index.ts +19 -0
  25. package/focusManager/FocusManager.ts +3 -1
  26. package/focusManager/index.ts +3 -21
  27. package/functionUtils/index.ts +25 -0
  28. package/index.d.ts +0 -12
  29. package/localizationUtils/index.ts +8 -13
  30. package/manifestUtils/defaultManifestConfigurations/generalContent.js +13 -0
  31. package/manifestUtils/defaultManifestConfigurations/player.js +6 -8
  32. package/manifestUtils/index.js +2 -0
  33. package/manifestUtils/keys.js +27 -2
  34. package/modalState/__tests__/index.test.ts +51 -0
  35. package/modalState/index.ts +32 -2
  36. package/navigationUtils/__tests__/__snapshots__/navigationUtils.test.js.snap +1 -0
  37. package/navigationUtils/index.ts +3 -1
  38. package/numberUtils/__tests__/toPositiveNumberWithDefault.test.ts +23 -3
  39. package/numberUtils/index.ts +4 -0
  40. package/package.json +2 -2
  41. package/playerUtils/configurationGenerator.ts +6 -16
  42. package/playerUtils/index.ts +23 -0
  43. package/reactHooks/advertising/index.ts +5 -5
  44. package/reactHooks/app/useAppState.ts +2 -2
  45. package/reactHooks/feed/useBatchLoading.ts +10 -12
  46. package/reactHooks/feed/useFeedLoader.tsx +17 -8
  47. package/reactHooks/hookModal/hooks/useHookModalScreenData.ts +39 -0
  48. package/reactHooks/navigation/{useGetTabBarHeight.ts → getTabBarHeight.ts} +1 -1
  49. package/reactHooks/navigation/useGetBottomTabBarHeight.ts +10 -3
  50. package/reactHooks/navigation/useNavigationPluginData.ts +8 -4
  51. package/reactHooks/navigation/useNavigationType.ts +4 -2
  52. package/reactHooks/navigation/useRoute.ts +4 -6
  53. package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +69 -0
  54. package/reactHooks/screen/useScreenBackgroundColor.ts +3 -15
  55. package/reactHooks/state/README.md +79 -0
  56. package/reactHooks/state/ZStoreProvider.tsx +71 -0
  57. package/reactHooks/state/__tests__/ZStoreProvider.test.tsx +66 -0
  58. package/reactHooks/state/index.ts +2 -0
  59. package/reactHooks/useListenEventBusEvent.ts +1 -1
  60. package/reactUtils/index.ts +9 -0
  61. package/typeGuards/index.ts +3 -0
  62. package/utils/README.md +30 -0
  63. package/utils/chunk.ts +5 -0
  64. package/utils/index.ts +5 -0
  65. package/utils/times.ts +5 -0
  66. package/zappFrameworkUtils/localStorageHelper.ts +38 -10
  67. package/zappFrameworkUtils/loginPluginUtils.ts +6 -2
  68. package/zappFrameworkUtils/types.ts +11 -0
@@ -1,23 +1,11 @@
1
- import * as React from "react";
2
- import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
3
1
  import { useScreenConfiguration } from "@applicaster/zapp-react-native-ui-components/Components/River/useScreenConfiguration";
4
2
  import { ifEmptyUseFallback } from "@applicaster/zapp-react-native-utils/cellUtils";
5
3
 
4
+ const DEFAULT_BACKGROUND_FALLBACK = "transparent";
5
+
6
6
  export const useScreenBackgroundColor = (screenId: string): string => {
7
7
  const { backgroundColor: screenBackgroundColor } =
8
8
  useScreenConfiguration(screenId);
9
9
 
10
- const theme = useTheme();
11
-
12
- const themeBackgroundColor = React.useMemo(
13
- () => theme.app_background_color,
14
- [theme.app_background_color]
15
- );
16
-
17
- const backgroundColor = ifEmptyUseFallback(
18
- screenBackgroundColor,
19
- themeBackgroundColor
20
- );
21
-
22
- return backgroundColor;
10
+ return ifEmptyUseFallback(screenBackgroundColor, DEFAULT_BACKGROUND_FALLBACK);
23
11
  };
@@ -0,0 +1,79 @@
1
+ # ZStoreProvider and useZStore
2
+
3
+ This module provides a React context-based solution for managing Zustand stores with named access.
4
+
5
+ ## Usage
6
+
7
+ ### ZStoreProvider
8
+
9
+ The `ZStoreProvider` component creates a Zustand store from the provided value and makes it available to child components.
10
+
11
+ ```tsx
12
+ import { ZStoreProvider } from "@applicaster/zapp-react-native-utils/reactHooks/state";
13
+
14
+ // In your component
15
+ <ZStoreProvider name="playerConfiguration" value={controller?.config}>
16
+ <YourComponent />
17
+ </ZStoreProvider>
18
+ ```
19
+
20
+ ### useZStore
21
+
22
+ The `useZStore` hook allows you to access a Zustand store by name from within a `ZStoreProvider`.
23
+
24
+ ```tsx
25
+ import { useZStore } from "@applicaster/zapp-react-native-utils/reactHooks/state";
26
+ import { useStore } from "zustand";
27
+
28
+ // In your component
29
+ const MyComponent = () => {
30
+ const store = useZStore("playerConfiguration");
31
+ const config = useStore(store, (state) => state.someProperty);
32
+
33
+ return <Text>{config}</Text>;
34
+ };
35
+ ```
36
+
37
+ ## Example
38
+
39
+ ```tsx
40
+ import React from "react";
41
+ import { ZStoreProvider, useZStore } from "@applicaster/zapp-react-native-utils/reactHooks/state";
42
+ import { useStore } from "zustand";
43
+
44
+ // Component that uses the store
45
+ const PlayerConfigDisplay = () => {
46
+ const store = useZStore("playerConfiguration");
47
+ const config = useStore(store, (state) => state);
48
+
49
+ return (
50
+ <View>
51
+ <Text>Player Config: {JSON.stringify(config)}</Text>
52
+ </View>
53
+ );
54
+ };
55
+
56
+ // Main component that provides the store
57
+ const PlayerComponent = ({ controller }) => {
58
+ return (
59
+ <ZStoreProvider name="playerConfiguration" value={controller?.config}>
60
+ <PlayerConfigDisplay />
61
+ </ZStoreProvider>
62
+ );
63
+ };
64
+ ```
65
+
66
+ ## Features
67
+
68
+ - **Named Stores**: Access stores by name instead of importing them directly
69
+ - **Context-based**: Uses React Context for store management
70
+ - **Zustand Integration**: Seamlessly works with existing Zustand stores
71
+ - **Type Safety**: Full TypeScript support
72
+ - **Error Handling**: Clear error messages when stores are not found or used outside providers
73
+
74
+ ## Error Handling
75
+
76
+ The `useZStore` hook will throw errors in the following cases:
77
+
78
+ 1. **Used outside provider**: "useZStore must be used within a ZStoreProvider"
79
+ 2. **Store not found**: "Store with name 'storeName' not found. Make sure it's provided by a ZStoreProvider"
@@ -0,0 +1,71 @@
1
+ import React, { createContext, useContext, ReactNode, useMemo } from "react";
2
+ import { create, UseBoundStore } from "zustand";
3
+
4
+ interface ZStoreContextType {
5
+ stores: Map<string, UseBoundStore<any>>;
6
+ registerStore: (name: string, store: UseBoundStore<any>) => void;
7
+ getStore: (name: string) => UseBoundStore<any> | undefined;
8
+ }
9
+
10
+ const ZStoreContext = createContext<ZStoreContextType | null>(null);
11
+
12
+ interface ZStoreProviderProps {
13
+ children: ReactNode;
14
+ name: string;
15
+ value: any;
16
+ }
17
+
18
+ export const ZStoreProvider: React.FC<ZStoreProviderProps> = ({
19
+ children,
20
+ name,
21
+ value,
22
+ }) => {
23
+ const parentContext = useContext(ZStoreContext);
24
+
25
+ const context = useMemo(() => {
26
+ if (parentContext) {
27
+ // If parent context exists, create a new store and register it
28
+ const store = create(() => value);
29
+ parentContext.registerStore(name, store);
30
+
31
+ return parentContext;
32
+ }
33
+
34
+ // Create a new context if none exists
35
+ const stores = new Map<string, UseBoundStore<any>>();
36
+
37
+ // Create a store from the provided value
38
+ const store = create(() => value);
39
+ stores.set(name, store);
40
+
41
+ return {
42
+ stores,
43
+ registerStore: (storeName: string, storeInstance: UseBoundStore<any>) => {
44
+ stores.set(storeName, storeInstance);
45
+ },
46
+ getStore: (storeName: string) => stores.get(storeName),
47
+ };
48
+ }, [parentContext, name, value]);
49
+
50
+ return (
51
+ <ZStoreContext.Provider value={context}>{children}</ZStoreContext.Provider>
52
+ );
53
+ };
54
+
55
+ export const useZStore = (name: string): UseBoundStore<any> => {
56
+ const context = useContext(ZStoreContext);
57
+
58
+ if (!context) {
59
+ throw new Error("useZStore must be used within a ZStoreProvider");
60
+ }
61
+
62
+ const store = context.getStore(name);
63
+
64
+ if (!store) {
65
+ throw new Error(
66
+ `Store with name "${name}" not found. Make sure it's provided by a ZStoreProvider.`
67
+ );
68
+ }
69
+
70
+ return store;
71
+ };
@@ -0,0 +1,66 @@
1
+ import React from "react";
2
+ import { render, screen } from "@testing-library/react-native";
3
+ import { Text } from "react-native";
4
+ import { ZStoreProvider, useZStore } from "../ZStoreProvider";
5
+ import { useStore } from "zustand";
6
+
7
+ interface TestState {
8
+ value: string;
9
+ }
10
+
11
+ // Test component that uses the store
12
+ const TestComponent = ({ storeName }: { storeName: string }) => {
13
+ const store = useZStore(storeName);
14
+ const value = useStore(store, (state: any) => (state as TestState).value);
15
+
16
+ return <Text testID="test-value">{value}</Text>;
17
+ };
18
+
19
+ // Test component that provides a store
20
+ const TestProvider = ({ children }: { children: React.ReactNode }) => {
21
+ return (
22
+ <ZStoreProvider name="testStore" value={{ value: "test-value" }}>
23
+ {children}
24
+ </ZStoreProvider>
25
+ );
26
+ };
27
+
28
+ describe("ZStoreProvider and useZStore", () => {
29
+ it("should provide a store and allow access via useZStore", () => {
30
+ render(
31
+ <TestProvider>
32
+ <TestComponent storeName="testStore" />
33
+ </TestProvider>
34
+ );
35
+
36
+ expect(screen.getByTestId("test-value").props.children).toBe("test-value");
37
+ });
38
+
39
+ it("should throw error when useZStore is used outside provider", () => {
40
+ // Suppress console.error for this test
41
+ const originalError = console.error;
42
+ console.error = jest.fn();
43
+
44
+ expect(() => {
45
+ render(<TestComponent storeName="testStore" />);
46
+ }).toThrow("useZStore must be used within a ZStoreProvider");
47
+
48
+ console.error = originalError;
49
+ });
50
+
51
+ it("should throw error when store name is not found", () => {
52
+ // Suppress console.error for this test
53
+ const originalError = console.error;
54
+ console.error = jest.fn();
55
+
56
+ expect(() => {
57
+ render(
58
+ <TestProvider>
59
+ <TestComponent storeName="nonExistentStore" />
60
+ </TestProvider>
61
+ );
62
+ }).toThrow('Store with name "nonExistentStore" not found');
63
+
64
+ console.error = originalError;
65
+ });
66
+ });
@@ -1,3 +1,5 @@
1
1
  export { useRivers } from "./useRivers";
2
2
 
3
3
  export { useHomeRiver } from "./useHomeRiver";
4
+
5
+ export { ZStoreProvider, useZStore } from "./ZStoreProvider";
@@ -23,5 +23,5 @@ export const useListenEventBusEvent = (
23
23
  sub.remove(); // stop listening to DeviceEventEmitter
24
24
  };
25
25
  }
26
- }, []);
26
+ }, [handler, subscriptionID, source, events]);
27
27
  };
@@ -187,3 +187,12 @@ export const hasVizioAPIs = () => {
187
187
 
188
188
  return hasAPIs;
189
189
  };
190
+
191
+ /**
192
+ * Checks if the Android version is at least the expected version
193
+ * @param expectedVersion The version to compare against
194
+ * @returns True if the current Android version is at least the expected version, false otherwise
195
+ */
196
+ export const isAndroidVersionAtLeast = (expectedVersion: number) => {
197
+ return parseFloat(Platform.Version.toString()) >= expectedVersion;
198
+ };
@@ -0,0 +1,3 @@
1
+ export const isString = (value: unknown) => {
2
+ return typeof value === "string";
3
+ };
@@ -0,0 +1,30 @@
1
+ ### ramda replacement utils
2
+
3
+ See contribution guide below
4
+
5
+ ## Reference
6
+
7
+ Prefer non-fp variant as it more performant - if refactoring assumes you need more efforts rewrite ramda sample to lodash and it can be easily replaced with lodash-fp - use lodash-fp.
8
+
9
+ ### Ramda alternatives:
10
+
11
+ Custom
12
+ - `splitEvery` => `chunk`
13
+ - `times` => `times`
14
+
15
+ From `lodash`
16
+ - `clone` => `clone`
17
+ - `flatten` => `flatten`
18
+ - `drop` => `drop`
19
+ - `length` => `size`
20
+
21
+
22
+ ## Contribution
23
+
24
+ To add new helper function as ramda replacement
25
+
26
+ 1. Search for replacement ( you can use lodash or pure JS solution), arguments should match with Ramda definition (for easier transition).
27
+ 2. Add new file if needed, add test, update exports in index file. 2.1. Make sure it's well-typed.
28
+ 3. If the function can-be reexported from other 3rd party lib - update index.ts to re-export it.
29
+ 4. Make sure README is updated and contains reference for newly added function.
30
+ 5. You can use AI's help. Use query like 'lodash & lodash/fp equivalent of Ramda's R.clone function' to get an options you can use.
package/utils/chunk.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { chunk as _chunk } from "lodash";
2
+
3
+ export const chunk = <T>(size: number, array: T[]): T[][] => {
4
+ return _chunk(array, size);
5
+ };
package/utils/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export { chunk } from "./chunk";
2
+
3
+ export { times } from "./times";
4
+
5
+ export { cloneDeep as clone, flatten, drop, size, isNil } from "lodash";
package/utils/times.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { times as _times } from "lodash";
2
+
3
+ export const times = <T>(iteratee: (index: number) => T, n: number) => {
4
+ return _times(n, iteratee);
5
+ };
@@ -1,6 +1,13 @@
1
1
  import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
2
2
  import { isNilOrEmpty } from "../reactUtils/helpers";
3
3
  import { parseJsonIfNeeded } from "@applicaster/zapp-react-native-utils/functionUtils";
4
+ import {
5
+ StorageOwnedValues,
6
+ NamespaceValues,
7
+ StorageValuesToRemove,
8
+ StorageValuesToAdd,
9
+ } from "./types";
10
+ import { Storage } from "@applicaster/zapp-react-native-bridge/ZappStorage/Storage";
4
11
 
5
12
  const defaultOwnedKey = "owned_keys";
6
13
  const DEFAULT_NAMESPACE = "applicaster.v2";
@@ -44,8 +51,9 @@ function mapOwnedKeysToAdd(
44
51
  return mappedData;
45
52
  }
46
53
 
47
- export async function batchSaveToLocalStorage(
48
- storageValues: StorageValuesToAdd
54
+ export async function batchSave(
55
+ storageValues: StorageValuesToAdd,
56
+ storage: Storage
49
57
  ) {
50
58
  if (isNilOrEmpty(storageValues)) {
51
59
  return false;
@@ -58,24 +66,37 @@ export async function batchSaveToLocalStorage(
58
66
  const value = namespaceData[key];
59
67
 
60
68
  if (!isNilOrEmpty(value)) {
61
- await localStorage.setItem(key, value, namespace);
69
+ await storage.setItem(key, value, namespace);
62
70
  }
63
71
  }
64
72
  }
65
73
  }
66
74
 
67
- export async function batchRemoveFromLocalStorage(
68
- storageValues: StorageValuesToRemove
75
+ export async function batchSaveToLocalStorage(
76
+ storageValues: StorageValuesToAdd
77
+ ) {
78
+ return await batchSave(storageValues, localStorage);
79
+ }
80
+
81
+ export async function batchRemoveFromStorage(
82
+ storageValues: StorageValuesToRemove,
83
+ storage: Storage = localStorage
69
84
  ) {
70
85
  for (const namespace of Object.keys(storageValues)) {
71
86
  const namespaceData = storageValues[namespace];
72
87
 
73
88
  for (const key of namespaceData) {
74
- await localStorage.removeItem(key, namespace);
89
+ await storage.removeItem(key, namespace);
75
90
  }
76
91
  }
77
92
  }
78
93
 
94
+ export async function batchRemoveFromLocalStorage(
95
+ storageValues: StorageValuesToRemove
96
+ ) {
97
+ await batchRemoveFromStorage(storageValues, localStorage);
98
+ }
99
+
79
100
  async function addOwnedKeys({
80
101
  newKeys,
81
102
  ownershipKey,
@@ -218,13 +239,20 @@ export async function batchRemoveOwnedNamespaceKeys({
218
239
  });
219
240
  }
220
241
 
221
- export async function batchRemoveAllFromNamespace(namespace) {
222
- const allDataInNamespace = await localStorage.getAllItems(namespace);
242
+ export async function batchRemoveAllFromNamespaceForStorage(
243
+ namespace: string,
244
+ storage: Storage
245
+ ) {
246
+ const allDataInNamespace = await storage.getAllItems(namespace);
223
247
  const keysToRemove = Object.keys(allDataInNamespace);
224
248
 
225
- const dataToRemove = {
249
+ const dataToRemove: StorageValuesToRemove = {
226
250
  [namespace]: keysToRemove,
227
251
  };
228
252
 
229
- await batchRemoveFromLocalStorage(dataToRemove);
253
+ await batchRemoveFromStorage(dataToRemove, storage);
254
+ }
255
+
256
+ export async function batchRemoveAllFromNamespace(namespace: string) {
257
+ await batchRemoveAllFromNamespaceForStorage(namespace, localStorage);
230
258
  }
@@ -89,11 +89,15 @@ const runInBackground = async ({
89
89
  const shouldPresent = await hookPresentPolicy.shouldPresentScreen();
90
90
 
91
91
  if (!shouldPresent) {
92
+ const isRefreshed = await checkUserAuthenticated();
93
+
92
94
  log_info(
93
- "runInBackground: Background mode finished, hook plugin will be skipped"
95
+ `runInBackground: Background mode finished, ${isRefreshed ? "finish hook with completion true" : "refresh failed will presentUI"}`
94
96
  );
95
97
 
96
- await checkUserAuthenticated();
98
+ isRefreshed
99
+ ? callback({ success: isRefreshed, payload: item })
100
+ : presentUI();
97
101
 
98
102
  return;
99
103
  }
@@ -0,0 +1,11 @@
1
+ export type StorageValuesToAdd = Record<string, NamespaceValues>;
2
+
3
+ export type StorageValuesToRemove = {
4
+ string?: string[];
5
+ };
6
+
7
+ export type StorageOwnedValues = {
8
+ string?: string[];
9
+ };
10
+
11
+ export type NamespaceValues = Record<string, string>;