@applicaster/zapp-react-native-utils 13.0.0-alpha.1700735421 → 13.0.0-alpha.1711912250

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 (74) hide show
  1. package/actionsExecutor/ActionExecutorContext.tsx +126 -6
  2. package/actionsExecutor/consts.ts +4 -0
  3. package/analyticsUtils/AnalyticsEvents/sendHeaderClickEvent.ts +1 -1
  4. package/analyticsUtils/AnalyticsEvents/sendMenuClickEvent.ts +1 -2
  5. package/analyticsUtils/index.tsx +4 -3
  6. package/analyticsUtils/manager.ts +1 -1
  7. package/appUtils/HooksManager/Hook.ts +4 -0
  8. package/appUtils/HooksManager/index.ts +2 -0
  9. package/appUtils/__tests__/__snapshots__/localizationsHelper.test.ts.snap +151 -0
  10. package/appUtils/__tests__/allZappLocales.ts +79 -0
  11. package/appUtils/__tests__/{localizationsHelper.test.js → localizationsHelper.test.ts} +11 -0
  12. package/appUtils/contextKeysManager/contextResolver.ts +1 -12
  13. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +2 -0
  14. package/appUtils/focusManager/index.ios.ts +14 -4
  15. package/appUtils/focusManager/index.ts +13 -0
  16. package/appUtils/focusManager/utils/__tests__/findChild.test.ts +35 -0
  17. package/appUtils/focusManager/utils/index.ts +5 -0
  18. package/appUtils/localizationsHelper.ts +31 -0
  19. package/appUtils/orientationHelper.ts +11 -12
  20. package/appUtils/playerManager/player.ts +24 -12
  21. package/appUtils/playerManager/playerHooks/usePlayerCurrentTime.tsx +11 -7
  22. package/appUtils/playerManager/playerNative.ts +18 -3
  23. package/appUtils/playerManager/usePlayerTitleSummaryOverlay.tsx +7 -1
  24. package/cellUtils/index.ts +9 -5
  25. package/componentsUtils/__tests__/isFirstComponentGallery.test.ts +33 -0
  26. package/componentsUtils/__tests__/isFirstComponentScreenPicker.test.ts +33 -0
  27. package/componentsUtils/__tests__/isGallery.test.ts +33 -0
  28. package/componentsUtils/__tests__/isScreenPicker.test.ts +33 -0
  29. package/componentsUtils/index.ts +39 -0
  30. package/dateUtils/index.ts +19 -0
  31. package/focusManager/FocusManager.ts +3 -1
  32. package/focusManager/index.ts +3 -21
  33. package/functionUtils/index.ts +25 -0
  34. package/index.d.ts +0 -12
  35. package/localizationUtils/index.ts +8 -13
  36. package/manifestUtils/defaultManifestConfigurations/generalContent.js +13 -0
  37. package/manifestUtils/defaultManifestConfigurations/player.js +10 -4
  38. package/manifestUtils/index.js +2 -0
  39. package/manifestUtils/keys.js +27 -2
  40. package/modalState/__tests__/index.test.ts +51 -0
  41. package/modalState/index.ts +32 -2
  42. package/navigationUtils/__tests__/__snapshots__/navigationUtils.test.js.snap +1 -0
  43. package/navigationUtils/index.ts +3 -1
  44. package/numberUtils/__tests__/toPositiveNumberWithDefault.test.ts +23 -3
  45. package/numberUtils/index.ts +4 -0
  46. package/package.json +2 -3
  47. package/playerUtils/configurationGenerator.ts +9 -11
  48. package/reactHooks/advertising/index.ts +5 -5
  49. package/reactHooks/app/useAppState.ts +2 -2
  50. package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +88 -39
  51. package/reactHooks/feed/useBatchLoading.ts +10 -12
  52. package/reactHooks/feed/useFeedLoader.tsx +17 -8
  53. package/reactHooks/hookModal/hooks/useHookModalScreenData.ts +39 -0
  54. package/reactHooks/navigation/{useGetTabBarHeight.ts → getTabBarHeight.ts} +1 -1
  55. package/reactHooks/navigation/index.ts +7 -5
  56. package/reactHooks/navigation/useGetBottomTabBarHeight.ts +10 -3
  57. package/reactHooks/navigation/useNavigationPluginData.ts +8 -4
  58. package/reactHooks/navigation/useNavigationType.ts +4 -2
  59. package/reactHooks/navigation/useRoute.ts +4 -6
  60. package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +69 -0
  61. package/reactHooks/screen/useScreenBackgroundColor.ts +3 -15
  62. package/reactHooks/useListenEventBusEvent.ts +1 -1
  63. package/reactUtils/index.ts +9 -0
  64. package/services/js2native.ts +673 -0
  65. package/testUtils/index.tsx +8 -7
  66. package/time/BackgroundTimer.ts +55 -0
  67. package/time/Timer.ts +6 -6
  68. package/utils/README.md +30 -0
  69. package/utils/chunk.ts +5 -0
  70. package/utils/index.ts +5 -0
  71. package/utils/times.ts +5 -0
  72. package/zappFrameworkUtils/localStorageHelper.ts +6 -0
  73. package/zappFrameworkUtils/loginPluginUtils.ts +6 -2
  74. package/zappFrameworkUtils/types.ts +11 -0
