@applicaster/zapp-react-native-utils 14.0.0-rc.9 → 14.0.0-rc.91

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 (142) hide show
  1. package/actionsExecutor/ActionExecutorContext.tsx +60 -84
  2. package/actionsExecutor/ScreenActions.ts +164 -0
  3. package/actionsExecutor/StorageActions.ts +110 -0
  4. package/actionsExecutor/feedDecorator.ts +171 -0
  5. package/actionsExecutor/screenResolver.ts +11 -0
  6. package/analyticsUtils/AnalyticPlayerListener.ts +5 -2
  7. package/analyticsUtils/AnalyticsEvents/helper.ts +81 -0
  8. package/analyticsUtils/AnalyticsEvents/sendHeaderClickEvent.ts +1 -1
  9. package/analyticsUtils/AnalyticsEvents/sendMenuClickEvent.ts +2 -1
  10. package/analyticsUtils/AnalyticsEvents/sendOnClickEvent.ts +14 -4
  11. package/analyticsUtils/__tests__/analyticsUtils.test.js +3 -0
  12. package/analyticsUtils/events.ts +8 -0
  13. package/analyticsUtils/index.tsx +3 -4
  14. package/analyticsUtils/manager.ts +1 -1
  15. package/analyticsUtils/playerAnalyticsTracker.ts +2 -1
  16. package/appUtils/HooksManager/Hook.ts +4 -4
  17. package/appUtils/HooksManager/index.ts +11 -1
  18. package/appUtils/accessibilityManager/const.ts +13 -0
  19. package/appUtils/accessibilityManager/hooks.ts +35 -1
  20. package/appUtils/accessibilityManager/index.ts +154 -30
  21. package/appUtils/accessibilityManager/utils.ts +24 -0
  22. package/appUtils/contextKeysManager/contextResolver.ts +42 -1
  23. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +8 -0
  24. package/appUtils/focusManager/__tests__/focusManager.test.js +1 -1
  25. package/appUtils/focusManager/events.ts +2 -0
  26. package/appUtils/focusManager/index.ios.ts +27 -0
  27. package/appUtils/focusManager/index.ts +86 -11
  28. package/appUtils/focusManager/treeDataStructure/Tree/index.js +1 -1
  29. package/appUtils/focusManagerAux/utils/index.ts +112 -3
  30. package/appUtils/focusManagerAux/utils/utils.ios.ts +35 -0
  31. package/appUtils/platform/platformUtils.ts +33 -3
  32. package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +91 -16
  33. package/appUtils/playerManager/OverlayObserver/utils.ts +32 -20
  34. package/appUtils/playerManager/conts.ts +21 -0
  35. package/appUtils/playerManager/useChapterMarker.tsx +0 -1
  36. package/appUtils/playerManager/usePlayerControllerSetup.tsx +16 -0
  37. package/arrayUtils/__tests__/allTruthy.test.ts +24 -0
  38. package/arrayUtils/__tests__/anyThruthy.test.ts +24 -0
  39. package/arrayUtils/__tests__/isEmptyArray.test.ts +63 -0
  40. package/arrayUtils/__tests__/isFilledArray.test.ts +1 -1
  41. package/arrayUtils/index.ts +13 -3
  42. package/audioPlayerUtils/__tests__/getArtworkImage.test.ts +144 -0
  43. package/audioPlayerUtils/__tests__/getBackgroundImage.test.ts +72 -0
  44. package/audioPlayerUtils/__tests__/getImageFromEntry.test.ts +110 -0
  45. package/audioPlayerUtils/assets/index.ts +2 -0
  46. package/audioPlayerUtils/index.ts +242 -0
  47. package/componentsUtils/__tests__/isTabsScreen.test.ts +38 -0
  48. package/componentsUtils/index.ts +4 -1
  49. package/conf/player/__tests__/selectors.test.ts +34 -0
  50. package/conf/player/selectors.ts +10 -0
  51. package/configurationUtils/__tests__/configurationUtils.test.js +0 -31
  52. package/configurationUtils/__tests__/getMediaItems.test.ts +65 -0
  53. package/configurationUtils/__tests__/imageSrcFromMediaItem.test.ts +34 -0
  54. package/configurationUtils/__tests__/manifestKeyParser.test.ts +546 -0
  55. package/configurationUtils/index.ts +64 -35
  56. package/configurationUtils/manifestKeyParser.ts +57 -32
  57. package/focusManager/FocusManager.ts +104 -20
  58. package/focusManager/Tree.ts +25 -21
  59. package/focusManager/__tests__/FocusManager.test.ts +50 -8
  60. package/focusManager/aux/index.ts +98 -0
  61. package/focusManager/utils.ts +12 -6
  62. package/index.d.ts +1 -10
  63. package/manifestUtils/_internals/getDefaultConfiguration.js +28 -0
  64. package/manifestUtils/{_internals.js → _internals/index.js} +2 -25
  65. package/manifestUtils/createConfig.js +4 -1
  66. package/manifestUtils/defaultManifestConfigurations/player.js +2764 -1539
  67. package/manifestUtils/index.js +4 -0
  68. package/manifestUtils/keys.js +33 -0
  69. package/manifestUtils/progressBar/__tests__/mobileProgressBar.test.js +0 -30
  70. package/manifestUtils/sharedConfiguration/screenPicker/stylesFields.js +6 -0
  71. package/manifestUtils/sharedConfiguration/screenPicker/utils.js +1 -0
  72. package/navigationUtils/__tests__/mapContentTypesToRivers.test.ts +130 -0
  73. package/navigationUtils/index.ts +26 -21
  74. package/package.json +2 -3
  75. package/playerUtils/PlayerTTS/PlayerTTS.ts +359 -0
  76. package/playerUtils/PlayerTTS/index.ts +1 -0
  77. package/playerUtils/__tests__/configurationUtils.test.ts +1 -65
  78. package/playerUtils/__tests__/getPlayerActionButtons.test.ts +54 -0
  79. package/playerUtils/_internals/__tests__/utils.test.ts +71 -0
  80. package/playerUtils/_internals/index.ts +1 -0
  81. package/playerUtils/_internals/utils.ts +31 -0
  82. package/playerUtils/configurationUtils.ts +0 -44
  83. package/playerUtils/getPlayerActionButtons.ts +17 -0
  84. package/playerUtils/index.ts +53 -0
  85. package/playerUtils/usePlayerTTS.ts +21 -0
  86. package/playerUtils/useValidatePlayerConfig.tsx +22 -19
  87. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +15 -14
  88. package/reactHooks/cell-click/__tests__/index.test.js +3 -0
  89. package/reactHooks/cell-click/index.ts +8 -1
  90. package/reactHooks/debugging/__tests__/index.test.js +0 -1
  91. package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +47 -90
  92. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +71 -31
  93. package/reactHooks/feed/index.ts +2 -0
  94. package/reactHooks/feed/useBatchLoading.ts +17 -10
  95. package/reactHooks/feed/useFeedLoader.tsx +36 -43
  96. package/reactHooks/feed/useInflatedUrl.ts +23 -29
  97. package/reactHooks/feed/useLoadPipesDataDispatch.ts +63 -0
  98. package/reactHooks/feed/usePipesCacheReset.ts +3 -3
  99. package/reactHooks/flatList/useSequentialRenderItem.tsx +3 -3
  100. package/reactHooks/layout/__tests__/index.test.tsx +3 -1
  101. package/reactHooks/layout/index.ts +1 -1
  102. package/reactHooks/layout/isTablet/index.ts +12 -5
  103. package/reactHooks/layout/useDimensions/__tests__/useDimensions.test.ts +34 -36
  104. package/reactHooks/layout/useDimensions/useDimensions.ts +2 -3
  105. package/reactHooks/layout/useLayoutVersion.ts +5 -5
  106. package/reactHooks/navigation/index.ts +7 -5
  107. package/reactHooks/navigation/useIsScreenActive.ts +9 -5
  108. package/reactHooks/navigation/useRoute.ts +7 -2
  109. package/reactHooks/navigation/useScreenStateStore.ts +8 -0
  110. package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +4 -0
  111. package/reactHooks/screen/useScreenContext.ts +1 -1
  112. package/reactHooks/state/__tests__/ZStoreProvider.test.tsx +2 -1
  113. package/reactHooks/state/index.ts +1 -1
  114. package/reactHooks/state/useHomeRiver.ts +4 -2
  115. package/reactHooks/state/useRivers.ts +7 -8
  116. package/riverComponetsMeasurementProvider/index.tsx +1 -1
  117. package/screenPickerUtils/index.ts +13 -0
  118. package/services/js2native.ts +1 -0
  119. package/storage/ScreenSingleValueProvider.ts +204 -0
  120. package/storage/ScreenStateMultiSelectProvider.ts +293 -0
  121. package/storage/StorageMultiSelectProvider.ts +192 -0
  122. package/storage/StorageSingleSelectProvider.ts +108 -0
  123. package/testUtils/index.tsx +7 -8
  124. package/time/BackgroundTimer.ts +6 -4
  125. package/utils/__tests__/endsWith.test.ts +30 -0
  126. package/utils/__tests__/find.test.ts +36 -0
  127. package/utils/__tests__/mapAccum.test.ts +73 -0
  128. package/utils/__tests__/omit.test.ts +19 -0
  129. package/utils/__tests__/path.test.ts +33 -0
  130. package/utils/__tests__/pathOr.test.ts +37 -0
  131. package/utils/__tests__/startsWith.test.ts +30 -0
  132. package/utils/__tests__/take.test.ts +40 -0
  133. package/utils/endsWith.ts +9 -0
  134. package/utils/find.ts +3 -0
  135. package/utils/index.ts +38 -1
  136. package/utils/mapAccum.ts +23 -0
  137. package/utils/omit.ts +5 -0
  138. package/utils/path.ts +5 -0
  139. package/utils/pathOr.ts +5 -0
  140. package/utils/startsWith.ts +9 -0
  141. package/utils/take.ts +5 -0
  142. package/playerUtils/configurationGenerator.ts +0 -2572
