@applicaster/zapp-react-native-utils 12.0.0-alpha.3977160850 → 12.0.0-alpha.4043183114

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 (110) hide show
  1. package/analyticsUtils/AnalyticsEvents/index.ts +13 -0
  2. package/analyticsUtils/AnalyticsEvents/searchEvents.ts +21 -0
  3. package/analyticsUtils/AnalyticsEvents/sendShareEvent.ts +21 -0
  4. package/analyticsUtils/analyticsPlugins.ts +25 -0
  5. package/analyticsUtils/events.ts +12 -0
  6. package/analyticsUtils/index.tsx +12 -0
  7. package/appUtils/HooksManager/{Hook.js → Hook.ts} +17 -11
  8. package/appUtils/HooksManager/{constants.js → constants.ts} +1 -1
  9. package/appUtils/HooksManager/{index.js → index.ts} +101 -110
  10. package/appUtils/HooksManager/types.ts +93 -0
  11. package/appUtils/RiverFocusManager/index.js +17 -12
  12. package/appUtils/accessibilityManager/const.ts +50 -0
  13. package/appUtils/accessibilityManager/hooks.ts +31 -0
  14. package/appUtils/accessibilityManager/index.ts +150 -0
  15. package/appUtils/accessibilityManager/logger.ts +5 -0
  16. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +2 -3
  17. package/appUtils/focusManager/__tests__/focusManager.test.js +4 -24
  18. package/appUtils/focusManager/__tests__/index.test.ts +2 -3
  19. package/appUtils/focusManager/index.ts +76 -57
  20. package/appUtils/focusManager/treeDataStructure/Tree/index.js +2 -3
  21. package/appUtils/focusManager/treeDataStructure/Utils/index.js +76 -38
  22. package/appUtils/focusManager/utils/index.ts +100 -0
  23. package/appUtils/focusManagerAux/index.ts +76 -0
  24. package/appUtils/focusManagerAux/utils/index.ts +100 -0
  25. package/appUtils/{index.js → index.ts} +2 -0
  26. package/appUtils/keyCodes/{index.js → index.ts} +2 -0
  27. package/appUtils/keyCodes/keys/index.ts +3 -0
  28. package/appUtils/keyCodes/{keys.android.js → keys/keyEventMapper.ts} +0 -19
  29. package/appUtils/keyCodes/keys/keys.android.ts +18 -0
  30. package/appUtils/keyCodes/keys/keys.ios.ts +25 -0
  31. package/appUtils/keyCodes/keys/keys.ts +15 -0
  32. package/appUtils/keyCodes/{keys.web.js → keys/keys.web.ts} +8 -0
  33. package/appUtils/keyCodes/{keysByPlatform.js → keys/keysByPlatform.ts} +11 -1
  34. package/appUtils/platform/const.ts +25 -0
  35. package/appUtils/platform/index.ts +3 -0
  36. package/appUtils/platform/platformUtils.ts +171 -0
  37. package/appUtils/playerManager/conts.ts +6 -0
  38. package/appUtils/playerManager/index.ts +11 -5
  39. package/appUtils/playerManager/nativePlayerManager.ts +12 -0
  40. package/appUtils/playerManager/player.ts +44 -3
  41. package/appUtils/playerManager/playerFactory.ts +12 -10
  42. package/appUtils/playerManager/playerNative.ts +14 -14
  43. package/appUtils/playerManager/usePlayerControllerSetup.tsx +7 -1
  44. package/arrayUtils/__tests__/isFilledArray.test.ts +63 -0
  45. package/arrayUtils/index.ts +5 -0
  46. package/booleanUtils/index.ts +4 -4
  47. package/cellUtils/__tests__/cellUtils.test.ts +9 -20
  48. package/cellUtils/index.ts +10 -14
  49. package/dateUtils/index.ts +11 -0
  50. package/domUtils/{cookieManager.js → cookieManager.ts} +1 -2
  51. package/functionUtils/index.ts +15 -11
  52. package/headersUtils/index.ts +1 -0
  53. package/inflatedUrlUtils/index.ts +4 -4
  54. package/keyboardState/index.ts +0 -0
  55. package/localizationUtils/__tests__/localizationUtils.test.ts +72 -53
  56. package/localizationUtils/index.ts +13 -22
  57. package/manifestUtils/defaultManifestConfigurations/generalContent.js +6 -0
  58. package/manifestUtils/defaultManifestConfigurations/player.js +2 -1
  59. package/manifestUtils/index.js +5 -1
  60. package/manifestUtils/secondaryImage/index.js +18 -15
  61. package/modalState/index.ts +1 -5
  62. package/navigationUtils/index.ts +70 -9
  63. package/numberUtils/__tests__/isLikeNumber.test.ts +18 -0
  64. package/numberUtils/index.ts +9 -18
  65. package/package.json +2 -2
  66. package/playerUtils/configurationGenerator.ts +3 -1
  67. package/pluginUtils/index.ts +9 -0
  68. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +2 -0
  69. package/reactHooks/autoscrolling/__tests__/{useTrackedView.test.ts → useTrackedView.test.tsx} +18 -1
  70. package/reactHooks/cell-click/__tests__/index.test.js +10 -1
  71. package/reactHooks/cell-click/index.ts +12 -12
  72. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +30 -70
  73. package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +6 -2
  74. package/reactHooks/feed/__tests__/useInflatedUrl.test.ts +18 -3
  75. package/reactHooks/feed/useBuildPipesUrl.ts +7 -10
  76. package/reactHooks/feed/useFeedRefresh.tsx +9 -7
  77. package/reactHooks/feed/useInflatedUrl.ts +44 -15
  78. package/reactHooks/layout/__tests__/{index.test.js → index.test.tsx} +44 -29
  79. package/reactHooks/layout/getDeviceInfo/index.ts +4 -2
  80. package/reactHooks/layout/types/index.ts +2 -0
  81. package/reactHooks/layout/useDimensions/useDimensions.ts +13 -7
  82. package/reactHooks/navigation/__mocks__/index.ts +15 -0
  83. package/reactHooks/navigation/__mocks__/useNavigation.ts +7 -0
  84. package/reactHooks/navigation/__tests__/index.test.tsx +26 -8
  85. package/reactHooks/navigation/index.ts +71 -25
  86. package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +3 -1
  87. package/reactHooks/screen/__mocks__/useScreenContext.ts +3 -1
  88. package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +21 -23
  89. package/reactHooks/screen/index.ts +2 -0
  90. package/reactHooks/screen/useScreenBackgroundColor.ts +23 -0
  91. package/reactHooks/screen/useScreenContext.ts +4 -4
  92. package/reactHooks/screen/useScreenData.ts +1 -1
  93. package/reactHooks/screen/useTargetScreenData.ts +7 -0
  94. package/reactHooks/useListenEventBusEvent.ts +1 -4
  95. package/reactHooks/videoModal/index.ts +0 -3
  96. package/reactUtils/index.ts +91 -0
  97. package/screenState/index.ts +0 -8
  98. package/stringUtils/index.ts +5 -0
  99. package/testUtils/getByTestId.ts +14 -0
  100. package/testUtils/index.tsx +38 -23
  101. package/types.ts +4 -0
  102. package/appUtils/focusManager/FocusableEvents.ts +0 -8
  103. package/appUtils/focusManager/treeDataStructure/Utils/__tests__/Utils_android.test.js +0 -1094
  104. package/appUtils/focusManager/treeDataStructure/Utils/index.android.js +0 -261
  105. package/appUtils/keyCodes/keys.ios.js +0 -46
  106. /package/appUtils/HooksManager/{logger.js → logger.ts} +0 -0
  107. /package/appUtils/{directionHelper.js → directionHelper.ts} +0 -0
  108. /package/appUtils/keyCodes/{androidTVKeys.js → androidTVKeys.ts} +0 -0
  109. /package/appUtils/{localizationsHelper.js → localizationsHelper.ts} +0 -0
  110. /package/domUtils/{logger.js → logger.ts} +0 -0
