@applicaster/zapp-react-native-utils 12.0.0-alpha.4342066143 → 12.0.0-alpha.4354608902

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 (73) hide show
  1. package/analyticsUtils/AnalyticsEvents/index.ts +7 -0
  2. package/analyticsUtils/AnalyticsEvents/sendShareEvent.ts +21 -0
  3. package/analyticsUtils/events.ts +6 -0
  4. package/analyticsUtils/index.tsx +6 -0
  5. package/appUtils/HooksManager/{Hook.js → Hook.ts} +35 -23
  6. package/appUtils/HooksManager/{constants.js → constants.ts} +1 -1
  7. package/appUtils/HooksManager/{index.js → index.ts} +118 -111
  8. package/appUtils/HooksManager/types.ts +116 -0
  9. package/appUtils/RiverFocusManager/index.js +17 -12
  10. package/appUtils/accessibilityManager/const.ts +50 -0
  11. package/appUtils/accessibilityManager/hooks.ts +31 -0
  12. package/appUtils/accessibilityManager/index.ts +150 -0
  13. package/appUtils/accessibilityManager/logger.ts +5 -0
  14. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +2 -3
  15. package/appUtils/focusManager/__tests__/focusManager.test.js +4 -24
  16. package/appUtils/focusManager/__tests__/index.test.ts +2 -3
  17. package/appUtils/focusManager/index.ts +76 -57
  18. package/appUtils/focusManager/treeDataStructure/Tree/index.js +2 -3
  19. package/appUtils/focusManager/treeDataStructure/Utils/index.js +76 -47
  20. package/appUtils/focusManager/utils/index.ts +100 -0
  21. package/appUtils/focusManagerAux/index.ts +76 -0
  22. package/appUtils/focusManagerAux/utils/index.ts +100 -0
  23. package/appUtils/{index.js → index.ts} +2 -0
  24. package/appUtils/keyCodes/{index.js → index.ts} +2 -0
  25. package/appUtils/keyCodes/keys/index.ts +3 -0
  26. package/appUtils/keyCodes/{keys.android.js → keys/keyEventMapper.ts} +0 -19
  27. package/appUtils/keyCodes/keys/keys.android.ts +18 -0
  28. package/appUtils/keyCodes/keys/keys.ios.ts +25 -0
  29. package/appUtils/keyCodes/keys/keys.ts +15 -0
  30. package/appUtils/keyCodes/{keys.web.js → keys/keys.web.ts} +8 -0
  31. package/appUtils/keyCodes/{keysByPlatform.js → keys/keysByPlatform.ts} +11 -1
  32. package/appUtils/platform/const.ts +25 -0
  33. package/appUtils/platform/index.ts +3 -0
  34. package/appUtils/platform/platformUtils.ts +171 -0
  35. package/appUtils/playerManager/conts.ts +1 -0
  36. package/appUtils/playerManager/index.ts +11 -5
  37. package/appUtils/playerManager/nativePlayerManager.ts +12 -0
  38. package/appUtils/playerManager/player.ts +9 -3
  39. package/appUtils/playerManager/playerNative.ts +5 -14
  40. package/appUtils/playerManager/usePlayerControllerSetup.tsx +1 -0
  41. package/arrayUtils/__tests__/isFilledArray.test.ts +63 -0
  42. package/arrayUtils/index.ts +5 -0
  43. package/booleanUtils/index.ts +4 -4
  44. package/domUtils/{cookieManager.js → cookieManager.ts} +1 -2
  45. package/functionUtils/index.ts +15 -11
  46. package/keyboardState/index.ts +0 -0
  47. package/modalState/index.ts +1 -5
  48. package/navigationUtils/index.ts +62 -5
  49. package/numberUtils/__tests__/isLikeNumber.test.ts +18 -0
  50. package/numberUtils/index.ts +5 -18
  51. package/package.json +2 -2
  52. package/pluginUtils/index.ts +9 -0
  53. package/reactHooks/cell-click/__tests__/index.test.js +9 -5
  54. package/reactHooks/cell-click/index.ts +11 -11
  55. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +30 -70
  56. package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +6 -2
  57. package/reactHooks/feed/useBuildPipesUrl.ts +7 -10
  58. package/reactHooks/feed/useFeedRefresh.tsx +9 -7
  59. package/reactHooks/navigation/index.ts +51 -11
  60. package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +21 -23
  61. package/reactHooks/screen/index.ts +2 -0
  62. package/reactHooks/screen/useScreenBackgroundColor.ts +23 -0
  63. package/reactHooks/screen/useScreenContext.ts +1 -2
  64. package/reactUtils/index.ts +91 -0
  65. package/appUtils/focusManager/FocusableEvents.ts +0 -8
  66. package/appUtils/focusManager/treeDataStructure/Utils/__tests__/Utils_android.test.js +0 -1094
  67. package/appUtils/focusManager/treeDataStructure/Utils/index.android.js +0 -261
  68. package/appUtils/keyCodes/keys.ios.js +0 -46
  69. /package/appUtils/HooksManager/{logger.js → logger.ts} +0 -0
  70. /package/appUtils/{directionHelper.js → directionHelper.ts} +0 -0
  71. /package/appUtils/keyCodes/{androidTVKeys.js → androidTVKeys.ts} +0 -0
  72. /package/appUtils/{localizationsHelper.js → localizationsHelper.ts} +0 -0
  73. /package/domUtils/{logger.js → logger.ts} +0 -0
