@applicaster/zapp-react-native-utils 12.0.0-alpha.4534459584 → 12.0.0-alpha.4536343143

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 (99) hide show
  1. package/actionsExecutor/ActionExecutorContext.tsx +16 -8
  2. package/analyticsUtils/AnalyticsEvents/index.ts +13 -0
  3. package/analyticsUtils/AnalyticsEvents/searchEvents.ts +21 -0
  4. package/analyticsUtils/AnalyticsEvents/sendShareEvent.ts +21 -0
  5. package/analyticsUtils/__tests__/analyticsManager.test.js +75 -73
  6. package/analyticsUtils/analyticsPlugins.ts +25 -0
  7. package/analyticsUtils/events.ts +12 -0
  8. package/analyticsUtils/helpers/hooks.ts +1 -1
  9. package/analyticsUtils/index.tsx +12 -0
  10. package/appUtils/HooksManager/index.js +3 -1
  11. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +2 -3
  12. package/appUtils/focusManager/__tests__/focusManager.test.js +4 -24
  13. package/appUtils/focusManager/__tests__/index.test.ts +2 -3
  14. package/appUtils/focusManager/index.ts +76 -56
  15. package/appUtils/focusManager/treeDataStructure/Utils/index.js +74 -34
  16. package/appUtils/focusManager/utils/index.ts +100 -0
  17. package/appUtils/focusManagerAux/index.ts +76 -0
  18. package/appUtils/focusManagerAux/utils/index.ts +100 -0
  19. package/appUtils/keyCodes/__tests__/__snapshots__/keyCodes.test.js.snap +1 -1
  20. package/appUtils/keyCodes/__tests__/keyCodes.test.js +80 -85
  21. package/appUtils/keyCodes/keys.web.js +1 -0
  22. package/appUtils/orientationHelper.ts +1 -1
  23. package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +53 -0
  24. package/appUtils/playerManager/conts.ts +5 -0
  25. package/appUtils/playerManager/player.ts +47 -4
  26. package/appUtils/playerManager/playerFactory.ts +15 -1
  27. package/appUtils/playerManager/playerNative.ts +36 -1
  28. package/appUtils/playerManager/usePlayerControllerSetup.tsx +6 -1
  29. package/appUtils/playerManager/usePlayerState.tsx +13 -1
  30. package/appUtils/playerManager/usePlayerTitleSummaryOverlay.tsx +50 -0
  31. package/arrayUtils/__tests__/isFilledArray.test.ts +63 -0
  32. package/arrayUtils/index.ts +5 -0
  33. package/cellUtils/__tests__/cellUtils.test.ts +48 -0
  34. package/cellUtils/__tests__/fixtures.ts +13 -0
  35. package/cellUtils/index.ts +40 -2
  36. package/dateUtils/index.ts +11 -0
  37. package/focusManager/index.ts +1 -1
  38. package/functionUtils/__tests__/__snapshots__/functionUtils.test.js.snap +2 -2
  39. package/functionUtils/__tests__/functionUtils.test.js +244 -248
  40. package/headersUtils/index.ts +1 -0
  41. package/inflatedUrlUtils/index.ts +4 -4
  42. package/localizationUtils/__tests__/localizationUtils.test.ts +78 -55
  43. package/localizationUtils/index.ts +13 -19
  44. package/logger/index.ts +1 -1
  45. package/manifestUtils/defaultManifestConfigurations/generalContent.js +6 -0
  46. package/manifestUtils/defaultManifestConfigurations/player.js +10 -1
  47. package/manifestUtils/index.js +5 -1
  48. package/manifestUtils/secondaryImage/index.js +18 -15
  49. package/modalState/index.ts +57 -0
  50. package/navigationUtils/index.ts +56 -7
  51. package/numberUtils/__tests__/isLikeNumber.test.ts +18 -0
  52. package/numberUtils/index.ts +9 -18
  53. package/package.json +3 -2
  54. package/playerUtils/configurationGenerator.ts +11 -1
  55. package/pluginUtils/index.ts +11 -7
  56. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +2 -0
  57. package/reactHooks/autoscrolling/__tests__/{useTrackedView.test.ts → useTrackedView.test.tsx} +18 -1
  58. package/reactHooks/cell-click/__tests__/index.test.js +16 -3
  59. package/reactHooks/cell-click/index.ts +14 -14
  60. package/reactHooks/device/index.ts +0 -1
  61. package/reactHooks/device/useIsTablet.tsx +28 -3
  62. package/reactHooks/device/useMemoizedIsTablet.ts +1 -1
  63. package/reactHooks/device/useOrientation.tsx +3 -1
  64. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +30 -70
  65. package/reactHooks/feed/__tests__/useInflatedUrl.test.ts +18 -3
  66. package/reactHooks/feed/useBuildPipesUrl.ts +7 -10
  67. package/reactHooks/feed/useInflatedUrl.ts +44 -15
  68. package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +16 -9
  69. package/reactHooks/index.ts +2 -0
  70. package/reactHooks/layout/__tests__/{index.test.js → index.test.tsx} +66 -59
  71. package/reactHooks/layout/getDeviceInfo/index.ts +4 -2
  72. package/reactHooks/layout/index.ts +2 -1
  73. package/reactHooks/layout/types/index.ts +2 -0
  74. package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.native.test.js +11 -16
  75. package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.test.js +12 -14
  76. package/reactHooks/layout/useDimensions/useDimensions.ts +13 -7
  77. package/reactHooks/navigation/__mocks__/index.ts +15 -0
  78. package/reactHooks/navigation/__mocks__/useNavigation.ts +7 -0
  79. package/reactHooks/navigation/__tests__/index.test.tsx +240 -81
  80. package/reactHooks/navigation/index.ts +230 -81
  81. package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +3 -1
  82. package/reactHooks/screen/__mocks__/useScreenContext.ts +3 -1
  83. package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +21 -23
  84. package/reactHooks/screen/index.ts +4 -0
  85. package/reactHooks/screen/useScreenBackgroundColor.ts +23 -0
  86. package/reactHooks/screen/useScreenContext.ts +4 -4
  87. package/reactHooks/screen/useScreenData.ts +1 -1
  88. package/reactHooks/screen/useTargetScreenData.ts +7 -0
  89. package/reactHooks/state/useRivers.ts +3 -1
  90. package/reactHooks/useListenEventBusEvent.ts +1 -4
  91. package/reactHooks/videoModal/hooks/useVideoModalScreenData.tsx +10 -9
  92. package/riverComponetsMeasurementProvider/index.tsx +2 -2
  93. package/stringUtils/index.ts +5 -0
  94. package/testUtils/getByTestId.ts +14 -0
  95. package/testUtils/index.tsx +38 -23
  96. package/types.ts +4 -0
  97. package/reactHooks/device/useIsTablet.android.tsx +0 -14
  98. package/reactHooks/device/useIsTablet.ios.tsx +0 -7
  99. package/reactHooks/device/useIsTablet.web.tsx +0 -3
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable @typescript-eslint/no-use-before-define */
2
2
  /* eslint max-len: off */