@@ -1,7 +1,8 @@
1
1
  import { renderHook } from "@testing-library/react-hooks";
2
- import { allFeedsIsReady, useBatchLoading } from "../useBatchLoading";
3
- import { WrappedWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
4
- import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
2
+ import * as reduxMockStore from "redux-mock-store";
3
+ import thunk from "redux-thunk";
4
+ import React from "react";
5
+ import * as ReactRedux from "react-redux";
5
6
 
6
7
  jest.mock("../../navigation");
7
8
 
@@ -12,18 +13,17 @@ jest.mock(
12
13
  })
13
14
  );
14
15
 
15
- const wrapper = WrappedWithProviders;
16
+ const useBatchLoading = require("../useBatchLoading").useBatchLoading;
17
+ const allFeedsIsReady = require("../useBatchLoading").allFeedsIsReady;
18
+
19
+ const mockStore = reduxMockStore.default([thunk]);
20
+
21
+ const wrapper: React.FC<any> = ({ children, store }) => (
22
+ <ReactRedux.Provider store={store}>{children}</ReactRedux.Provider>
23
+ );
16
24
 
17
25
  describe("useBatchLoading", () => {
18
- const data = [
19
- { data: { source: "url1" }, component_type: "any" },
20
- { data: { source: "url2" }, component_type: "any" },
21
- { data: { source: "url3" }, component_type: "any" },
22
- { data: { source: "url4" }, component_type: "any" },
23
- { data: { source: "url5" }, component_type: "any" },
24
- { data: { source: "url6" }, component_type: "any" },
25
- // ... more items
26
- ];
26
+ const useDispatchSpy = jest.spyOn(ReactRedux, "useDispatch");
27
27
 
28
28
  beforeAll(() => {
29
29
  jest.useFakeTimers();
@@ -34,7 +34,7 @@ describe("useBatchLoading", () => {
34
34
  });
35
35
 
36
36
  it("loadPipesData start loading not started requests", () => {
37
- const store = {
37
+ const store = mockStore({
38
38
  zappPipes: {
39
39
  url1: {
40
40
  loading: true,
@@ -53,17 +53,29 @@ describe("useBatchLoading", () => {
53
53
  },
54
54
  },
55
55
  test: "true",
56
- };
56
+ });
57
+
58
+ useDispatchSpy.mockReturnValue(store.dispatch);
57
59
 
58
60
  const initialBatchSize = 3;
59
61
  const riverId = "123";
60
62
 
63
+ const data = [
64
+ { data: { source: "url1" } },
65
+ { data: { source: "url2" } },
66
+ { data: { source: "url3" } },
67
+ { data: { source: "url4" } },
68
+ { data: { source: "url5" } },
69
+ { data: { source: "url6" } },
70
+ // ... more items
71
+ ];
72
+
61
73
  renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
62
74
  wrapper,
63
75
  initialProps: { store },
64
76
  });
65
77
 
66
- const actions = (appStore.getStore() as any).getActions();
78
+ const actions = store.getActions();
67
79
 
68
80
  expect(actions).toHaveLength(2);
69
81
 
@@ -79,7 +91,7 @@ describe("useBatchLoading", () => {
79
91
  });
80
92
 
81
93
  it("loadPipesData start loading new feed when 1 feed is done loading and 1 is in loading state", () => {
82
- const store = {
94
+ const store = mockStore({
83
95
  zappPipes: {
84
96
  url1: {
85
97
  loading: false,
@@ -98,17 +110,31 @@ describe("useBatchLoading", () => {
98
110
  },
99
111
  },
100
112
  test: "true",
101
- };
113
+ });
114
+
115
+ useDispatchSpy.mockReturnValue(store.dispatch);
102
116
 
103
117
  const initialBatchSize = 3;
104
118
  const riverId = "123";
105
119
 
120
+ const data = [
121
+ { data: { source: "url1" } },
122
+ { data: { source: "url2" } },
123
+ { data: { source: "url3" } },
124
+ { data: { source: "url4" } },
125
+ { data: { source: "url5" } },
126
+ { data: { source: "url6" } },
127
+ // ... more items
128
+ ];
129
+
130
+ expect(useDispatchSpy).toBeCalledTimes(0);
131
+
106
132
  renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
107
133
  wrapper,
108
134
  initialProps: { store },
109
135
  });
110
136
 
111
- const actions = (appStore.getStore() as any).getActions();
137
+ const actions = store.getActions();
112
138
 
113
139
  expect(actions).toHaveLength(1);
114
140
 
@@ -119,26 +145,38 @@ describe("useBatchLoading", () => {
119
145
  });
120
146
 
121
147
  it("loadPipesData has been called when no data cached", () => {
122
- const store = {
148
+ const store = mockStore({
123
149
  zappPipes: {},
124
150
  test: "true",
125
- };
151
+ });
152
+
153
+ useDispatchSpy.mockReturnValue(store.dispatch);
126
154
 
127
155
  const initialBatchSize = 3;
128
156
  const riverId = "123";
129
157
 
158
+ const data = [
159
+ { data: { source: "url1" } },
160
+ { data: { source: "url2" } },
161
+ { data: { source: "url3" } },
162
+ { data: { source: "url4" } },
163
+ { data: { source: "url5" } },
164
+ { data: { source: "url6" } },
165
+ // ... more items
166
+ ];
167
+
130
168
  renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
131
169
  wrapper,
132
170
  initialProps: { store },
133
171
  });
134
172
 
135
- const actions = (appStore.getStore() as any).getActions();
173
+ const actions = store.getActions();
136
174
 
137
175
  expect(actions).toHaveLength(3);
138
176
  });
139
177
 
140
178
  it("initial batch ready when all initial items loaded", () => {
141
- const store = {
179
+ const store = mockStore({
142
180
  zappPipes: {
143
181
  url1: {
144
182
  loading: false,
@@ -156,11 +194,19 @@ describe("useBatchLoading", () => {
156
194
  data: {},
157
195
  },
158
196
  },
159
- };
197
+ });
198
+
199
+ useDispatchSpy.mockReturnValue(store.dispatch);
160
200
 
161
201
  const initialBatchSize = 3;
162
202
  const riverId = "123";
163
203
 
204
+ const data: Partial<ZappUIComponent>[] = [
205
+ { data: { source: "url1" } },
206
+ { data: { source: "url2" } },
207
+ { data: { source: "url3" } },
208
+ ];
209
+
164
210
  const { result } = renderHook(
165
211
  () => useBatchLoading(data, { initialBatchSize, riverId }),
166
212
  { wrapper, initialProps: { store } }
@@ -170,10 +216,12 @@ describe("useBatchLoading", () => {
170
216
  });
171
217
 
172
218
  it("gallery-qb: loadPipesData should be called only once for first component in the gallery", () => {
173
- const store = {
219
+ const store = mockStore({
174
220
  zappPipes: {},
175
221
  test: "true",
176
- };
222
+ });
223
+
224
+ useDispatchSpy.mockReturnValue(store.dispatch);
177
225
 
178
226
  const initialBatchSize = 3;
179
227
  const riverId = "123";
@@ -183,11 +231,11 @@ describe("useBatchLoading", () => {
183
231
  component_type: "gallery-qb",
184
232
  ui_components: [{ data: { source: "url1" } }],
185
233
  },
186
- { data: { source: "url2" }, component_type: "any" },
187
- { data: { source: "url3" }, component_type: "any" },
188
- { data: { source: "url4" }, component_type: "any" },
189
- { data: { source: "url5" }, component_type: "any" },
190
- { data: { source: "url6" }, component_type: "any" },
234
+ { data: { source: "url2" } },
235
+ { data: { source: "url3" } },
236
+ { data: { source: "url4" } },
237
+ { data: { source: "url5" } },
238
+ { data: { source: "url6" } },
191
239
  // ... more items
192
240
  ];
193
241
 
@@ -196,13 +244,13 @@ describe("useBatchLoading", () => {
196
244
  initialProps: { store },
197
245
  });
198
246
 
199
- const actions = (appStore.getStore() as any).getActions();
247
+ const actions = store.getActions();
200
248
 
201
249
  expect(actions).toHaveLength(1);
202
250
  });
203
251
 
204
252
  it("gallery-qb: initial batch ready when all initial items loaded", () => {
205
- const store = {
253
+ const store = mockStore({
206
254
  zappPipes: {
207
255
  url1: {
208
256
  loading: false,
@@ -210,19 +258,20 @@ describe("useBatchLoading", () => {
210
258
  data: {},
211
259
  },
212
260
  },
213
- };
261
+ });
262
+
263
+ useDispatchSpy.mockReturnValue(store.dispatch);
214
264
 
215
265
  const initialBatchSize = 3;
216
266
  const riverId = "123";
217
267
 
218
- const data = [
268
+ const data: Partial<ZappUIComponent>[] = [
219
269
  {
220
270
  component_type: "gallery-qb",
221
- data: {},
222
- ui_components: [{ data: { source: "url1" } }] as any,
271
+ ui_components: [{ data: { source: "url1" } }],
223
272
  },
224
- { data: { source: "url2" }, component_type: "any" },
225
- { data: { source: "url3" }, component_type: "any" },
273
+ { data: { source: "url2" } },
274
+ { data: { source: "url3" } },
226
275
  ];
227
276
 
228
277
  const { result } = renderHook(
@@ -1,7 +1,7 @@
1
- import { isNil, complement, compose, map, min, prop, take, uniq } from "ramda";
1
+ import { complement, compose, isNil, map, min, prop, take, uniq } from "ramda";
2
2
  import { useDispatch } from "react-redux";
3
3
  import * as React from "react";
4
- import { useZappPipesFeeds } from "@applicaster/zapp-react-native-redux/hooks/useZappPipesFeeds";
4
+ import { useZappPipesFeeds } from "@applicaster/zapp-react-native-redux/hooks";
5
5
  import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
6
6
  import { isNilOrEmpty } from "../../reactUtils/helpers";
7
7
  import { ZappPipesSearchContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
@@ -9,6 +9,7 @@ import {
9
9
  getInflatedDataSourceUrl,
10
10
  getSearchContext,
11
11
  } from "@applicaster/zapp-react-native-utils/reactHooks";
12
+ import { isGallery } from "@applicaster/zapp-react-native-utils/componentsUtils";
12
13
  import { useScreenContext } from "../screen/useScreenContext";
13
14
 
14
15
  type Options = {
@@ -46,9 +47,7 @@ const filterEmptyData = (data) => {
46
47
  };
47
48
 
48
49
  const getData = (rawData) =>
49
- rawData.component_type === "gallery-qb"
50
- ? rawData.ui_components[0].data
51
- : rawData.data;
50
+ isGallery(rawData) ? rawData.ui_components[0].data : rawData.data;
52
51
 
53
52
  const extractData = compose(uniq, map(getData));
54
53
 
@@ -70,13 +69,12 @@ export const useBatchLoading = (
70
69
  const [hasEverBeenReady, setHasEverBeenReady] = React.useState(false);
71
70
 
72
71
  // if first component is gallery-qb, take only one component for initial load
73
- const takeSize =
74
- componentsToRender?.[0]?.component_type === "gallery-qb"
75
- ? 1
76
- : min(
77
- options.initialBatchSize ?? DEFAULT_BATCH_SIZE,
78
- componentsToRender.length
79
- );
72
+ const takeSize = isGallery(componentsToRender?.[0])
73
+ ? 1
74
+ : min(
75
+ options.initialBatchSize ?? DEFAULT_BATCH_SIZE,
76
+ componentsToRender.length
77
+ );
80
78
 
81
79
  const takeBatchSize = React.useCallback(take(takeSize), [takeSize]);
82
80
 
@@ -5,7 +5,7 @@ import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
5
5
  import { useZappPipesFeed } from "@applicaster/zapp-react-native-redux/hooks";
6
6
 
7
7
  import { reactHooksLogger } from "../logger";
8
- import { useIsInitialRender, shouldDispatchData } from "../utils";
8
+ import { shouldDispatchData, useIsInitialRender } from "../utils";
9
9
  import { useInflatedUrl } from "./useInflatedUrl";
10
10
  import { useRoute } from "../navigation";
11
11
 
@@ -20,6 +20,7 @@ type Props = {
20
20
  silentRefresh?: boolean;
21
21
  method?: "get" | "post";
22
22
  bodyParams?: Record<string, unknown>;
23
+ skipLoading?: boolean;
23
24
  };
24
25
  };
25
26
 
@@ -55,7 +56,9 @@ export const useFeedLoader = ({
55
56
 
56
57
  const currentFeed = useZappPipesFeed(callableFeedUrl);
57
58
 
58
- const riverId = screenData?.id;
59
+ const riverId =
60
+ (screenData as LegacyNavigationScreenData)?.targetScreen?.id ??
61
+ screenData?.id;
59
62
 
60
63
  const reloadData = React.useCallback<ReloadDataFunction>(
61
64
  (silentRefresh = true, callback) => {
@@ -93,7 +96,7 @@ export const useFeedLoader = ({
93
96
  if (
94
97
  shouldDispatchData(callableFeedUrl, currentFeed, pipesOptions.clearCache)
95
98
  ) {
96
- if (callableFeedUrl) {
99
+ if (callableFeedUrl && !pipesOptions.skipLoading) {
97
100
  dispatch(
98
101
  loadPipesData(callableFeedUrl, {
99
102
  ...pipesOptions,
@@ -101,26 +104,33 @@ export const useFeedLoader = ({
101
104
  riverId,
102
105
  })
103
106
  );
104
- } else {
107
+ } else if (!callableFeedUrl) {
105
108
  logger.info({
106
109
  message:
107
110
  "Feed is not defined or not inflated, skipping loading. \nMake sure you have correct feedUrl and mapping.",
108
111
  jsOnly: true,
109
112
  });
113
+ } else {
114
+ logger.info({
115
+ message:
116
+ "Loading skipped as per pipesOptions.skipLoading configuration.",
117
+ data: { url: callableFeedUrl },
118
+ jsOnly: true,
119
+ });
110
120
  }
111
121
  } else {
112
122
  logger.info({
113
123
  message:
114
- "Feed already exist, skipping loading. \nCall reloadData() if you want to refresh data.",
124
+ "Feed already exists, skipping loading. \nCall reloadData() if you want to refresh data.",
115
125
  data: { url: callableFeedUrl },
116
126
  jsOnly: true,
117
127
  });
118
128
  }
119
129
  }, []);
120
130
 
121
- // Reload feed when feedUrl changes
131
+ // Reload feed when feedUrl changes, unless skipLoading is true
122
132
  useEffect(() => {
123
- if (!isInitialRender && callableFeedUrl) {
133
+ if (!isInitialRender && callableFeedUrl && !pipesOptions.skipLoading) {
124
134
  dispatch(loadPipesData(callableFeedUrl, { ...pipesOptions, riverId }));
125
135
  }
126
136
  }, [callableFeedUrl]);
@@ -156,7 +166,6 @@ export const useFeedLoader = ({
156
166
  currentFeed?.data,
157
167
  currentFeed?.error,
158
168
  currentFeed?.loading,
159
-
160
169
  reloadData,
161
170
  loadNext,
162
171
  ]);
@@ -0,0 +1,39 @@
1
+ import { reactHooksLogger } from "../../logger";
2
+ import { useZappHooksModalState } from "@applicaster/zapp-react-dom-ui-components/Components/ZappHooksModal/hooks/useZappHooksModalState";
3
+
4
+ const logger = reactHooksLogger.addSubsystem("useHookModalScreenData");
5
+
6
+ type VariousScreenData = LegacyNavigationScreenData | ZappRiver | ZappEntry;
7
+
8
+ export const useHookModalScreenData = (): VariousScreenData | undefined => {
9
+ const hookModalState = useZappHooksModalState();
10
+
11
+ if (!hookModalState.state?.screenData) {
12
+ return;
13
+ }
14
+
15
+ try {
16
+ const screenData = hookModalState.state.screenData?.payload;
17
+ const hookPlugin = hookModalState.state.screenData.hookPlugin;
18
+
19
+ if (hookPlugin?.screen_id) {
20
+ return {
21
+ ...screenData,
22
+ targetScreen: hookPlugin,
23
+ };
24
+ }
25
+
26
+ return hookModalState.state.screenData?.payload;
27
+ } catch (error) {
28
+ logger.error({
29
+ message: "Hook modal screen data creation failed",
30
+ data: {
31
+ error,
32
+ hookModalState,
33
+ },
34
+ jsOnly: true,
35
+ });
36
+
37
+ return hookModalState.state.screenData?.payload;
38
+ }
39
+ };
@@ -3,7 +3,7 @@ import { platformSelect } from "../../reactUtils";
3
3
  const TAB_BAR_HEIGHT_IOS = 49;
4
4
  const TAB_BAR_HEIGHT_ANDROID = 56;
5
5
 
6
- export const useGetTabBarHeight = () =>
6
+ export const getTabBarHeight = () =>
7
7
  platformSelect({
8
8
  ios: TAB_BAR_HEIGHT_IOS,
9
9
  android: TAB_BAR_HEIGHT_ANDROID,
@@ -108,9 +108,11 @@ export function isNavBarVisible(
108
108
  return false;
109
109
  }
110
110
 
111
- const showSecondaryLevel = screenData?.navigations?.some(
112
- (navigation) => navigation.styles?.show_secondary_level_menu
113
- );
111
+ const showSecondaryLevel =
112
+ !isTV() ||
113
+ screenData?.navigations?.some(
114
+ (navigation) => navigation.styles?.show_secondary_level_menu
115
+ );
114
116
 
115
117
  if (canGoBack && !showSecondaryLevel) {
116
118
  return false;
@@ -125,10 +127,10 @@ export function isNavBarVisible(
125
127
 
126
128
  export const useBackHandler = (cb: () => boolean) => {
127
129
  useEffect(() => {
128
- const unsubscribe = BackHandler.addEventListener("hardwareBackPress", cb);
130
+ BackHandler.addEventListener("hardwareBackPress", cb);
129
131
 
130
132
  return () => {
131
- unsubscribe.remove();
133
+ BackHandler.removeEventListener("hardwareBackPress", cb);
132
134
  };
133
135
  }, [cb]);
134
136
  };
@@ -1,12 +1,19 @@
1
1
  import { useGetNavBarTopBorderWidth } from "./useGetNavBarTopBorderWidth";
2
- import { useGetTabBarHeight } from "./useGetTabBarHeight";
2
+ import { getTabBarHeight } from "./getTabBarHeight";
3
+ import { useNavigation } from "./useNavigation";
3
4
  import { MenuTypes, useNavigationType } from "./useNavigationType";
5
+ import { useNavigationPluginData } from "./useNavigationPluginData";
4
6
 
5
7
  export const useGetBottomTabBarHeight = (): number => {
8
+ const { activeRiver } = useNavigation();
9
+
10
+ const navigationPluginData = useNavigationPluginData(activeRiver);
11
+ const navigationType = useNavigationType(navigationPluginData);
12
+
6
13
  const topBorderWidth = useGetNavBarTopBorderWidth();
7
- const tabBarHeight = useGetTabBarHeight();
14
+ const tabBarHeight = getTabBarHeight();
8
15
 
9
- const isBottomBarNavigation = useNavigationType() === MenuTypes.bottomTabBar;
16
+ const isBottomBarNavigation = navigationType === MenuTypes.bottomTabBar;
10
17
 
11
18
  return !isBottomBarNavigation ? 0 : tabBarHeight + topBorderWidth;
12
19
  };
@@ -1,13 +1,17 @@
1
1
  import { useRoute } from "./useRoute";
2
2
 
3
- export const useNavigationPluginData = (): ZappNavigation | undefined => {
3
+ export const useNavigationPluginData = (
4
+ screenData?: LegacyNavigationScreenData | null
5
+ ): ZappNavigation | undefined => {
4
6
  const {
5
7
  screenData: useRouteScreenData,
6
8
  }: { screenData: QuickBrickNavigationData | null } = useRoute();
7
9
 
8
- const navigations = useRouteScreenData?.targetScreen
9
- ? (useRouteScreenData.targetScreen as ZappRiver).navigations
10
- : (useRouteScreenData as ZappRiver).navigations;
10
+ const activeScreenData = screenData ?? useRouteScreenData;
11
+
12
+ const navigations = activeScreenData?.targetScreen
13
+ ? (activeScreenData.targetScreen as ZappRiver).navigations
14
+ : (activeScreenData as ZappRiver).navigations;
11
15
 
12
16
  const navigationMenu = navigations?.find((nav) => nav.category === "menu");
13
17
 
@@ -5,8 +5,10 @@ export enum MenuTypes {
5
5
  bottomTabBar = "BOTTOM_TAB_BAR",
6
6
  }
7
7
 
8
- export const useNavigationType = (): MenuTypes => {
9
- const navigationMenu = useNavigationPluginData();
8
+ export const useNavigationType = (navigation?: ZappNavigation): MenuTypes => {
9
+ const navigationPluginData = useNavigationPluginData();
10
+
11
+ const navigationMenu = navigation ?? navigationPluginData;
10
12
 
11
13
  return !navigationMenu ||
12
14
  navigationMenu.navigation_type === "quick_brick_side_menu"
@@ -7,12 +7,11 @@ import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
7
7
 
8
8
  import { legacyScreenData } from "@applicaster/quick-brick-core/App/NavigationProvider/utils";
9
9
 
10
- import { useZappHooksModalState } from "@applicaster/zapp-react-dom-ui-components/Components/ZappHooksModal/hooks/useZappHooksModalState";
11
-
12
10
  import { getTargetScreenData } from "../screen/useTargetScreenData";
11
+ import { useHookModalScreenData } from "../hookModal/hooks/useHookModalScreenData";
13
12
 
14
13
  import { useNavigation } from "./useNavigation";
15
- import { useModalStore } from "../../modalState";
14
+ import { useModalStoreState } from "../../modalState";
16
15
  import { ScreenDataContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";
17
16
  import { usePathname } from "./usePathname";
18
17
 
@@ -44,12 +43,11 @@ export const useRoute = (): {
44
43
  "contentTypes",
45
44
  ]);
46
45
 
47
- const { modalState } = useModalStore();
48
- const hookModalState = useZappHooksModalState();
46
+ const modalState = useModalStoreState();
49
47
 
50
48
  const modalScreenData = modalState.screen;
51
49
 
52
- const hookModalScreenData = hookModalState.state.screenData?.payload;
50
+ const hookModalScreenData = useHookModalScreenData();
53
51
 
54
52
  const videoModalScreenData =
55
53
  navigator?.videoModalState?.item &&
@@ -0,0 +1,69 @@
1
+ import { renderHook } from "@testing-library/react-hooks";
2
+
3
+ jest.mock(
4
+ "@applicaster/zapp-react-native-ui-components/Components/River/useScreenConfiguration",
5
+ () => ({
6
+ useScreenConfiguration: jest.fn(),
7
+ })
8
+ );
9
+
10
+ const {
11
+ useScreenConfiguration,
12
+ } = require("@applicaster/zapp-react-native-ui-components/Components/River/useScreenConfiguration");
13
+
14
+ const { useScreenBackgroundColor } = require("../useScreenBackgroundColor");
15
+
16
+ describe("useScreenBackgroundColor", () => {
17
+ afterEach(() => {
18
+ jest.clearAllMocks();
19
+ });
20
+
21
+ it("should return the background color from screen configuration", () => {
22
+ useScreenConfiguration.mockReturnValue({
23
+ backgroundColor: "#FF0000",
24
+ });
25
+
26
+ // Render the hook with a screen ID
27
+ const { result } = renderHook(() =>
28
+ useScreenBackgroundColor("test-screen-id")
29
+ );
30
+
31
+ expect(result.current).toBe("#FF0000");
32
+
33
+ expect(useScreenConfiguration).toHaveBeenCalledWith("test-screen-id");
34
+ });
35
+
36
+ it("should return 'transparent' when background color is empty", () => {
37
+ useScreenConfiguration.mockReturnValue({
38
+ backgroundColor: "",
39
+ });
40
+
41
+ const { result } = renderHook(() =>
42
+ useScreenBackgroundColor("test-screen-id")
43
+ );
44
+
45
+ expect(result.current).toBe("transparent");
46
+ });
47
+
48
+ it("should return 'transparent' when background color is null", () => {
49
+ useScreenConfiguration.mockReturnValue({
50
+ backgroundColor: null,
51
+ });
52
+
53
+ const { result } = renderHook(() =>
54
+ useScreenBackgroundColor("test-screen-id")
55
+ );
56
+
57
+ expect(result.current).toBe("transparent");
58
+ });
59
+
60
+ it("should return 'transparent' when background color is undefined", () => {
61
+ useScreenConfiguration.mockReturnValue({});
62
+
63
+ const { result } = renderHook(() =>
64
+ useScreenBackgroundColor("test-screen-id")
65
+ );
66
+
67
+ expect(result.current).toBe("transparent");
68
+ });
69
+ });
@@ -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
  };
@@ -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
+ };