@@ -50,27 +50,14 @@ export const toFiniteNumberWithDefault = (
50
50
  return possibleNumber;
51
51
  };
52
52
 
53
- export const isLikeNumber = (value: any): boolean => {
54
- if (R.isEmpty(value)) {
55
- return false;
56
- }
57
-
58
- if (R.is(Number, value)) {
59
- return true;
60
- }
61
-
62
- if (R.is(String, value)) {
63
- const onlyDigit = value
64
- .split("")
65
- .filter((char) =>
66
- ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"].includes(char)
67
- )
68
- .join("");
53
+ export const isLikeNumber = (value: unknown): boolean => {
54
+ const possibleNumber = toNumber(value);
69
55
 
70
- return value === onlyDigit;
56
+ if (R.isNil(possibleNumber)) {
57
+ return false;
71
58
  }
72
59
 
73
- return false;
60
+ return true;
74
61
  };
75
62
 
76
63
  export const isZero = (value: unknown): boolean =>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "12.0.0-alpha.4342066143",
3
+ "version": "12.0.0-alpha.4354608902",
4
4
  "description": "Applicaster Zapp React Native utilities package",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "homepage": "https://github.com/applicaster/quickbrick#readme",
30
30
  "dependencies": {
31
- "@applicaster/applicaster-types": "12.0.0-alpha.4342066143",
31
+ "@applicaster/applicaster-types": "12.0.0-alpha.4354608902",
32
32
  "buffer": "^5.2.1",
33
33
  "camelize": "^1.0.0",
34
34
  "create-react-context": "^0.2.3",
@@ -245,3 +245,12 @@ export function generateManifest({ manifestConfig, version }) {
245
245
 
246
246
  return manifestConfig({ platform, version });
247
247
  }
248
+
249
+ const getPluginType = R.pathOr("unknown_plugin_type", [
250
+ "state",
251
+ "screen",
252
+ "plugin_type",
253
+ ]);
254
+
255
+ export const isPlayerPlugin = (routeState): boolean =>
256
+ getPluginType(routeState) === "player";
@@ -1,6 +1,8 @@
1
1
  import * as React from "react";
2
2
  import { cleanup, renderHook } from "@testing-library/react-hooks";
3
3
  import { CellTapContext } from "@applicaster/zapp-react-native-ui-components/Contexts/CellTapContext";
4
+ import { ActionExecutorContext } from "@applicaster/zapp-react-native-utils/actionsExecutor/ActionExecutorContext";
5
+
4
6
  import { waitFor } from "@testing-library/react-native";
5
7
 
6
8
  const navigator = {
@@ -29,10 +31,6 @@ jest.mock("@applicaster/zapp-react-native-ui-components/Contexts", () => ({
29
31
  },
30
32
  }));
31
33
 
32
- jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen", () => ({
33
- useScreenContext: jest.fn(() => navigator.data),
34
- }));
35
-
36
34
  const { useCellClick } = require("../");