3
3
 
4
- import React, { useEffect, useMemo } from "react";
4
+ import React, { useContext, useEffect, useMemo } from "react";
5
5
  import { BackHandler, InteractionManager, NativeModules } from "react-native";
6
6
  import { useSafeAreaInsets } from "react-native-safe-area-context";
7
7
 
@@ -12,23 +12,113 @@ import {
12
12
  import { HooksManager } from "@applicaster/zapp-react-native-utils/appUtils/HooksManager";
13
13
 
14
14
  import { legacyScreenData } from "@applicaster/quick-brick-core/App/NavigationProvider/utils";
15
- import { LONG_KEY_PRESS_TIMEOUT } from "@applicaster/quick-brick-core/const";
15
+ import {
16
+ LONG_KEY_PRESS_TIMEOUT,
17
+ QUICK_BRICK_NAVBAR,
18
+ QUICK_BRICK_CONTENT,
19
+ } from "@applicaster/quick-brick-core/const";
16
20
  import { useZappHooksModalState } from "@applicaster/zapp-react-dom-ui-components/Components/ZappHooksModal/ZappHooksModal";
17
21
  import { ZappHookModalContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
18
22
  import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
19
23
  import { HookModalContextT } from "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext";
20
- import { getNavigationProps } from "@applicaster/zapp-react-native-utils/navigationUtils";
21
24
  import { HOOKS_EVENTS } from "../../appUtils/HooksManager/constants";
22
- import { getRiverFromRoute, getTargetRoute } from "../../navigationUtils";
25
+ import {
26
+ getNavigationProps,
27
+ getRiverFromRoute,
28
+ getTargetRoute,
29
+ } from "../../navigationUtils";
23
30
  import { platformSelect } from "../../reactUtils";
24
31
  import { useConnectionInfo } from "../connection";
25
32
  import { getTargetScreenData } from "../screen/useTargetScreenData";
26
- import { useNavbarState } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
27
33
 
34
+ import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
35
+ import { useNavbarState } from "../screen";
28
36
  import { useNavigation } from "./useNavigation";
37
+ import { useModalStore } from "../../modalState";
38
+ import { ScreenDataContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";
29
39
 
30
40
  export { useNavigation } from "./useNavigation";
31
41
 
42
+ /**
43
+ * This function helps to decide wether the navbar should be presented on the screen
44
+ * based on route and / or screen Data
45
+ *
46
+ * Currently the scenarios include
47
+ * - players => false
48
+ * - search screen plugin => false
49
+ * - hooks with `showNavBar: true` or `presentFullScreen` not set to true, defaults to no navbar for hook screens
50
+ * - screens with `allow_screen_plugin_presentation` in general property => false
51
+ *
52
+ * @param {String} route current route of the screen
53
+ * @param {Object} screenData payload associated with the currently presented screen
54
+ * @returns {Boolean}
55
+ */
56
+ export function isNavBarVisible(
57
+ route: string,
58
+ screenData: ZappRiver = {} as ZappRiver,
59
+ showNavBar: boolean,
60
+ canGoBack: boolean,
61
+ videoModalState: QuickBrickVideoModalState | null = null
62
+ ) {
63
+ /* screenData is not actual navigator.data
64
+ * or navigator.screenData,
65
+ * but navigator.data.screen */
66
+ if (route.includes("playable")) {
67
+ return false;
68
+ }
69
+
70
+ if (
71
+ videoModalState?.mode === "FULLSCREEN" &&
72
+ videoModalState?.visible === true
73
+ ) {
74
+ return false;
75
+ }
76
+
77
+ if (screenData?.type === "qb_search_screen" && !isTV()) {
78
+ return false;
79
+ }
80
+
81
+ /* Match if screen is Hook */
82
+ if (route.startsWith("/hooks/")) {
83
+ const module = screenData?.module;
84
+
85
+ if (module?.presentFullScreen) {
86
+ return false;
87
+ }
88
+
89
+ return module?.showNavBar ?? false;
90
+ }
91
+
92
+ if (screenData?.hookPlugin) {
93
+ const hookPlugin = screenData?.hookPlugin?.module;
94
+
95
+ return (
96
+ hookPlugin?.showNavBar || hookPlugin?.presentFullScreen !== true || false
97
+ );
98
+ }
99
+
100
+ if (
101
+ screenData?.general?.allow_screen_plugin_presentation ||
102
+ screenData?.general?.hide_app_nav_bar
103
+ ) {
104
+ return false;
105
+ }
106
+
107
+ const hideSecondaryLevel = screenData?.navigations?.some(
108
+ (navigation) => navigation.styles?.hide_secondary_level_menu
109
+ );
110
+
111
+ if (canGoBack && hideSecondaryLevel) {
112
+ return false;
113
+ }
114
+
115
+ if (typeof showNavBar === "boolean" && !showNavBar) {
116
+ return false;
117
+ }
118
+
119
+ return true;
120
+ }
121
+
32
122
  const { ProfilerBridge } = NativeModules;
33
123
 
34
124
  export const usePathname = () => React.useContext(PathnameContext);
@@ -43,6 +133,88 @@ export const useBackHandler = (cb: () => boolean) => {
43
133
  }, [cb]);
44
134
  };
45
135
 
136
+ // starts with modal/
137
+ const isModalPathname = (pathname: string) => /^modal\//.test(pathname);
138
+
139
+ const isVideoModalPathname = (pathname: string) =>
140
+ /^video-modal\//.test(pathname);
141
+
142
+ const isHookModalPathname = (pathname: string) =>
143
+ /^hooks-modal\//.test(pathname);
144
+
145
+ const isHookPathname = (pathname: string) => /^\/hooks\//.test(pathname);
146
+
147
+ type VariousScreenData = LegacyNavigationScreenData | ZappRiver | ZappEntry;
148
+
149
+ export const useRoute = (): {
150
+ screenData: VariousScreenData;
151
+ pathname: string;
152
+ } => {
153
+ const pathname = usePathname() || "";
154
+ const navigator = useNavigation();
155
+ const screenDataContext = legacyScreenData(useContext(ScreenDataContext));
156
+
157
+ const { plugins, contentTypes, rivers } = usePickFromState([
158
+ "plugins",
159
+ "rivers",
160
+ "contentTypes",
161
+ ]);
162
+
163
+ const { modalState } = useModalStore();
164
+ const hookModalState = useZappHooksModalState();
165
+
166
+ const modalScreenData = modalState.screen;
167
+
168
+ const hookModalScreenData = hookModalState.state.screenData?.payload;
169
+
170
+ const videoModalScreenData =
171
+ navigator.videoModalState?.item &&
172
+ legacyScreenData(
173
+ {
174
+ entry: navigator.videoModalState?.item as ZappEntry,
175
+ screen: getTargetScreenData(
176
+ navigator.videoModalState?.item as ZappEntry,
177
+ rivers,
178
+ contentTypes
179
+ ),
180
+ },
181
+ plugins
182
+ );
183
+
184
+ // There are 4 route scenarios
185
+ // For regular screens take date from navigator stack.
186
+ // is path is model grab screenData from modal state
187
+ // if path is video modal grab screenData from video state
188
+ // if path is hook modal grab screenData from hook state
189
+ // if path is hook grab screenData from screenData
190
+
191
+ if (isModalPathname(pathname)) {
192
+ const screenData = modalScreenData ?? ({} as ZappEntry);
193
+
194
+ return { screenData, pathname };
195
+ }
196
+
197
+ if (isVideoModalPathname(pathname)) {
198
+ const screenData = videoModalScreenData as LegacyNavigationScreenData;
199
+
200
+ return { screenData, pathname };
201
+ }
202
+
203
+ if (isHookModalPathname(pathname)) {
204
+ const screenData = hookModalScreenData;
205
+
206
+ return { screenData, pathname };
207
+ }
208
+
209
+ if (isHookPathname(pathname)) {
210
+ return { screenData: screenDataContext, pathname };
211
+ }
212
+
213
+ const screenData = screenDataContext;
214
+
215
+ return { screenData, pathname };
216
+ };
217
+
46
218
  type Callbacks = Partial<{
47
219
  handleHookPresent: ({
48
220
  route,
@@ -209,7 +381,7 @@ export const useRunIfLongPress = (
209
381
  React.useRef<Nullable<ReturnType<typeof setTimeout>>>(null);
210
382
 
211
383
  const resetTimeout = () => {
212
- clearTimeout(pressTimeout.current);
384
+ clearTimeout(pressTimeout.current as ReturnType<typeof setTimeout>);
213
385
  };
214
386
 
215
387
  const startTimeout = (cb: () => void) => {
@@ -231,102 +403,79 @@ export const useRunIfLongPress = (
231
403
  * @returns boolean - navbar visiblity status
232
404
  */
233
405
  export const useIsNavBarVisible = (): boolean => {
234
- const visible = useNavbarState().visible;
406
+ const { visible } = useNavbarState();
235
407
 
236
408
  return useMemo(() => visible, [visible]);
237
409
  };
238
410
 
239
- const isModalPathname = (pathname: string) => /^modal\//.test(pathname);
240
-
241
- const isVideoModalPathname = (pathname: string) =>
242
- /^video-modal\//.test(pathname);
243
-
244
- const isHookModalPathname = (pathname: string) =>
245
- /^hooks-modal\//.test(pathname);
246
-
247
- export const useRoute = () => {
248
- const pathname = usePathname() || "";
411
+ const useGetNavBarTopBorderWidth = (): number => {
249
412
  const navigator = useNavigation();
250
413
 
251
- const { plugins, contentTypes, rivers } = usePickFromState([
252
- "plugins",
253
- "rivers",
254
- "contentTypes",
255
- ]);
414
+ const navProps = getNavigationProps({
415
+ navigator,
416
+ title: "",
417
+ category: "menu",
418
+ });
256
419
 
257
- const currentStack = navigator.getStackForPathname(pathname);
258
- const modalState = navigator.modalState;
259
- const hookModalState = useZappHooksModalState();
420
+ return Number(((navProps?.styles as any)?.top_border_width as number) ?? 0);
421
+ };
260
422
 
261
- const modalScreenData = modalState.screen;
423
+ const TAB_BAR_HEIGHT_IOS = 49;
424
+ const TAB_BAR_HEIGHT_ANDROID = 56;
262
425
 
263
- const hookModalScreenData = hookModalState.state.screenData?.payload;
426
+ const useGetTabBarHeight = () =>
427
+ platformSelect({
428
+ ios: TAB_BAR_HEIGHT_IOS + (useSafeAreaInsets().bottom ?? 0),
429
+ android: TAB_BAR_HEIGHT_ANDROID,
430
+ }) as number;
264
431
 
265
- const videoModalScreenData =
266
- navigator.videoModalState?.item &&
267
- legacyScreenData(
268
- {
269
- entry: navigator.videoModalState?.item,
270
- screen: getTargetScreenData(
271
- navigator.videoModalState?.item,
272
- rivers,
273
- contentTypes
274
- ),
275
- },
276
- plugins
277
- );
432
+ export const useGetBottomTabBarHeight = (): number => {
433
+ const topBorderWidth = useGetNavBarTopBorderWidth();
434
+ const tabBarHeight = useGetTabBarHeight();
278
435
 
279
- const currentRouteScreenData = legacyScreenData(
280
- {
281
- screen:
282
- currentStack?.state?.screen ??
283
- navigator.data?.screen ??
284
- ({} as ZappRiver),
285
- entry: currentStack?.state?.entry ?? ({} as ZappEntry),
286
- },
436
+ const isBottomBarNavigation = useNavigationType() === MenuTypes.bottomTabBar;
287
437
 
288
- plugins
289
- );
438
+ return !isBottomBarNavigation ? 0 : tabBarHeight + topBorderWidth;
439
+ };
290
440
 
291
- // There are 4 route scenarios
292
- // For regular screens take date from navigator stack.
293
- // is path is model grab screenData from modal state
294
- // if path is video modal grab screenData from video state
295
- // if path is hook modal grab screenData from hook state
441
+ // If current screen is active/focused (visible to the user)
442
+ export const useIsScreenActive = () => {
443
+ const pathname = usePathname();
444
+ const { currentRoute, videoModalState } = useNavigation();
296
445
 
297
- const screenData = isModalPathname(pathname)
298
- ? modalScreenData
299
- : isVideoModalPathname(pathname)
300
- ? videoModalScreenData
301
- : isHookModalPathname(pathname)
302
- ? hookModalScreenData
303
- : currentRouteScreenData;
446
+ if (
447
+ videoModalState.visible &&
448
+ ["FULLSCREEN", "MAXIMIZED", "PIP"].includes(videoModalState.mode)
449
+ ) {
450
+ return false;
451
+ }
304
452
 
305
- return { screenData, pathname };
453
+ return pathname === currentRoute;
306
454
  };
307
455
 
308
- export const useGetBottomTabBarHeight = (): number => {
309
- const insets = useSafeAreaInsets();
310
- const navigator = useNavigation();
456
+ type Return = (prefix: string) => string;
311
457
 
312
- const navProps = getNavigationProps({
313
- navigator,
314
- title: "",
315
- category: "menu",
316
- });
458
+ export const useUniqueRouteSuffix = (): Return => {
459
+ const pathname = usePathname();
460
+ const { currentRoute } = useNavigation();
317
461
 
318
- const navType = useNavigationType();
319
- const isBottomBarNavigation = navType === MenuTypes.bottomTabBar;
462
+ const suffix = `currentRoute:${currentRoute}_pathname:${pathname}`;
320
463
 
321
- const TAB_BAR_HEIGHT_IOS = 49;
322
- const TAB_BAR_HEIGHT_ANDROID = 56;
464
+ const withUniqueRouteSuffix = React.useCallback((prefix: string) => {
465
+ return `${prefix}___${suffix}`;
466
+ }, []);
323
467
 
324
- if (!isBottomBarNavigation) return 0;
468
+ return withUniqueRouteSuffix;
469
+ };
325
470
 
326
- const tabBarHeight = platformSelect({
327
- ios: TAB_BAR_HEIGHT_IOS + insets.bottom,
328
- android: TAB_BAR_HEIGHT_ANDROID,
329
- }) as number;
471
+ export const useNavbarId = () => {
472
+ const withUniqueRouteSuffix = useUniqueRouteSuffix();
473
+
474
+ return withUniqueRouteSuffix(QUICK_BRICK_NAVBAR);
475
+ };
476
+
477
+ export const useContentId = () => {
478
+ const withUniqueRouteSuffix = useUniqueRouteSuffix();
330
479
 
331
- return tabBarHeight + Number(navProps?.styles?.top_border_width ?? 0);
480
+ return withUniqueRouteSuffix(QUICK_BRICK_CONTENT);
332
481
  };
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { View } from "react-native";
3
- import { renderHook, cleanup } from "@testing-library/react-hooks";
3
+ import { cleanup, renderHook } from "@testing-library/react-hooks";
4
4
  import configureStore from "redux-mock-store";
5
5
  import { Provider } from "react-redux";
6
6
 
@@ -12,6 +12,8 @@ jest.mock("@applicaster/zapp-react-native-utils/localizationUtils", () => ({
12
12
  useIsRTL: jest.fn(() => mock_rtl_flag),
13
13
  }));
14
14
 
15
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation");
16
+
15
17
  const { useCellResolver } = require("../useCellResolver");
16
18
 
17
19
  describe("cellResolver", () => {
@@ -1,7 +1,7 @@
1
1
  // @ts-ignore
2
2
  import { View } from "react-native";
3
3
 
4
- const mockData: NavigationScreenData = {
4
+ const mockData = {
5
5
  screen: {
6
6
  id: "screen-id",
7
7
  name: "screen",
@@ -40,3 +40,5 @@ const mockData: NavigationScreenData = {
40
40
  };
41
41
 
42
42
  export const useScreenContext = jest.fn().mockReturnValue(mockData);
43
+
44
+ export const useNavbarState = () => ({ visible: true });
@@ -3,23 +3,28 @@ import { Provider } from "react-redux";
3
3
  import { renderHook } from "@testing-library/react-hooks";
4
4
  import configureStore from "redux-mock-store";
5
5
  import thunk from "redux-thunk";
6
- import { NavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NavigationContext";
7
6
 
8
7
  const mockStore = configureStore([thunk]);
9
8
 
10
- import { useCurrentScreenData } from "../useCurrentScreenData";
11
-
12
- describe("useScreenData", function () {
13
- const river_id_2: ZappRiver = {
14
- name: "River 2",
15
- id: "A1234",
16
- home: false,
17
- home_offline: false,
18
- supports_offline: false,
19
- navigations: [],
20
- hooks: { preload_plugins: [] },
21
- };
22
-
9
+ const river_id_2: ZappRiver = {
10
+ name: "River 2",
11
+ id: "A1234",
12
+ home: false,
13
+ home_offline: false,
14
+ supports_offline: false,
15
+ navigations: [],
16
+ hooks: { preload_plugins: [] },
17
+ };
18
+
19
+ jest.mock("../useScreenContext", () => ({
20
+ useScreenContext: () => ({
21
+ screen: river_id_2,
22
+ }),
23
+ }));
24
+
25
+ const { useCurrentScreenData } = require("../useCurrentScreenData");
26
+
27
+ describe("useScreenData", () => {
23
28
  const river_id_1 = { id: "B5678" };
24
29
 
25
30
  const store = mockStore({
@@ -27,17 +32,10 @@ describe("useScreenData", function () {
27
32
  });
28
33
 
29
34
  const wrapper: React.FC<any> = ({ children }) => (
30
- <NavigationContext.Provider
31
- value={{
32
- currentRoute: "/river/river_id_1/river/river_id_2",
33
- data: { screen: river_id_2 },
34
- }}
35
- >
36
- <Provider store={store}>{children}</Provider>
37
- </NavigationContext.Provider>
35
+ <Provider store={store}>{children}</Provider>
38
36
  );
39
37
 
40
- it("should return river data for the current screen/route", function () {
38
+ it("should return river data for the current screen/route", () => {
41
39
  const { result } = renderHook(() => useCurrentScreenData(), { wrapper });
42
40
 
43
41
  expect(result.current).toBe(river_id_2);
@@ -2,9 +2,13 @@ export { useCurrentScreenData } from "./useCurrentScreenData";
2
2
 
3
3
  export { useTargetScreenData } from "./useTargetScreenData";
4
4
 
5
+ export { useScreenData } from "./useScreenData";
6
+
5
7
  export {
6
8
  useScreenContext,
7
9
  useLegacyScreenData,
8
10
  useNavbarState,
9
11
  useSetNavbarState,
10
12
  } from "./useScreenContext";
13
+
14
+ export { useScreenBackgroundColor } from "./useScreenBackgroundColor";
@@ -0,0 +1,23 @@
1
+ import * as React from "react";
2
+ import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
3
+ import { useScreenConfiguration } from "@applicaster/zapp-react-native-ui-components/Components/River/useScreenConfiguration";
4
+ import { ifEmptyUseFallback } from "@applicaster/zapp-react-native-utils/cellUtils";
5
+
6
+ export const useScreenBackgroundColor = (screenId: string): string => {
7
+ const { backgroundColor: screenBackgroundColor } =
8
+ useScreenConfiguration(screenId);
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;
23
+ };
@@ -2,11 +2,12 @@ import { useContext, useMemo } from "react";
2
2
 
3
3
  import { useModalNavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ModalNavigationContext";
4
4
  import { useNestedNavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NestedNavigationContext";
5
- import { useNavigation } from "../navigation";
5
+ import { useNavigation } from "../navigation/useNavigation";
6
6
 
7
7
  import { ScreenContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenContext";
8
+ import { ScreenDataContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";
8
9
 
9
- function useScreenContextV2() {
10
+ export function useScreenContextV2() {
10
11
  return useContext(ScreenContext);
11
12
  }
12
13
 
@@ -44,9 +45,8 @@ export function useSetNavbarState() {
44
45
 
45
46
  export function useScreenContext(): NavigationScreenData {
46
47
  const navigator = useNavigation();
48
+ const screenData = useContext(ScreenDataContext);
47
49
 
48
- const screenKey = useMemo(() => navigator?.key, [navigator]);
49
- const screenData = useMemo(() => navigator?.data, [screenKey]);
50
50
  const modalScreenData = navigator?.modalData;
51
51
 
52
52
  const isModal = useModalNavigationContext();
@@ -4,7 +4,7 @@ import { useRivers } from "../state";
4
4
 
5
5
  const logger = utilsLogger.addSubsystem("useScreenData");
6
6
 
7
- export const useScreenData = (screenId?: string): ZappRiver => {
7
+ export const useScreenData = (screenId: string): ZappRiver => {
8
8
  const rivers = useRivers();
9
9
 
10
10
  React.useEffect(() => {
@@ -1,6 +1,7 @@
1
1
  import React from "react";
2
2
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
3
3
  import * as R from "ramda";
4
+ import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
4
5
 
5
6
  export function getTargetScreenData(
6
7
  entry: ZappEntry,
@@ -35,6 +36,12 @@ export function getTargetScreenData(
35
36
  return rivers?.[screenId];
36
37
  }
37
38
 
39
+ export function getTargetScreenDataFromEntry(entry: ZappEntry): ZappRiver {
40
+ const { rivers, contentTypes } = appStore.get(["rivers", "contentTypes"]);
41
+
42
+ return getTargetScreenData(entry, rivers, contentTypes);
43
+ }
44
+
38
45
  export const useTargetScreenData = (entry: ZappEntry) => {
39
46
  const { rivers, contentTypes } = usePickFromState(["rivers", "contentTypes"]);
40
47
 
@@ -1,7 +1,9 @@
1
1
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
2
2
 
3
+ const riversSelector = ["rivers"];
4
+
3
5
  export const useRivers = () => {
4
- const { rivers } = usePickFromState(["rivers"]);
6
+ const { rivers } = usePickFromState(riversSelector as any);
5
7
 
6
8
  return rivers;
7
9
  };
@@ -13,10 +13,7 @@ export const useListenEventBusEvent = (
13
13
  // TODO: remove after implementing ReactNativeEventBusBridge on iOS
14
14
  if (Platform.OS === "android") {
15
15
  // subscribe to DeviceEventEmitter using subsciption ID
16
- const sub = DeviceEventEmitter.addListener(
17
- subscriptionID,
18
- handler
19
- );
16
+ const sub = DeviceEventEmitter.addListener(subscriptionID, handler);
20
17
 
21
18
  // ask native to start routing these events to RN
22
19
  ReactNativeEventBusBridge.subscribe(subscriptionID, { [source]: events });
@@ -1,8 +1,7 @@
1
- import {
2
- useContentTypes,
3
- usePickFromState,
4
- } from "@applicaster/zapp-react-native-redux/hooks";
1
+ import React from "react";
2
+ import { useContentTypes } from "@applicaster/zapp-react-native-redux/hooks";
5
3
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
4
+ import { useRivers } from "../../state";
6
5
 
7
6
  export const useVideoModalScreenData = ():
8
7
  | (ZappEntry & { targetScreen: any }) // TODO: fix ZappEntry type ( was ZappRiver but conflict )
@@ -12,11 +11,13 @@ export const useVideoModalScreenData = ():
12
11
  } = useNavigation();
13
12
 
14
13
  const contentTypes = useContentTypes();
15
- const { rivers } = usePickFromState(["rivers"]);
14
+ const rivers = useRivers();
16
15
 
17
- if (item?.type?.value) {
18
- const screenId = contentTypes[item?.type?.value].screen_id;
16
+ return React.useMemo(() => {
17
+ if (item?.type?.value) {
18
+ const screenId = contentTypes[item?.type?.value].screen_id;
19
19
 
20
- return { ...item, targetScreen: rivers?.[screenId] };
21
- }
20
+ return { ...item, targetScreen: rivers?.[screenId] };
21
+ }
22
+ }, [item]);
22
23
  };
@@ -3,7 +3,7 @@ import { NativeModules, StyleSheet, View } from "react-native";
3
3
  import { getXray } from "@applicaster/zapp-react-native-utils/logger";
4
4
 
5
5
  import { isApplePlatform, isWeb } from "../reactUtils";
6
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
6
+ import { useRivers } from "../reactHooks/state";
7
7
 
8
8
  const layoutReducer = (state, { payload }) => {
9
9
  return state.map((item, index, _state) => ({
@@ -58,7 +58,7 @@ export const ScreenLoadingMeasurements = ({
58
58
  numberOfComponents,
59
59
  riverId,
60
60
  }: Props) => {
61
- const { rivers } = usePickFromState(["rivers"]);
61
+ const rivers = useRivers();
62
62
  const screenData = rivers?.[riverId];
63
63
 
64
64
  const [itemsLayout, dispatchItemLayout] = React.useReducer(
@@ -152,3 +152,8 @@ export function objectToCamelCase(obj) {
152
152
  export function isString(value: unknown): value is string {
153
153
  return typeof value === "string" || value instanceof String;
154
154
  }
155
+
156
+ /** Checks if a value is a non-empty string */
157
+ export function isNotEmptyString(value: unknown): value is string {
158
+ return isString(value) && value.length > 0;
159
+ }
@@ -0,0 +1,14 @@
1
+ export const getByTestId = (wrapper, testId) => {
2
+ try {
3
+ if (wrapper?.getByTestId) {
4
+ return wrapper?.queryAllByTestId(testId)?.[0] ?? undefined;
5
+ } else if (wrapper?.root?.findByProps) {
6
+ return wrapper.root.findAllByProps({ testID: testId })?.[0] ?? undefined;
7
+ }
8
+ } catch (e) {
9
+ // eslint-disable-next-line no-console
10
+ console.log("getByTestId E:", e);
11
+
12
+ return undefined;
13
+ }
14
+ };