@@ -2,15 +2,12 @@ import { renderHook } from "@testing-library/react-hooks";
2
2
  import * as R from "ramda";
3
3
  import * as zappPipesModule from "@applicaster/zapp-react-native-redux/ZappPipes";
4
4
  import * as reactReduxModules from "react-redux";
5
- import { Provider } from "react-redux";
6
5
  import * as React from "react";
7
- import configureStore from "redux-mock-store";
8
- import thunk from "redux-thunk";
9
6
  import * as useRouteHook from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useRoute";
10
7
  import * as useNavigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
11
8
  import { useFeedLoader } from "../useFeedLoader";
12
-
13
- const mockStore = configureStore([thunk]);
9
+ import { WrappedWithProviders } from "../../../testUtils";
10
+ import { ScreenStateResolver } from "../../../appUtils/contextKeysManager/contextResolver";
14
11
 
15
12
  jest.useFakeTimers({ legacyFakeTimers: true });
16
13
 
@@ -55,13 +52,15 @@ const mockZappPipesData = {
55
52
 
56
53
  describe("useFeedLoader", () => {
57
54
  describe("with cached feed url", () => {
58
- const store = mockStore({
55
+ const store = {
59
56
  plugins: [],
60
57
  zappPipes: { "test://testfakeurl": mockZappPipesData },
61
- });
58
+ };
62
59
 
63
- const wrapper: React.FC<any> = ({ children }) => (
64
- <Provider store={store}>{children}</Provider>
60
+ const wrapper: React.FC<any> = ({ children, ...props }) => (
61
+ <WrappedWithProviders store={props.store || store}>
62
+ {children}
63
+ </WrappedWithProviders>
65
64
  );
66
65
 
67
66
  it("returns cached feed", () => {
@@ -110,8 +109,10 @@ describe("useFeedLoader", () => {
110
109
  describe("without cached feeds", () => {
111
110
  const feedUrl = "test://testfakeurl2";
112
111
 
113
- const wrapper: React.FC<any> = ({ children, store }) => (
114
- <Provider store={store}>{children}</Provider>
112
+ const wrapper: React.FC<any> = ({ children, ...props }) => (
113
+ <WrappedWithProviders store={props.store}>
114
+ {children}
115
+ </WrappedWithProviders>
115
116
  );
116
117
 
117
118
  it("It loads data for new url and returns it", () => {
@@ -123,10 +124,10 @@ describe("useFeedLoader", () => {
123
124
  .spyOn(zappPipesModule, "loadPipesData")
124
125
  .mockImplementation(jest.fn());
125
126
 
126
- const initialStore = mockStore({
127
+ const initialStore = {
127
128
  plugins: [],
128
129
  zappPipes: { "test://testfakeurl": "foobar" },
129
- });
130
+ };
130
131
 
131
132
  const { result, rerender } = renderHook(
132
133
  () => useFeedLoader({ feedUrl: "test://testfakeurl2" }),
@@ -135,15 +136,19 @@ describe("useFeedLoader", () => {
135
136
 
136
137
  expect(result.current.data).toBeNull();
137
138
 
138
- expect(loadPipesDataSpy).toBeCalledWith(feedUrl, {
139
+ expect(loadPipesDataSpy).toHaveBeenCalledWith(feedUrl, {
139
140
  clearCache: true,
140
141
  riverId: undefined,
142
+ callback: expect.any(Function),
143
+ resolvers: {
144
+ screen: expect.any(ScreenStateResolver),
145
+ },
141
146
  });
142
147
 
143
- const store2 = mockStore({
148
+ const store2 = {
144
149
  plugins: [],
145
150
  zappPipes: { "test://testfakeurl2": mockZappPipesData },
146
- });
151
+ };
147
152
 
148
153
  rerender({ store: store2 });
149
154
 
@@ -164,10 +169,10 @@ describe("useFeedLoader", () => {
164
169
  .spyOn(reactReduxModules, "useDispatch")
165
170
  .mockImplementation(() => jest.fn());
166
171
 
167
- const initialStore = mockStore({
172
+ const initialStore = {
168
173
  plugins: [],
169
174
  zappPipes: { "test://testfakeurl": "foobar" },
170
- });
175
+ };
171
176
 
172
177
  const { result, rerender } = renderHook(
173
178
  () => useFeedLoader({ feedUrl: "test://testfakeurl2" }),
@@ -176,15 +181,22 @@ describe("useFeedLoader", () => {
176
181
 
177
182
  expect(result.current.data).toBeNull();
178
183
 
179
- expect(loadPipesDataSpy).toBeCalledWith(feedUrl, {
184
+ expect(loadPipesDataSpy.mock.calls[0][0]).toBe(feedUrl);
185
+
186
+ expect(loadPipesDataSpy.mock.calls[0][1]).toMatchObject({
180
187
  clearCache: true,
181
188
  riverId: undefined,
189
+ resolvers: {
190
+ screen: {
191
+ screenStateStore: expect.any(Function),
192
+ },
193
+ },
182
194
  });
183
195
 
184
- const store2 = mockStore({
196
+ const store2 = {
185
197
  plugins: [],
186
198
  zappPipes: { "test://testfakeurl2": mockZappPipesData },
187
- });
199
+ };
188
200
 
189
201
  rerender({ store: store2 });
190
202
 
@@ -197,8 +209,10 @@ describe("useFeedLoader", () => {
197
209
  const feedUrl = "test://testfakeurl";
198
210
  const feedUrlWithNext = "test://withnexttestfakeurl";
199
211
 
200
- const wrapper: React.FC<any> = ({ children, store }) => (
201
- <Provider store={store}>{children}</Provider>
212
+ const wrapper: React.FC<any> = ({ children, ...props }) => (
213
+ <WrappedWithProviders store={props.store || {}}>
214
+ {children}
215
+ </WrappedWithProviders>
202
216
  );
203
217
 
204
218
  describe("reloadData", () => {
@@ -211,10 +225,10 @@ describe("useFeedLoader", () => {
211
225
  .spyOn(reactReduxModules, "useDispatch")
212
226
  .mockImplementation(() => jest.fn());
213
227
 
214
- const initialStore = mockStore({
228
+ const initialStore = {
215
229
  plugins: [],
216
230
  zappPipes: { [feedUrl]: "foobar" },
217
- });
231
+ };
218
232
 
219
233
  const { result } = renderHook(() => useFeedLoader({ feedUrl }), {
220
234
  wrapper,
@@ -223,11 +237,24 @@ describe("useFeedLoader", () => {
223
237
 
224
238
  const { reloadData } = result.current;
225
239
 
226
- reloadData();
240
+ reloadData?.();
241
+
242
+ expect(loadPipesDataSpy).toHaveBeenCalled();
243
+
244
+ expect(
245
+ loadPipesDataSpy.mock.calls[loadPipesDataSpy.mock.calls.length - 1][0]
246
+ ).toBe(feedUrl);
227
247
 
228
- expect(loadPipesDataSpy).toBeCalledWith(feedUrl, {
248
+ expect(
249
+ loadPipesDataSpy.mock.calls[loadPipesDataSpy.mock.calls.length - 1][1]
250
+ ).toMatchObject({
229
251
  clearCache: true,
230
252
  silentRefresh: true,
253
+ resolvers: {
254
+ screen: {
255
+ screenStateStore: expect.any(Function),
256
+ },
257
+ },
231
258
  });
232
259
 
233
260
  loadPipesDataSpy.mockRestore();
@@ -247,10 +274,10 @@ describe("useFeedLoader", () => {
247
274
  .spyOn(reactReduxModules, "useDispatch")
248
275
  .mockImplementation(() => jest.fn());
249
276
 
250
- const initialStore = mockStore({
277
+ const initialStore = {
251
278
  plugins: [],
252
279
  zappPipes: { [feedUrlWithNext]: { data: { next: nextUrl } } },
253
- });
280
+ };
254
281
 
255
282
  const { result } = renderHook(
256
283
  () => useFeedLoader({ feedUrl: feedUrlWithNext }),
@@ -262,11 +289,24 @@ describe("useFeedLoader", () => {
262
289
 
263
290
  const { loadNext } = result.current;
264
291
 
265
- loadNext();
292
+ loadNext?.();
293
+
294
+ expect(loadPipesDataSpy).toHaveBeenCalled();
295
+
296
+ expect(
297
+ loadPipesDataSpy.mock.calls[loadPipesDataSpy.mock.calls.length - 1][0]
298
+ ).toBe(nextUrl);
266
299
 
267
- expect(loadPipesDataSpy).toBeCalledWith(nextUrl, {
300
+ expect(
301
+ loadPipesDataSpy.mock.calls[loadPipesDataSpy.mock.calls.length - 1][1]
302
+ ).toMatchObject({
268
303
  parentFeed: feedUrlWithNext,
269
304
  silentRefresh: true,
305
+ resolvers: {
306
+ screen: {
307
+ screenStateStore: expect.any(Function),
308
+ },
309
+ },
270
310
  });
271
311
 
272
312
  loadPipesDataSpy.mockRestore();
@@ -11,3 +11,5 @@ export { useBuildPipesUrl } from "./useBuildPipesUrl";
11
11
  export { usePipesCacheReset } from "./usePipesCacheReset";
12
12
 
13
13
  export { useBatchLoading } from "./useBatchLoading";
14
+
15
+ export { useLoadPipesDataDispatch } from "./useLoadPipesDataDispatch";
@@ -1,16 +1,15 @@
1
1
  import { complement, compose, isNil, map, min, prop, take, uniq } from "ramda";
2
- import { useDispatch } from "react-redux";
3
2
  import * as React from "react";
4
- import { useZappPipesFeeds } from "@applicaster/zapp-react-native-redux/hooks";
5
- import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
3
+ import { useZappPipesFeed } from "@applicaster/zapp-react-native-redux";
6
4
  import { isNilOrEmpty } from "../../reactUtils/helpers";
7
5
  import { ZappPipesSearchContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
8
6
  import {
9
7
  getInflatedDataSourceUrl,
10
8
  getSearchContext,
9
+ useLoadPipesDataDispatch,
11
10
  } from "@applicaster/zapp-react-native-utils/reactHooks";
12
11
  import { isGallery } from "@applicaster/zapp-react-native-utils/componentsUtils";
13
- import { useScreenContext } from "../screen/useScreenContext";
12
+ import { useScreenContext } from "../screen";
14
13
 
15
14
  type Options = {
16
15
  initialBatchSize?: number;
@@ -63,7 +62,6 @@ export const useBatchLoading = (
63
62
  componentsToRender: { data?: ZappDataSource; component_type: string }[],
64
63
  options: Options
65
64
  ) => {
66
- const dispatch = useDispatch();
67
65
  const { screen: screenContext, entry: entryContext } = useScreenContext();
68
66
  const [searchContext] = ZappPipesSearchContext.useZappPipesContext();
69
67
  const [hasEverBeenReady, setHasEverBeenReady] = React.useState(false);
@@ -118,7 +116,9 @@ export const useBatchLoading = (
118
116
  []
119
117
  );
120
118
 
121
- const feeds = useZappPipesFeeds(feedUrls);
119
+ const feeds = useZappPipesFeed(feedUrls);
120
+
121
+ const loadPipesDataDispatcher = useLoadPipesDataDispatch();
122
122
 
123
123
  // dispatch loadPipesData for each feed that is not loaded
124
124
  const runBatchLoading = React.useCallback(() => {
@@ -138,17 +138,24 @@ export const useBatchLoading = (
138
138
 
139
139
  if (mappedFeedUrl) {
140
140
  // 4. load data
141
- return dispatch(
142
- loadPipesData(mappedFeedUrl, { riverId: options.riverId })
141
+ return loadPipesDataDispatcher(
142
+ mappedFeedUrl,
143
+ {
144
+ riverId: options.riverId,
145
+ },
146
+ {
147
+ withResolvers: true,
148
+ withScreenRouteMapping: true,
149
+ }
143
150
  );
144
151
  }
145
152
  }
146
153
  });
147
- }, [feedUrls]);
154
+ }, [feedUrls, feeds, loadPipesDataDispatcher]);
148
155
 
149
156
  React.useEffect(() => {
150
157
  runBatchLoading();
151
- }, []);
158
+ }, [runBatchLoading]); // Adding runBatchLoading as a dependency to ensure that it reloads feeds when clearPipesData is called
152
159
 
153
160
  React.useEffect(() => {
154
161
  // check if all feeds are ready and set hasEverBeenReady to true
@@ -1,13 +1,11 @@
1
1
  import React, { useEffect } from "react";
2
- import { useDispatch } from "react-redux";
3
2
 
4
- import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
5
- import { useZappPipesFeed } from "@applicaster/zapp-react-native-redux/hooks";
3
+ import { useZappPipesFeed } from "@applicaster/zapp-react-native-redux";
6
4
 
7
5
  import { reactHooksLogger } from "../logger";
8
6
  import { shouldDispatchData, useIsInitialRender } from "../utils";
9
7
  import { useInflatedUrl } from "./useInflatedUrl";
10
- import { useRoute } from "../navigation";
8
+ import { useLoadPipesDataDispatch } from "./useLoadPipesDataDispatch";
11
9
 
12
10
  const logger = reactHooksLogger.addSubsystem("useFeedLoader");
13
11
 
@@ -39,39 +37,27 @@ export const useFeedLoader = ({
39
37
  mapping,
40
38
  pipesOptions = {},
41
39
  }: Props): FeedLoaderResponse => {
42
- useEffect(() => {
43
- if (!feedUrl) {
44
- logger.warning({
45
- message: "Required parameter feedUrl is missing",
46
- data: { feedUrl },
47
- });
48
- }
49
- }, []);
50
-
51
40
  const isInitialRender = useIsInitialRender();
52
- const dispatch = useDispatch();
53
- const { screenData } = useRoute();
54
41
 
55
42
  const callableFeedUrl = useInflatedUrl({ feedUrl, mapping });
56
43
 
57
44
  const currentFeed = useZappPipesFeed(callableFeedUrl);
58
45
 
59
- const riverId =
60
- (screenData as LegacyNavigationScreenData)?.targetScreen?.id ??
61
- screenData?.id;
46
+ const loadPipesDataDispatcher = useLoadPipesDataDispatch();
62
47
 
63
48
  const reloadData = React.useCallback<ReloadDataFunction>(
64
49
  (silentRefresh = true, callback) => {
65
- if (callableFeedUrl) {
66
- dispatch(
67
- loadPipesData(callableFeedUrl, {
68
- clearCache: true,
69
- silentRefresh,
70
- callback,
71
- riverId,
72
- })
73
- );
74
- }
50
+ loadPipesDataDispatcher(
51
+ callableFeedUrl,
52
+ {
53
+ clearCache: true,
54
+ silentRefresh,
55
+ callback,
56
+ },
57
+ {
58
+ withResolvers: true,
59
+ }
60
+ );
75
61
  },
76
62
  [callableFeedUrl]
77
63
  );
@@ -80,15 +66,16 @@ export const useFeedLoader = ({
80
66
  if (callableFeedUrl) {
81
67
  const nextFeed = currentFeed?.data?.next;
82
68
 
83
- if (nextFeed) {
84
- dispatch(
85
- loadPipesData(nextFeed, {
86
- silentRefresh: true,
87
- parentFeed: callableFeedUrl,
88
- riverId,
89
- })
90
- );
91
- }
69
+ loadPipesDataDispatcher(
70
+ nextFeed,
71
+ {
72
+ silentRefresh: true,
73
+ parentFeed: callableFeedUrl,
74
+ },
75
+ {
76
+ withResolvers: true,
77
+ }
78
+ );
92
79
  }
93
80
  }, [callableFeedUrl, currentFeed?.data?.next]);
94
81
 
@@ -97,12 +84,16 @@ export const useFeedLoader = ({
97
84
  shouldDispatchData(callableFeedUrl, currentFeed, pipesOptions.clearCache)
98
85
  ) {
99
86
  if (callableFeedUrl && !pipesOptions.skipLoading) {
100
- dispatch(
101
- loadPipesData(callableFeedUrl, {
87
+ loadPipesDataDispatcher(
88
+ callableFeedUrl,
89
+ {
102
90
  ...pipesOptions,
103
91
  clearCache: true,
104
- riverId,
105
- })
92
+ },
93
+ {
94
+ withResolvers: true,
95
+ withScreenRouteMapping: true,
96
+ }
106
97
  );
107
98
  } else if (!callableFeedUrl) {
108
99
  logger.info({
@@ -131,9 +122,11 @@ export const useFeedLoader = ({
131
122
  // Reload feed when feedUrl changes, unless skipLoading is true
132
123
  useEffect(() => {
133
124
  if (!isInitialRender && callableFeedUrl && !pipesOptions.skipLoading) {
134
- dispatch(loadPipesData(callableFeedUrl, { ...pipesOptions, riverId }));
125
+ loadPipesDataDispatcher(callableFeedUrl, pipesOptions, {
126
+ withResolvers: true,
127
+ });
135
128
  }
136
- }, [callableFeedUrl]);
129
+ }, [callableFeedUrl, isInitialRender, pipesOptions.skipLoading]);
137
130
 
138
131
  return React.useMemo(() => {
139
132
  if (!callableFeedUrl || !feedUrl) {
@@ -18,6 +18,7 @@ import {
18
18
  } from "@applicaster/zapp-pipes-v2-client";
19
19
  import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
20
20
  import { ENDPOINT_TAGS } from "../../types";
21
+ import { isNilOrEmpty } from "../../reactUtils/helpers";
21
22
 
22
23
  /**
23
24
  * will match any occurrence in a string of one or more word characters
@@ -75,15 +76,19 @@ export const getInflatedDataSourceUrl: GetInflatedDataSourceUrl = ({
75
76
  * https://foo.com/shows/A1234
76
77
  */
77
78
 
78
- if (!source) {
79
- // eslint-disable-next-line no-console
80
- console.error("source is empty", {
81
- source,
82
- contexts,
83
- mapping,
84
- });
79
+ if (!isNilOrEmpty(mapping)) {
80
+ if (!source) {
81
+ if (__DEV__) {
82
+ // eslint-disable-next-line no-console
83
+ throw new Error(
84
+ "getInflatedDataSourceUrl: source is empty while mapping is provided"
85
+ );
86
+ }
85
87
 
86
- return null;
88
+ return null;
89
+ }
90
+ } else {
91
+ return source || null;
87
92
  }
88
93
 
89
94
  // Hack because in tv we expect to get key names instead of values from the fake entry
@@ -193,28 +198,17 @@ export function useInflatedUrl({
193
198
 
194
199
  const url = useMemo(
195
200
  () =>
196
- mapping
197
- ? getInflatedDataSourceUrl({
198
- source: feedUrl,
199
- contexts: {
200
- entry: entryContext,
201
- screen: screenContext,
202
- search: getSearchContext(searchContext, mapping),
203
- },
204
- mapping,
205
- })
206
- : feedUrl,
207
- [feedUrl, mapping]
201
+ getInflatedDataSourceUrl({
202
+ source: feedUrl,
203
+ contexts: {
204
+ entry: entryContext,
205
+ screen: screenContext,
206
+ search: getSearchContext(searchContext, mapping),
207
+ },
208
+ mapping,
209
+ }),
210
+ [entryContext, feedUrl, mapping, screenContext, searchContext]
208
211
  );
209
212
 
210
- if (!feedUrl) {
211
- logger.warning({
212
- message: "Required parameter feedUrl is missing",
213
- data: { feedUrl },
214
- });
215
-
216
- return null;
217
- }
218
-
219
213
  return url;
220
214
  }
@@ -0,0 +1,63 @@
1
+ import {
2
+ useAppDispatch,
3
+ ZappPipes,
4
+ } from "@applicaster/zapp-react-native-redux";
5
+ import { applyScreenRouteDefaults } from "@applicaster/zapp-react-native-redux/ZappPipes/feedProcessor";
6
+ import React from "react";
7
+ import { useScreenResolvers } from "../../actionsExecutor/screenResolver";
8
+ import { useRoute } from "../navigation";
9
+ import { useScreenStateStore } from "../navigation/useScreenStateStore";
10
+
11
+ export const useLoadPipesDataDispatch = () => {
12
+ const screenStateStore = useScreenStateStore();
13
+ const resolvers = useScreenResolvers();
14
+ const dispatch = useAppDispatch();
15
+
16
+ const { pathname, screenData } = useRoute();
17
+
18
+ const riverId =
19
+ (screenData as LegacyNavigationScreenData)?.targetScreen?.id ??
20
+ screenData?.id;
21
+
22
+ const onLoadCB = (options) => (data, _err) => {
23
+ options?.callback?.();
24
+
25
+ if (data) {
26
+ applyScreenRouteDefaults(data, screenStateStore, pathname);
27
+ }
28
+ };
29
+
30
+ return React.useCallback(
31
+ (
32
+ url: string,
33
+ options: {
34
+ callback?: (data: unknown, error?: Error | null | undefined) => void;
35
+ riverId?: string;
36
+ clearCache?: boolean;
37
+ silentRefresh?: boolean;
38
+ parentFeed?: string;
39
+ } = {},
40
+ {
41
+ withResolvers = false,
42
+ withScreenRouteMapping = false,
43
+ }: {
44
+ withResolvers?: boolean;
45
+ withScreenRouteMapping?: boolean;
46
+ } = {}
47
+ ) => {
48
+ if (url) {
49
+ dispatch(
50
+ ZappPipes.loadPipesData(url, {
51
+ riverId,
52
+ resolvers: withResolvers ? resolvers : undefined,
53
+ ...options,
54
+ callback: withScreenRouteMapping
55
+ ? onLoadCB(options)
56
+ : options?.callback,
57
+ })
58
+ );
59
+ }
60
+ },
61
+ []
62
+ );
63
+ };
@@ -1,11 +1,11 @@
1
1
  import React from "react";
2
- import { useDispatch } from "react-redux";
3
2
 
4
3
  import { getDatasourceUrl } from "@applicaster/zapp-react-native-ui-components/Decorators/RiverFeedLoader/utils/getDatasourceUrl";
5
4
  import { usePipesContexts } from "@applicaster/zapp-react-native-ui-components/Decorators/RiverFeedLoader/utils/usePipesContexts";
6
5
  import { clearPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
7
6
 
8
- import { useRoute } from "../navigation/useRoute";
7
+ import { useRoute } from "../navigation";
8
+ import { useAppDispatch } from "@applicaster/zapp-react-native-redux";
9
9
 
10
10
  /**
11
11
  * reset river components cache when screen is unmounted
@@ -13,7 +13,7 @@ import { useRoute } from "../navigation/useRoute";
13
13
  * @param {Array} riverComponents list of UI components
14
14
  */
15
15
  export const usePipesCacheReset = (riverId, riverComponents) => {
16
- const dispatch = useDispatch();
16
+ const dispatch = useAppDispatch();
17
17
  const { screenData, pathname } = useRoute();
18
18
  const pipesContexts = usePipesContexts(riverId, pathname);
19
19
 
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import * as R from "ramda";
3
- import { View } from "react-native";
3
+ import { View, ViewStyle } from "react-native";
4
4
 
5
5
  import { platformSelect } from "../../reactUtils";
6
6
 
@@ -49,13 +49,13 @@ export const useSequentialRenderItem = (data: Data) => {
49
49
  const readyToDisplay =
50
50
  index === 0 ? true : arePreviousComponentsReady(index);
51
51
 
52
- const displayStyle = {
52
+ const displayStyle: ViewStyle = {
53
53
  display: readyToDisplay ? "flex" : "none",
54
54
  };
55
55
 
56
56
  const readyStyle = {
57
57
  visibility: readyToDisplay ? "visible" : "hidden",
58
- };
58
+ } as ViewStyle;
59
59
 
60
60
  const style = platformSelect({
61
61
  tvos: readyStyle,
@@ -42,15 +42,17 @@ jest.mock("react-native-safe-area-context", () => ({
42
42
  }));
43
43
 
44
44
  jest.mock("../../../reactUtils", () => ({
45
+ ...jest.requireActual("../../../reactUtils"),
45
46
  platformSelect: jest.fn((specs) => specs[platform] || specs.default),
46
47
  isTV: jest.fn(() => mock_tv_flag),
47
48
  }));
48
49
 
49
50
  jest.mock("../../navigation", () => ({
50
- useNavigation: () => null,
51
51
  useIsScreenActive: () => true,
52
52
  }));
53
53
 
54
+ jest.mock("../../navigation/useNavigation");
55
+
54
56
  const { Dimensions } = require("react-native");
55
57
  const { useDimensions } = require("..");
56
58
 
@@ -44,7 +44,7 @@ export function useStatusBarHeight() {
44
44
 
45
45
  return platformSelect({
46
46
  ios: StatusBarHeight,
47
- android: StatusBar.currentHeight,
47
+ android: StatusBar.currentHeight ?? 0,
48
48
  default: 0,
49
49
  });
50
50
  }
@@ -1,21 +1,28 @@
1
1
  import { NativeModules, Platform } from "react-native";
2
2
 
3
+ export const isAndroidTablet = () => {
4
+ const { initialProps } = NativeModules.QuickBrickCommunicationModule;
5
+
6
+ return initialProps?.is_tablet;
7
+ };
8
+
3
9
  /**
4
10
  * Determines wether the given device is a tablet based on dimensions, orientation, and platform
5
11
  * @param {Object} dimensions - Dimensions object passed to the function
6
12
  * @param {String} orientation - Orientation enum passed to the function
7
13
  * @returns {Boolean} isTablet - returns whether the given device is a tablet
8
14
  */
9
- export const isTablet = (dimensions, orientation) => {
15
+ export const isTablet = (
16
+ dimensions?: { width: number; height: number },
17
+ orientation?: string
18
+ ) => {
10
19
  if (Platform?.OS === "ios") {
11
20
  return Platform?.isPad;
12
21
  } else if (Platform?.OS === "android") {
13
- const { initialProps } = NativeModules.QuickBrickCommunicationModule;
14
-
15
- return initialProps?.is_tablet;
22
+ return isAndroidTablet();
16
23
  }
17
24
 
18
- const { width } = dimensions;
25
+ const { width } = dimensions || {};
19
26
 
20
27
  if (width < 600) return false;
21
28
  if (width >= 600 && width < 840) return orientation === "portrait";