37
35
 
38
36
  const mockProps = {
@@ -47,9 +45,15 @@ const mockProps = {
47
45
 
48
46
  const onCellTap = jest.fn();
49
47
 
48
+ const actionExecutor = {
49
+ handleEntryActions: jest.fn(() => Promise.resolve()),
50
+ };
51
+
50
52
  const wrapper = ({ children }) => (
51
53
  <CellTapContext.Provider value={onCellTap}>
52
- {children}
54
+ <ActionExecutorContext.Provider value={actionExecutor}>
55
+ {children}
56
+ </ActionExecutorContext.Provider>
53
57
  </CellTapContext.Provider>
54
58
  );
55
59
 
@@ -1,7 +1,6 @@
1
1
  /// <reference types="@applicaster/applicaster-types" />
2
2
 
3
3
  import * as React from "react";
4
- import { useContext } from "react";
5
4
  import * as R from "ramda";
6
5
  import { handleActionSchemeUrl } from "@applicaster/quick-brick-core/App/DeepLinking/URLSchemeHandler/SchemeHandlerHooks/useUrlSchemeHandler";
7
6
  import { CellTapContext } from "@applicaster/zapp-react-native-ui-components/Contexts/CellTapContext";
@@ -12,8 +11,9 @@ import {
12
11
  } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
13
12
  import { ZappPipesEntryContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
14
13
  import { toBooleanWithDefaultTrue } from "@applicaster/zapp-react-native-utils/booleanUtils";
15
- import { noop } from "../../functionUtils";
16
- import { ActionExecutorContext } from "../../actionsExecutor/ActionExecutorContext";
14
+ import { ActionExecutorContext } from "@applicaster/zapp-react-native-utils/actionsExecutor/ActionExecutorContext";
15
+
16
+ import { isFunction, noop } from "../../functionUtils";
17
17
  import { useSendAnalyticsOnPress } from "../analytics";
18
18
  import { logOnPress, warnEmptyContentType } from "./helpers";
19
19
 
@@ -30,12 +30,12 @@ type Props = {
30
30
  zappPipesData?: ZappPipesData;
31
31
  };
32
32
 
33
- export const useCellClick = (props: Props) => {
34
- const { component, zappPipesData } = props;
33
+ export const useCellClick = ({ component, zappPipesData, item }: Props) => {
35
34
  const { push, currentRoute } = useNavigation();
36
35
  const { pathname } = useRoute();
37
- const onCellTap = React.useContext(CellTapContext);
38
- const actionExecutor = useContext(ActionExecutorContext);
36
+
37
+ const onCellTap: Option<Function> = React.useContext(CellTapContext);
38
+ const actionExecutor = React.useContext(ActionExecutorContext);
39
39
 
40
40
  const cellSelectable = toBooleanWithDefaultTrue(
41
41
  component?.rules?.component_cells_selectable
@@ -47,7 +47,7 @@ export const useCellClick = (props: Props) => {
47
47
  const logTimestamp = useProfilerLogging();
48
48
 
49
49
  const sendAnalyticsOnPress = useSendAnalyticsOnPress(
50
- props.item,
50
+ item,
51
51
  component,
52
52
  zappPipesData
53
53
  );
@@ -56,7 +56,7 @@ export const useCellClick = (props: Props) => {
56
56
  async (_item?: ZappEntry | any, _index?: number) => {
57
57
  // Making sure we are not getting GestureResponderEvent in here.
58
58
  const isZappEntry = _item?.id && _item?.type;
59
- const selectedItem = isZappEntry ? _item : props.item;
59
+ const selectedItem = isZappEntry ? _item : item;
60
60
  setEntryContext?.(selectedItem);
61
61
 
62
62
  if (!selectedItem?.type?.value) {
@@ -80,8 +80,8 @@ export const useCellClick = (props: Props) => {
80
80
  });
81
81
  }
82
82
  } else {
83
- if (typeof onCellTap === "function") {
84
- onCellTap(selectedItem, _index);
83
+ if (isFunction(onCellTap)) {
84
+ onCellTap?.(selectedItem, _index);
85
85
  } else {
86
86
  if (currentRoute === pathname || pathname.includes("video-modal")) {
87
87
  const targetScreen = component?.data?.target;
@@ -1,77 +1,26 @@
1
- import React from "react";
2
1
  import { renderHook } from "@testing-library/react-hooks";
3
- import configureStore from "redux-mock-store";
4
- import thunk from "redux-thunk";
5
- import { Provider } from "react-redux";
6
-
7
2
  import { encodeParams } from "@applicaster/zapp-pipes-v2-client/src/utils";
8
3
 
9
- const mockStore = configureStore([thunk]);
10
-
11
- jest.useFakeTimers();
12
-
13
4
  const appData = {
14
5
  platform: "foo",
15
6
  version_name: "1.2.0",
16
7
  sdk_version: "2.0.0",
17
8
  };
18
9
 
19
- const pipesEndpoints = {
20
- "http://foo.com/show": {
21
- context_obj: [
22
- { type: "ctx", key: "platform" },
23
- { type: "query", mapper: "version", key: "appVersion" },
24
- { type: "header", mapper: "SDK", key: "sdkVersion" },
25
- ],
26
- },
27
- };
28
-
29
- const store_mock = { appData, pipesEndpoints };
30
-
31
- const defaultStore = mockStore({
32
- pipesEndpoints,
33
- appData,
34
- });
10
+ let INFLATED_URL;
35
11
 
36
- const wrapper: React.FC<any> = ({ children, store }) => (
37
- <Provider store={store}>{children}</Provider>
12
+ jest.mock(
13
+ "@applicaster/zapp-react-native-utils/reactHooks/feed/useInflatedUrl",
14
+ () => ({
15
+ useInflatedUrl: () => INFLATED_URL,
16
+ })
38
17
  );
39
18
 
40
- const navigator = {
41
- currentRoute: "/river/A1234",
42
- };
43
-
44
- jest.mock("../../navigation", () => ({
45
- useNavigation: jest.fn(() => navigator),
46
- useRoute: jest.fn(() => ({})),
47
- }));
48
-
49
- const contexts = {
50
- entry: { id: "show-1" },
51
- search: {},
52
- screen: {},
53
- };
54
-
55
- const contextMock = (type) => ({
56
- useZappPipesContext: () => [contexts[type] || {}],
57
- });
58
-
59
- jest.mock("@applicaster/zapp-react-native-ui-components/Contexts", () => ({
60
- ZappPipesEntryContext: contextMock("entry"),
61
- ZappPipesSearchContext: contextMock("search"),
62
- ZappPipesScreenContext: contextMock("screen"),
63
- }));
64
-
65
- jest.mock("@applicaster/zapp-react-native-redux/AppStore", () => ({
66
- appStore: {
67
- get: jest.fn((prop) => store_mock[prop]),
68
- },
69
- }));
70
-
71
19
  const { useBuildPipesUrl } = require("../useBuildPipesUrl");
72
20
 
73
21
  describe("useBuildPipesUrl", () => {
74
22
  it("returns the proper url", async () => {
23
+ INFLATED_URL = "http://foo.com/show/show-1";
75
24
  const url = "http://foo.com/show/{{showId}}";
76
25
 
77
26
  const mapping = {
@@ -81,12 +30,20 @@ describe("useBuildPipesUrl", () => {
81
30
  },
82
31
  };
83
32
 
84
- const { result, waitForNextUpdate } = renderHook(
85
- () => useBuildPipesUrl({ url, mapping }),
86
- {
87
- wrapper,
88
- initialProps: { store: defaultStore },
89
- }
33
+ const buildResult = {
34
+ params: {
35
+ ctx: encodeParams({ platform: appData.platform }),
36
+ version: appData.version_name,
37
+ },
38
+ headers: { SDK: appData.sdk_version },
39
+ };
40
+
41
+ const mockedRequestBuilder = {
42
+ build: jest.fn(() => Promise.resolve(buildResult)),
43
+ };
44
+
45
+ const { result, waitForNextUpdate } = renderHook(() =>
46
+ useBuildPipesUrl({ url, mapping, requestBuilder: mockedRequestBuilder })
90
47
  );
91
48
 
92
49
  expect(result.current.url).toBe("http://foo.com/show/show-1");
@@ -108,6 +65,7 @@ describe("useBuildPipesUrl", () => {
108
65
  });
109
66
 
110
67
  it("returns empty object if url is not in endpoints", async () => {
68
+ INFLATED_URL = "http://foobar.com/show-1";
111
69
  const url = "http://foobar.com/{{showId}}";
112
70
 
113
71
  const mapping = {
@@ -117,12 +75,14 @@ describe("useBuildPipesUrl", () => {
117
75
  },
118
76
  };
119
77
 
120
- const { result, waitForNextUpdate } = renderHook(
121
- () => useBuildPipesUrl({ url, mapping }),
122
- {
123
- wrapper,
124
- initialProps: { store: defaultStore },
125
- }
78
+ const buildResult = {};
79
+
80
+ const mockedRequestBuilder = {
81
+ build: jest.fn(() => Promise.resolve(buildResult)),
82
+ };
83
+
84
+ const { result, waitForNextUpdate } = renderHook(() =>
85
+ useBuildPipesUrl({ url, mapping, requestBuilder: mockedRequestBuilder })
126
86
  );
127
87
 
128
88
  expect(result.current.url).toBe("http://foobar.com/show-1");
@@ -1,9 +1,13 @@
1
1
  import { renderHook } from "@testing-library/react-hooks";
2
2
 
3
- import { useFeedRefresh, feedRefreshLogger } from "../";
4
-
5
3
  jest.useFakeTimers();
6
4
 
5
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
6
+ useIsScreenActive: () => true,
7
+ }));
8
+
9
+ const { useFeedRefresh, feedRefreshLogger } = require("..");
10
+
7
11
  describe("useFeedRefresh", () => {
8
12
  const reloadData = jest.fn();
9
13
 
@@ -1,7 +1,6 @@
1
- // @ts-ignore
2
1
  import { RequestBuilder } from "@applicaster/zapp-pipes-v2-client";
3
- import { useEffect, useState } from "react";
4
- import { useInflatedUrl } from "./useInflatedUrl";
2
+ import * as React from "react";
3
+ import { useInflatedUrl } from "@applicaster/zapp-react-native-utils/reactHooks/feed/useInflatedUrl";
5
4
  import { reactHooksLogger } from "../logger";
6
5
 
7
6
  export const logger = reactHooksLogger.addSubsystem("build-pipes-url");
@@ -15,18 +14,16 @@ type PipesBuildRequestObject = {
15
14
  export function useBuildPipesUrl({
16
15
  url,
17
16
  mapping = {},
17
+ requestBuilder = new RequestBuilder(),
18
18
  }): PipesBuildRequestObject {
19
- const [requestParams, setRequestParams] = useState<object | null>(null);
20
- const [error, setError] = useState(null);
19
+ const [requestParams, setRequestParams] = React.useState<object | null>(null);
21
20
 
21
+ const [error, setError] = React.useState(null);
22
22
  const inflatedUrl = useInflatedUrl({ feedUrl: url, mapping });
23
23
 
24
- const requestBuilder = new RequestBuilder();
25
-
26
24
  const buildRequest = async (_url) => {
27
25
  try {
28
26
  const result = await requestBuilder.build(_url);
29
-
30
27
  setRequestParams(result);
31
28
  } catch (e) {
32
29
  setError(e);
@@ -34,7 +31,7 @@ export function useBuildPipesUrl({
34
31
  }
35
32
  };
36
33
 
37
- useEffect(() => {
34
+ React.useEffect(() => {
38
35
  if (inflatedUrl && !requestParams) {
39
36
  buildRequest(inflatedUrl);
40
37
  }
@@ -42,7 +39,7 @@ export function useBuildPipesUrl({
42
39
 
43
40
  return {
44
41
  url: inflatedUrl || "",
45
- requestParams: requestParams, // TODO should it be: || {} ?
42
+ requestParams, // TODO should it be: || {} ?
46
43
  error: error || undefined,
47
44
  };
48
45
  }
@@ -1,7 +1,8 @@
1
1
  import * as React from "react";
2
- import * as R from "ramda";
2
+ import { path, max } from "ramda";
3
3
  import { isTrue } from "@applicaster/zapp-react-native-utils/booleanUtils";
4
4
  import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
5
+ import { useIsScreenActive } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
5
6
 
6
7
  import { reactHooksLogger } from "../logger";
7
8
  import { ReloadDataFunction } from "./useFeedLoader";
@@ -18,9 +19,8 @@ const minimumRefreshingInterval = 5;
18
19
  const defaultRefreshInterval = 60;
19
20
 
20
21
  export const useFeedRefresh = ({ reloadData, component }: Props): void => {
21
- const enable_data_refreshing = R.path(
22
- ["rules", "enable_data_refreshing"],
23
- component
22
+ const isDataRefreshingEnabled = isTrue(
23
+ path(["rules", "enable_data_refreshing"], component)
24
24
  );
25
25
 
26
26
  const refreshing_interval = toNumberWithDefault(
@@ -29,10 +29,12 @@ export const useFeedRefresh = ({ reloadData, component }: Props): void => {
29
29
  );
30
30
 
31
31
  const refreshingIntervalInMilliseconds =
32
- R.max(refreshing_interval, minimumRefreshingInterval) * 1000;
32
+ max(refreshing_interval, minimumRefreshingInterval) * 1000;
33
+
34
+ const isScreenActive = useIsScreenActive();
33
35
 
34
36
  React.useEffect(() => {
35
- if (isTrue(enable_data_refreshing) && refreshing_interval) {
37
+ if (isDataRefreshingEnabled && refreshing_interval && isScreenActive) {
36
38
  if (refreshing_interval < minimumRefreshingInterval) {
37
39
  feedRefreshLogger.warning({
38
40
  message: `You set your feed refresh interval to ${refreshing_interval} when minimum value is ${minimumRefreshingInterval}seconds.Your feed will refresh after ${minimumRefreshingInterval}seconds.`,
@@ -59,5 +61,5 @@ export const useFeedRefresh = ({ reloadData, component }: Props): void => {
59
61
  clearInterval(refreshInterval);
60
62
  };
61
63
  }
62
- }, [reloadData]);
64
+ }, [reloadData, isScreenActive]);
63
65
  };
@@ -4,7 +4,6 @@
4
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
- import { isEmpty } from "ramda";
8
7
 
9
8
  import {
10
9
  useContentTypes,
@@ -13,7 +12,11 @@ import {
13
12
  import { HooksManager } from "@applicaster/zapp-react-native-utils/appUtils/HooksManager";
14
13
 
15
14
  import { legacyScreenData } from "@applicaster/quick-brick-core/App/NavigationProvider/utils";
16
- 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";
17
20
  import { useZappHooksModalState } from "@applicaster/zapp-react-dom-ui-components/Components/ZappHooksModal/ZappHooksModal";
18
21
  import { ZappHookModalContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
19
22
  import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
@@ -28,7 +31,7 @@ import { platformSelect } from "../../reactUtils";
28
31
  import { useConnectionInfo } from "../connection";
29
32
  import { getTargetScreenData } from "../screen/useTargetScreenData";
30
33
 
31
- import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
34
+ import { isTV, isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
32
35
  import { useNavbarState } from "../screen";
33
36
  import { useNavigation } from "./useNavigation";
34
37
  import { useModalStore } from "../../modalState";
@@ -75,6 +78,10 @@ export function isNavBarVisible(
75
78
  return false;
76
79
  }
77
80
 
81
+ if (screenData?.plugin_type === "login" && isTV()) {
82
+ return false;
83
+ }
84
+
78
85
  /* Match if screen is Hook */
79
86
  if (route.startsWith("/hooks/")) {
80
87
  const module = screenData?.module;
@@ -207,10 +214,7 @@ export const useRoute = (): {
207
214
  return { screenData: screenDataContext, pathname };
208
215
  }
209
216
 
210
- // Cover cases where screenContext is used before navigation is initialized
211
- const screenData = isEmpty(screenDataContext)
212
- ? navigator.screenData
213
- : screenDataContext;
217
+ const screenData = screenDataContext;
214
218
 
215
219
  return { screenData, pathname };
216
220
  };
@@ -316,16 +320,19 @@ export const useZappHooksForEntry = (
316
320
  callbacks?.handleHookComplete?.(props);
317
321
  };
318
322
 
319
- const hookManager = HooksManager(hooksOptions)
323
+ const hookManager = HooksManager(hooksOptions);
324
+
325
+ hookManager.subscriber
320
326
  .on(HOOKS_EVENTS.PRESENT_SCREEN_HOOK, handleHookPresent)
321
327
  .on(HOOKS_EVENTS.ERROR, handleHookError)
322
328
  .on(HOOKS_EVENTS.CANCEL, handleHookCancel)
323
329
  .on(HOOKS_EVENTS.START_BACKGROUND_HOOK, handleBackgroundHook)
324
- .on(HOOKS_EVENTS.COMPLETE, handleHookComplete)
325
- .handleHooks(entry);
330
+ .on(HOOKS_EVENTS.COMPLETE, handleHookComplete);
331
+
332
+ hookManager.handleHooks(entry);
326
333
 
327
334
  return () => {
328
- hookManager
335
+ hookManager.subscriber
329
336
  .removeHandler(HOOKS_EVENTS.PRESENT_SCREEN_HOOK, handleHookPresent)
330
337
  .removeHandler(HOOKS_EVENTS.ERROR, handleHookError)
331
338
  .removeHandler(HOOKS_EVENTS.CANCEL, handleHookCancel)
@@ -452,3 +459,36 @@ export const useIsScreenActive = () => {
452
459
 
453
460
  return pathname === currentRoute;
454
461
  };
462
+
463
+ type Return = (prefix: string) => string;
464
+
465
+ export const useUniqueRouteSuffix = (): Return => {
466
+ const pathname = usePathname();
467
+ const { currentRoute } = useNavigation();
468
+
469
+ const suffix = `currentRoute:${currentRoute}_pathname:${pathname}`;
470
+
471
+ const withUniqueRouteSuffix = React.useCallback((prefix: string) => {
472
+ if (isWeb()) {
473
+ // we should use extended route prefix only on Web, where we have stack-navigator
474
+ return `${prefix}___${suffix}`;
475
+ }
476
+
477
+ // for other platforms use previous version
478
+ return prefix;
479
+ }, []);
480
+
481
+ return withUniqueRouteSuffix;
482
+ };
483
+
484
+ export const useNavbarId = () => {
485
+ const withUniqueRouteSuffix = useUniqueRouteSuffix();
486
+
487
+ return withUniqueRouteSuffix(QUICK_BRICK_NAVBAR);
488
+ };
489
+
490
+ export const useContentId = () => {
491
+ const withUniqueRouteSuffix = useUniqueRouteSuffix();
492
+
493
+ return withUniqueRouteSuffix(QUICK_BRICK_CONTENT);
494
+ };
@@ -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);
@@ -10,3 +10,5 @@ export {
10
10
  useNavbarState,
11
11
  useSetNavbarState,
12
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
+ };
@@ -45,8 +45,7 @@ export function useSetNavbarState() {
45
45
 
46
46
  export function useScreenContext(): NavigationScreenData {
47
47
  const navigator = useNavigation();
48
- // Cover cases where screenContext is used before navigation is initialized
49
- const screenData = useContext(ScreenDataContext) || navigator.data;
48
+ const screenData = useContext(ScreenDataContext);
50
49
 
51
50
  const modalScreenData = navigator?.modalData;
52
51