@@ -0,0 +1,11 @@
1
+ import dayjs from "dayjs";
2
+ import utc from "dayjs/plugin/utc";
3
+ import timezone from "dayjs/plugin/timezone";
4
+ import isoWeek from "dayjs/plugin/isoWeek";
5
+
6
+ // Extend dayjs with plugins
7
+ dayjs.extend(utc);
8
+ dayjs.extend(timezone);
9
+ dayjs.extend(isoWeek);
10
+
11
+ export { dayjs };
@@ -2,7 +2,6 @@ import { domUtilsLogger } from "./logger";
2
2
 
3
3
  /**
4
4
  * Gets an object of cookies and sets them on the DOM.
5
- * @param {Object} cookies selected data key for label.
6
5
  */
7
6
  export function setCookies(cookies): void {
8
7
  const cookieKeys = Object.keys(cookies);
@@ -25,7 +24,7 @@ export function setCookies(cookies): void {
25
24
  /**
26
25
  * Gets cookies set on DOM
27
26
  */
28
- export function getCookies(): Object {
27
+ export function getCookies(): typeof document.cookie {
29
28
  try {
30
29
  if (document) {
31
30
  return document.cookie;
@@ -73,12 +73,12 @@ type SubscriberFn<T> = (
73
73
 
74
74
  export type EventHandlerFn<T> = (event: string, ...args: unknown[]) => T;
75
75
 
76
- type SubscriberObj = Partial<{
77
- on?: SubscriberFn<SubscriberObj>;
78
- invokeHandler: EventHandlerFn<SubscriberObj>;
79
- removeHandler: EventHandlerFn<SubscriberObj>;
80
- handlers: Record<string, SubscriberFn<SubscriberObj>[] | []>;
81
- }>;
76
+ export type SubscriberObj<T extends {} = {}> = {
77
+ on: SubscriberFn<SubscriberObj<T>>;
78
+ invokeHandler: EventHandlerFn<SubscriberObj<T>>;
79
+ removeHandler: EventHandlerFn<SubscriberObj<T>>;
80
+ handlers: Record<string, SubscriberFn<SubscriberObj<T>>[] | []>;
81
+ } & T;
82
82
 
83
83
  export const clearObject = (object: { [key: string]: unknown }) =>
84
84
  Object.keys(object).forEach((key) => delete object[key]);
@@ -88,7 +88,11 @@ export const clearObject = (object: { [key: string]: unknown }) =>
88
88
  * @param {Object} obj to add the subscription feature on
89
89
  * @returns {Object} subscriber object
90
90
  */
91
- export function subscriber(obj: SubscriberObj = {}): SubscriberObj {
91
+ export function subscriber<T extends Partial<SubscriberObj> = {}>(
92
+ _obj: T = {} as T
93
+ ): SubscriberObj {
94
+ const obj: T = _obj;
95
+
92
96
  if (!obj.handlers) {
93
97
  obj.handlers = {};
94
98
  }
@@ -134,7 +138,7 @@ export function subscriber(obj: SubscriberObj = {}): SubscriberObj {
134
138
  | SubscriberFn<SubscriberObj>[]
135
139
  | [];
136
140
 
137
- return obj;
141
+ return obj as SubscriberObj;
138
142
  };
139
143
 
140
144
  /**
@@ -150,16 +154,16 @@ export function subscriber(obj: SubscriberObj = {}): SubscriberObj {
150
154
 
151
155
  R.compose(R.forEach(callHandlerWithDispose), R.propOr([], event))(handlers);
152
156
 
153
- return obj;
157
+ return obj as SubscriberObj;
154
158
  };
155
159
 
156
160
  obj.removeHandler = function (event, handler) {
157
161
  handlers[event] = R.reject(R.equals(handler), handlers[event]);
158
162
 
159
- return obj;
163
+ return obj as SubscriberObj;
160
164
  };
161
165
 
162
- return obj;
166
+ return obj as SubscriberObj;
163
167
  }
164
168
 
165
169
  /**
@@ -28,5 +28,6 @@ export const getAppDataHeaders = (screenId: string) => {
28
28
  "x-applicaster-signed-device-info-token": appData.signedDeviceInfoToken,
29
29
  "x-applicaster-device-make": appData.deviceMake,
30
30
  "x-applicaster-device-model": appData.deviceModel,
31
+ "x-applicaster-uuid": appData?.uuid,
31
32
  };
32
33
  };
@@ -1,4 +1,4 @@
1
- import { last, head, isNil, includes, all, pathOr } from "ramda";
1
+ import { last, head, isNil, includes, pathOr } from "ramda";
2
2
 
3
3
  const stripBrackets = (path) => {
4
4
  const withoutPrepened = last(path.split("{{"));
@@ -13,15 +13,15 @@ const hasValue = (context) => (path) => {
13
13
  return !isNil(value);
14
14
  };
15
15
 
16
- export const isEnoughDataToInflateString = (context, string): boolean => {
16
+ export const getMissingValues = (context, string): string[] => {
17
17
  if (!includes("{{", string)) {
18
- return true;
18
+ return [];
19
19
  }
20
20
 
21
21
  const SEARCH_REGEX = new RegExp(/{{.*?}}/g);
22
22
  const paths = string.toString().match(SEARCH_REGEX);
23
23
 
24
- return all(hasValue(context), paths);
24
+ return paths.filter((path) => !hasValue(context)(path));
25
25
  };
26
26
 
27
27
  export const isNonInflatedUrl = (url: string): boolean =>
File without changes
@@ -1,59 +1,59 @@
1
- import * as ReactNative from "react-native";
2
-
3
- const mocked_state = {
4
- remoteConfigurations: { localizations: {} },
5
- appData: {
6
- languageCode: "en",
7
- countryCode: "US",
8
- },
9
- };
10
-
11
- let mocked_locale = ["en-US"];
12
-
13
- jest.doMock("react-redux", () => ({
14
- useSelector: jest.fn((fn) => fn(mocked_state)),
15
- }));
1
+ import { NativeModules } from "react-native";
16
2
 
17
- const SettingsManager = {
3
+ const settingsManagerMock = {
18
4
  getConstants: jest.fn(() => ({
19
- settings: { AppleLanguages: mocked_locale },
5
+ settings: { AppleLanguages: ["en-US"] },
20
6
  })),
21
7
  };
22
8
 
23
- const QuickBrickCommunicationModule = {
9
+ const qbCommunicationModuleMock = {
24
10
  languageLocale: "en",
25
11
  countryLocale: "US",
12
+ uiLanguage: "en-US",
26
13
  };
27
14
 
28
- ReactNative.NativeModules.SettingsManager = SettingsManager;
29
-
30
- ReactNative.NativeModules.QuickBrickCommunicationModule =
31
- QuickBrickCommunicationModule;
32
-
33
- const { useIsRTL } = require("../index");
15
+ NativeModules.SettingsManager = settingsManagerMock;
16
+ NativeModules.QuickBrickCommunicationModule = qbCommunicationModuleMock;
34
17
 
35
18
  describe("localizationUtils", () => {
19
+ beforeEach(() => {
20
+ jest.resetModules();
21
+ });
22
+
36
23
  describe("when the app has a single locale", () => {
37
24
  describe("when the app has only a RTL language as locale", () => {
38
25
  beforeEach(() => {
39
- mocked_state.remoteConfigurations.localizations = {
40
- he: "http://url.com",
26
+ jest.resetModules();
27
+ const RN = require("react-native");
28
+
29
+ RN.NativeModules.QuickBrickCommunicationModule = {
30
+ languageLocale: "he",
31
+ countryLocale: "IL",
32
+ uiLanguage: "he-HE",
41
33
  };
42
34
  });
43
35
 
44
36
  it("useIsRTL returns true", () => {
37
+ const { useIsRTL } = require("../index");
45
38
  expect(useIsRTL()).toBe(true);
46
39
  });
47
40
  });
48
41
 
49
42
  describe("when the app has only a LTR language as locale", () => {
50
43
  beforeEach(() => {
51
- mocked_state.remoteConfigurations.localizations = {
52
- en: "http://url.com",
44
+ jest.resetModules();
45
+
46
+ const RN = require("react-native");
47
+
48
+ RN.NativeModules.QuickBrickCommunicationModule = {
49
+ languageLocale: "en",
50
+ countryLocale: "US",
51
+ uiLanguage: "en",
53
52
  };
54
53
  });
55
54
 
56
55
  it("useIsRTL returns false", () => {
56
+ const { useIsRTL } = require("../index");
57
57
  expect(useIsRTL()).toBe(false);
58
58
  });
59
59
  });
@@ -63,45 +63,56 @@ describe("localizationUtils", () => {
63
63
  describe("when device locale is in the app's locales", () => {
64
64
  describe("when device locale is LTR", () => {
65
65
  beforeEach(() => {
66
- mocked_state.remoteConfigurations.localizations = {
67
- he: "http://url.com",
68
- en: "http://url.com",
69
- };
66
+ jest.resetModules();
67
+
68
+ const RN = require("react-native");
70
69
 
71
- mocked_locale = ["en-US"];
70
+ RN.NativeModules.QuickBrickCommunicationModule = {
71
+ languageLocale: "en",
72
+ countryLocale: "US",
73
+ uiLanguage: "en-US",
74
+ };
72
75
  });
73
76
 
74
77
  it("useIsRTL returns false", () => {
78
+ const { useIsRTL } = require("../index");
75
79
  expect(useIsRTL()).toBe(false);
76
80
  });
77
81
  });
78
82
 
79
83
  describe("when device locale is RTL", () => {
80
84
  beforeEach(() => {
81
- mocked_state.remoteConfigurations.localizations = {
82
- he: "http://url.com",
83
- en: "http://url.com",
84
- };
85
+ jest.resetModules();
86
+ const RN = require("react-native");
85
87
 
86
- mocked_locale = ["he-HE"];
88
+ RN.NativeModules.QuickBrickCommunicationModule = {
89
+ languageLocale: "he",
90
+ countryLocale: "IL",
91
+ uiLanguage: "he",
92
+ };
87
93
  });
88
94
 
89
95
  it("useIsRTL returns true", () => {
96
+ const { useIsRTL } = require("../index");
90
97
  expect(useIsRTL()).toBe(true);
91
98
  });
92
99
  });
93
100
 
94
101
  describe("when a device has a secondary language in a supported language", () => {
95
102
  beforeEach(() => {
96
- mocked_state.remoteConfigurations.localizations = {
97
- en: "http://url.com",
98
- he: "http://url.com",
99
- };
103
+ jest.resetModules();
104
+
105
+ const RN = require("react-native");
100
106
 
101
- mocked_locale = ["es-SP", "he-HE"];
107
+ RN.NativeModules.QuickBrickCommunicationModule = {
108
+ languageLocale: "he",
109
+ countryLocale: "IL",
110
+ uiLanguage: "he",
111
+ };
102
112
  });
103
113
 
104
114
  it("useIsRTL returns true", () => {
115
+ const { useIsRTL } = require("../index");
105
116
  expect(useIsRTL()).toBe(true);
106
117
  });
107
118
  });
@@ -110,30 +121,38 @@ describe("localizationUtils", () => {
110
121
  describe("when device locale is not in the app's locales", () => {
111
122
  describe("when first app locale is LTR", () => {
112
123
  beforeEach(() => {
113
- mocked_state.remoteConfigurations.localizations = {
114
- en: "http://url.com",
115
- he: "http://url.com",
116
- };
124
+ jest.resetModules();
125
+
126
+ const RN = require("react-native");
117
127
 
118
- mocked_locale = ["fr-FR"];
128
+ RN.NativeModules.QuickBrickCommunicationModule = {
129
+ languageLocale: "fr",
130
+ countryLocale: "FR",
131
+ uiLanguage: "fr-FR",
132
+ };
119
133
  });
120
134
 
121
135
  it("useIsRTL returns false", () => {
136
+ const { useIsRTL } = require("../index");
122
137
  expect(useIsRTL()).toBe(false);
123
138
  });
124
139
  });
125
140
 
126
141
  describe("when first app locale is RTL", () => {
127
142
  beforeEach(() => {
128
- mocked_state.remoteConfigurations.localizations = {
129
- he: "http://url.com",
130
- en: "http://url.com",
131
- };
143
+ jest.resetModules();
144
+
145
+ const RN = require("react-native");
132
146
 
133
- mocked_locale = ["fr-FR"];
147
+ RN.NativeModules.QuickBrickCommunicationModule = {
148
+ languageLocale: "he",
149
+ countryLocale: "HE",
150
+ uiLanguage: "he",
151
+ };
134
152
  });
135
153
 
136
154
  it("useIsRTL returns true", () => {
155
+ const { useIsRTL } = require("../index");
137
156
  expect(useIsRTL()).toBe(true);
138
157
  });
139
158
  });
@@ -1,10 +1,9 @@
1
1
  import * as R from "ramda";
2
2
  import { ViewStyle } from "react-native";
3
- import { useSelector } from "react-redux";
4
3
 
5
- import { getDeviceLocales } from "./deviceLocales";
6
4
  import { useMemo } from "react";
7
5
  import { getUILanguage } from "../appUtils/localizationsHelper";
6
+ import { utilsLogger } from "../logger";
8
7
 
9
8
  export {
10
9
  getLocale,
@@ -45,34 +44,26 @@ export function useLocalizedStrings({ localizations }) {
45
44
  return result;
46
45
  }
47
46
 
48
- function getLocaleToUse(languageCodes, localizations) {
49
- const matchingLanguages = languageCodes.filter(
50
- R.contains(R.__, localizations)
51
- );
47
+ export function getIsRTL(): boolean {
48
+ const uiLanguage = getUILanguage();
49
+
50
+ if (!uiLanguage) {
51
+ utilsLogger.error({ message: "getUILanguage returned null or undefined" });
52
52
 
53
- if (matchingLanguages?.length) {
54
- return R.head(matchingLanguages);
53
+ return false;
55
54
  }
56
55
 
57
- return R.head(localizations);
58
- }
56
+ const [languageCode] = uiLanguage.split("-");
59
57
 
60
- export function getIsRTLFromLocalizations(localizations): boolean {
61
- const deviceLocales = getDeviceLocales() || [];
62
- const localeToUse = getLocaleToUse(deviceLocales, R.keys(localizations));
58
+ const lowerCaseLanguageCode = languageCode.toLocaleLowerCase();
63
59
 
64
- return R.contains(localeToUse, RTL_LOCALES);
65
- }
60
+ const isRTL = R.contains(lowerCaseLanguageCode, RTL_LOCALES);
66
61
 
67
- const remoteConfigLocalizationSelector = R.path([
68
- "remoteConfigurations",
69
- "localizations",
70
- ]);
62
+ return isRTL;
63
+ }
71
64
 
72
65
  export function useIsRTL(): boolean {
73
- const localizations = useSelector(remoteConfigLocalizationSelector);
74
-
75
- return getIsRTLFromLocalizations(localizations);
66
+ return getIsRTL();
76
67
  }
77
68
 
78
69
  export const applyRTLStylesIfNeeded = (
@@ -245,6 +245,12 @@ const generalContent = () => ({
245
245
  ],
246
246
  initial_value: "reloading...",
247
247
  },
248
+ {
249
+ type: "text_input",
250
+ label: "Navigation Bar Screen Title",
251
+ key: "screen_title",
252
+ initial_value: null,
253
+ },
248
254
  ],
249
255
  },
250
256
  advertising: {
@@ -1663,7 +1663,8 @@ function getPlayerConfiguration({ platform }) {
1663
1663
  platform.includes("lg") ||
1664
1664
  platform.includes("samsung") ||
1665
1665
  platform.includes("android_tv") ||
1666
- platform.includes("amazon")
1666
+ platform.includes("amazon") ||
1667
+ platform.includes("vizio")
1667
1668
  ) {
1668
1669
  styles.fields.push(
1669
1670
  // Captions Menu
@@ -22,7 +22,11 @@ const {
22
22
  const { buttonKey } = require("./buttons");
23
23
  const { tvBadges } = require("./tvBadges");
24
24
  const { mobileProgressBar, tvProgressBar } = require("./progressBar");
25
- const { secondaryImage, getUpdatedSecondaryImageKeys } = require("./secondaryImage");
25
+
26
+ const {
27
+ secondaryImage,
28
+ getUpdatedSecondaryImageKeys,
29
+ } = require("./secondaryImage");
26
30
 
27
31
  module.exports = {
28
32
  fontKey,
@@ -132,29 +132,32 @@ function secondaryImage({
132
132
 
133
133
  const POSITION_OVER_IMAGE = toSnakeCase(position_over_image);
134
134
 
135
- const getUpdatedSecondaryImageKeys = (secondaryImageManifest) => secondaryImageManifest.fields.reduce((acc, item) => {
136
- const key = item.key;
135
+ const getUpdatedSecondaryImageKeys = (secondaryImageManifest) =>
136
+ secondaryImageManifest.fields.reduce((acc, item) => {
137
+ const key = item.key;
137
138
 
138
- const conditionalFields = (item.conditional_fields || []).map((field) => field.key);
139
+ const conditionalFields = (item.conditional_fields || []).map(
140
+ (field) => field.key
141
+ );
139
142
 
140
- const updatedConditionalFields = conditionalFields.reduce((acc, field) => {
141
- const updatedKey = field.replace("secondary_image_", "nested_image_");
143
+ const updatedConditionalFields = conditionalFields.reduce((acc, field) => {
144
+ const updatedKey = field.replace("secondary_image_", "nested_image_");
145
+
146
+ return {
147
+ ...acc,
148
+ [updatedKey]: field,
149
+ };
150
+ }, {});
151
+
152
+ const updatedKey = key.replace("secondary_image_", "nested_image_");
142
153
 
143
154
  return {
144
155
  ...acc,
145
- [updatedKey]: field,
156
+ ...updatedConditionalFields,
157
+ [updatedKey]: key,
146
158
  };
147
159
  }, {});
148
160
 
149
- const updatedKey = key.replace("secondary_image_", "nested_image_");
150
-
151
- return {
152
- ...acc,
153
- ...updatedConditionalFields,
154
- [updatedKey]: key,
155
- };
156
- }, {});
157
-
158
161
  module.exports = {
159
162
  secondaryImage,
160
163
  getUpdatedSecondaryImageKeys,
@@ -31,11 +31,7 @@ export const useModalStore = create<ModalStore>((set) => ({
31
31
  set((state) => ({
32
32
  modalState: { ...state.modalState, ...newState },
33
33
  })),
34
- openModal: ({
35
- item,
36
- options = {},
37
- props = { screenData: {} },
38
- }: OpenModalArg) =>
34
+ openModal: ({ item, options = {}, props }: OpenModalArg) =>
39
35
  set({
40
36
  modalState: {
41
37
  visible: true,
@@ -114,7 +114,11 @@ export function getNavigationProps({
114
114
  } | null {
115
115
  const { activeRiver } = navigator;
116
116
  const { navigations, id: selected, home } = activeRiver; // use useRiver hook instead
117
- const navigation = R.find(R.propEq("category", category), navigations);
117
+
118
+ const navigation: ZappNavigation = R.find(
119
+ R.propEq("category", category),
120
+ navigations
121
+ );
118
122
 
119
123
  if (!navigation) {
120
124
  return null;
@@ -127,9 +131,9 @@ export function getNavigationProps({
127
131
  title,
128
132
  home,
129
133
  styles,
130
- assets,
131
- nav_items,
132
- rules,
134
+ assets: assets as ZappNavBarAssets,
135
+ nav_items: nav_items as any as NavBarItem[],
136
+ rules: rules as any as ZappNavBarRules,
133
137
  };
134
138
  }
135
139
 
@@ -320,7 +324,13 @@ export function getPathAttributes({
320
324
  * @param {object} rivers
321
325
  * @returns {object}
322
326
  */
323
- export function getRiverFromRoute({ route, rivers }) {
327
+ export function getRiverFromRoute({
328
+ route,
329
+ rivers,
330
+ }: {
331
+ route: string;
332
+ rivers: Record<string, ZappRiver>;
333
+ }) {
324
334
  if (!route) {
325
335
  return null;
326
336
  }
@@ -433,7 +443,7 @@ export const runZappHooksForEntry = async (
433
443
 
434
444
  let success;
435
445
  let payload;
436
- const rivers = appStore.get("rivers");
446
+ const rivers: Record<string, ZappRiver> = appStore.get("rivers");
437
447
  const plugins = appStore.get("plugins");
438
448
  const appData = appStore.get("appData");
439
449
 
@@ -488,13 +498,16 @@ export const runZappHooksForEntry = async (
488
498
  payload = _payload;
489
499
  };
490
500
 
491
- HooksManager(hooksOptions)
501
+ const hooksManager = HooksManager(hooksOptions);
502
+
503
+ hooksManager.subscriber
492
504
  .on(HOOKS_EVENTS.PRESENT_SCREEN_HOOK, handleHookPresent)
493
505
  .on(HOOKS_EVENTS.START_BACKGROUND_HOOK, handleBackgroundHook)
494
506
  .on(HOOKS_EVENTS.ERROR, onFinished(false))
495
507
  .on(HOOKS_EVENTS.CANCEL, onFinished(false))
496
- .on(HOOKS_EVENTS.COMPLETE, onFinished(true))
497
- .handleHooks(entry);
508
+ .on(HOOKS_EVENTS.COMPLETE, onFinished(true));
509
+
510
+ hooksManager.handleHooks(entry);
498
511
 
499
512
  // eslint-disable-next-line no-unmodified-loop-condition
500
513
  while (success === undefined) {
@@ -588,3 +601,51 @@ export function isMenuDisabled(
588
601
  export function routeIsPlayerScreen(currentRoute) {
589
602
  return currentRoute?.includes("/playable");
590
603
  }
604
+
605
+ export const getNavBarProps =
606
+ (currentRiver: ZappRiver, pathname: string, title: string) => () => {
607
+ const props = getNavigationPropsV2({
608
+ currentRiver,
609
+ title,
610
+ category: "nav_bar",
611
+ });
612
+
613
+ if (props) {
614
+ return {
615
+ ...props,
616
+ id: pathname,
617
+ pathname: pathname,
618
+ };
619
+ }
620
+
621
+ return null;
622
+ };
623
+
624
+ export const findMenuPlugin = (
625
+ navigations: ZappNavigation[],
626
+ plugins
627
+ ): QuickBrickPlugin => {
628
+ return resolveNavigationPlugin({
629
+ category: "menu",
630
+ navigations,
631
+ plugins,
632
+ }) as QuickBrickPlugin;
633
+ };
634
+
635
+ export const shouldNavBarDisplayMenu = (currentRiver: ZappRiver, plugins) =>
636
+ findMenuPlugin(currentRiver.navigations, plugins)?.identifier ===
637
+ "quick_brick_side_menu" ||
638
+ currentRiver?.navigations.findIndex(
639
+ (nav) => nav.category === "nav_bar" && nav.general?.override_menu_target
640
+ ) > -1;
641
+
642
+ export const getScreenId = (
643
+ screenData: LegacyNavigationScreenData,
644
+ fallbackRiver: ZappRiver
645
+ ) => {
646
+ return screenData?.targetScreen
647
+ ? screenData?.targetScreen?.id ?? fallbackRiver.id
648
+ : "screen_id" in screenData
649
+ ? screenData.screen_id
650
+ : fallbackRiver.id;
651
+ };
@@ -7,12 +7,24 @@ describe("isLikeNumber", () => {
7
7
  expect(isLikeNumber(value)).toBe(true);
8
8
  });
9
9
 
10
+ it("value is a number", () => {
11
+ const value = 123.45;
12
+
13
+ expect(isLikeNumber(value)).toBe(true);
14
+ });
15
+
10
16
  it("value is a string as number", () => {
11
17
  const value = "123";
12
18
 
13
19
  expect(isLikeNumber(value)).toBe(true);
14
20
  });
15
21
 
22
+ it("value is a string as number", () => {
23
+ const value = "123.45";
24
+
25
+ expect(isLikeNumber(value)).toBe(true);
26
+ });
27
+
16
28
  it("value is empty string", () => {
17
29
  const value = "";
18
30
 
@@ -54,4 +66,10 @@ describe("isLikeNumber", () => {
54
66
 
55
67
  expect(isLikeNumber(value)).toBe(false);
56
68
  });
69
+
70
+ it("NaN is not a number", () => {
71
+ const value = NaN;
72
+
73
+ expect(isLikeNumber(value)).toBe(false);
74
+ });
57
75
  });