@applicaster/zapp-react-native-ui-components 14.0.0-alpha.9256258513 → 14.0.0-alpha.9551591420

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 (66) hide show
  1. package/Components/AnimatedInOut/index.tsx +5 -3
  2. package/Components/AudioPlayer/mobile/Layout.tsx +1 -1
  3. package/Components/AudioPlayer/tv/helpers.tsx +10 -3
  4. package/Components/Cell/Cell.tsx +3 -8
  5. package/Components/Cell/index.js +1 -1
  6. package/Components/ComponentResolver/index.ts +1 -1
  7. package/Components/FeedLoader/index.js +1 -1
  8. package/Components/Focusable/FocusableTvOS.tsx +3 -3
  9. package/Components/Focusable/FocusableiOS.tsx +2 -2
  10. package/Components/Focusable/index.tsx +1 -1
  11. package/Components/FocusableList/index.tsx +4 -0
  12. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +42 -59
  13. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +12 -8
  14. package/Components/HandlePlayable/HandlePlayable.tsx +14 -8
  15. package/Components/Layout/TV/LayoutBackground.tsx +1 -1
  16. package/Components/MasterCell/DefaultComponents/Button.tsx +1 -1
  17. package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +1 -1
  18. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +1 -1
  19. package/Components/MasterCell/elementMapper.tsx +1 -2
  20. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +13 -18
  21. package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +9 -0
  22. package/Components/OfflineHandler/__tests__/index.test.tsx +20 -22
  23. package/Components/PlayerContainer/ErrorDisplay/index.ts +1 -1
  24. package/Components/PlayerContainer/PlayerContainer.tsx +26 -22
  25. package/Components/PlayerContainer/ProgramInfo/index.tsx +1 -1
  26. package/Components/PlayerContainer/index.ts +1 -1
  27. package/Components/River/ComponentsMap/ComponentsMap.tsx +0 -1
  28. package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +379 -0
  29. package/Components/River/ComponentsMap/hooks/useLoadingState.ts +2 -2
  30. package/Components/River/RefreshControl.tsx +6 -4
  31. package/Components/River/TV/River.tsx +2 -17
  32. package/Components/River/TV/index.tsx +3 -1
  33. package/Components/River/TV/withPipesV1DataLoader.tsx +43 -0
  34. package/Components/River/TV/withRiverDataLoader.tsx +17 -0
  35. package/Components/River/TV/withTVEventHandler.tsx +1 -1
  36. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +2 -0
  37. package/Components/River/index.tsx +1 -1
  38. package/Components/Screen/__tests__/Screen.test.tsx +23 -12
  39. package/Components/ScreenRevealManager/ScreenRevealManager.ts +76 -0
  40. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +107 -0
  41. package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +96 -0
  42. package/Components/ScreenRevealManager/index.ts +1 -0
  43. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +79 -0
  44. package/Components/Tabs/TV/Tabs.android.tsx +0 -2
  45. package/Components/TextInputTv/__tests__/__snapshots__/TextInputTv.test.js.snap +0 -13
  46. package/Components/TextInputTv/index.tsx +0 -11
  47. package/Components/Touchable/__tests__/__snapshots__/touchable.test.tsx.snap +34 -0
  48. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +15 -9
  49. package/Components/VideoLive/animationUtils.ts +3 -3
  50. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +24 -8
  51. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +12 -16
  52. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +84 -24
  53. package/Decorators/ConfigurationWrapper/withConfigurationProvider.tsx +2 -2
  54. package/Decorators/RiverResolver/__tests__/riverResolver.test.tsx +3 -6
  55. package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -0
  56. package/Decorators/ZappPipesDataConnector/__tests__/NullFeedResolver.test.tsx +78 -0
  57. package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +205 -0
  58. package/Decorators/ZappPipesDataConnector/__tests__/StaticFeedResolver.test.tsx +251 -0
  59. package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +368 -0
  60. package/Decorators/ZappPipesDataConnector/__tests__/utils.test.ts +39 -0
  61. package/Decorators/ZappPipesDataConnector/index.tsx +26 -293
  62. package/Decorators/ZappPipesDataConnector/resolvers/NullFeedResolver.tsx +25 -0
  63. package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +87 -0
  64. package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +241 -0
  65. package/Decorators/ZappPipesDataConnector/types.ts +29 -0
  66. package/package.json +5 -7
@@ -1,7 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { useEffect, useReducer } from "react";
3
- // @ts-ignore
4
- import { TVMenuControl, View, ViewStyle } from "react-native";
3
+ import { View, ViewStyle } from "react-native";
5
4
  import * as R from "ramda";
6
5
  import uuid from "uuid/v4";
7
6
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
@@ -62,6 +61,11 @@ import {
62
61
  useModalAnimationContext,
63
62
  } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
64
63
 
64
+ import {
65
+ PlayerNativeCommandTypes,
66
+ PlayerNativeSendCommand,
67
+ } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerNativeCommand";
68
+
65
69
  type Props = {
66
70
  Player: React.ComponentType<any>;
67
71
  PlayerLoadingView?: React.ComponentType<any>; // 👀 we are not receiving this prop
@@ -259,9 +263,15 @@ const PlayerContainerComponent = (props: Props) => {
259
263
  return;
260
264
  }
261
265
 
266
+ // send command to clear and stop player
267
+ PlayerNativeSendCommand(
268
+ PlayerNativeCommandTypes.clearPlayerData,
269
+ state.playerId
270
+ );
271
+
262
272
  showNavBar(true);
263
273
  navigator.goBack();
264
- }, [isModal, navigator.goBack, showNavBar]);
274
+ }, [isModal, navigator.goBack, state.playerId, showNavBar]);
265
275
 
266
276
  const playEntry = (entry) => navigator.replaceTop(entry, { mode });
267
277
 
@@ -389,13 +399,17 @@ const PlayerContainerComponent = (props: Props) => {
389
399
  }
390
400
  };
391
401
 
392
- const playerRemoteHandler = (event, isLanguageOverlayVisible) => {
393
- const { eventType } = event;
402
+ const playerRemoteHandler = React.useCallback(
403
+ (isLanguageOverlayVisible = false) =>
404
+ (event) => {
405
+ const { eventType } = event;
394
406
 
395
- if (!isLanguageOverlayVisible && eventType === "menu") {
396
- close();
397
- }
398
- };
407
+ if (!isLanguageOverlayVisible && eventType === "menu") {
408
+ close();
409
+ }
410
+ },
411
+ [close]
412
+ );
399
413
 
400
414
  // Effects
401
415
  useEffect(() => {
@@ -508,16 +522,6 @@ const PlayerContainerComponent = (props: Props) => {
508
522
  }
509
523
  }, [isAudioContent]);
510
524
 
511
- // Needs to handle back button on Apple TV
512
- // https://github.com/facebook/react-native/issues/18930
513
- useEffect(() => {
514
- TVMenuControl?.enableTVMenuKey();
515
-
516
- return () => {
517
- TVMenuControl?.disableTVMenuKey();
518
- };
519
- }, []);
520
-
521
525
  useEffect(() => {
522
526
  playerEvent("source_changed", { item });
523
527
 
@@ -633,9 +637,9 @@ const PlayerContainerComponent = (props: Props) => {
633
637
  <PlayerContainerContext.Consumer>
634
638
  {(context) => (
635
639
  <TVEventHandlerComponent
636
- tvEventHandler={(_component, event) =>
637
- playerRemoteHandler(event, context.isLanguageOverlayVisible)
638
- }
640
+ tvEventHandler={playerRemoteHandler(
641
+ context.isLanguageOverlayVisible
642
+ )}
639
643
  >
640
644
  <FocusableGroup
641
645
  id={FocusableGroupMainContainerId}
@@ -1,4 +1,4 @@
1
- import { connectToStore } from "@applicaster/zapp-react-native-redux";
1
+ import { connectToStore } from "@applicaster/zapp-react-native-redux/utils/connectToStore";
2
2
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
3
3
  import { styleKeys } from "@applicaster/zapp-react-native-utils/styleKeysUtils";
4
4
  import { transformColorCode as fixColorHexCode } from "@applicaster/zapp-react-native-utils/transform";
@@ -1,6 +1,6 @@
1
1
  import * as R from "ramda";
2
2
 
3
- import { connectToStore } from "@applicaster/zapp-react-native-redux";
3
+ import { connectToStore } from "@applicaster/zapp-react-native-redux/utils/connectToStore";
4
4
  import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
5
5
 
6
6
  import { PlayerContainer as PlayerContainerComponent } from "./PlayerContainer";
@@ -286,7 +286,6 @@ function ComponentsMapComponent(props: Props) {
286
286
  initialNumToRender={3}
287
287
  maxToRenderPerBatch={10}
288
288
  windowSize={12}
289
- listKey={riverId}
290
289
  keyExtractor={keyExtractor}
291
290
  renderItem={renderRiverItem}
292
291
  data={riverComponents}
@@ -0,0 +1,379 @@
1
+ import { renderHook, act } from "@testing-library/react-hooks";
2
+ import { BehaviorSubject } from "rxjs";
3
+ import { useLoadingState } from "../useLoadingState";
4
+
5
+ // Mock the useRefWithInitialValue hook
6
+ jest.mock(
7
+ "@applicaster/zapp-react-native-utils/reactHooks/state/useRefWithInitialValue",
8
+ () => ({
9
+ useRefWithInitialValue: jest.fn((initializer) => ({
10
+ current: initializer(),
11
+ })),
12
+ })
13
+ );
14
+
15
+ describe("useLoadingState", () => {
16
+ let onLoadDone: jest.Mock;
17
+
18
+ beforeEach(() => {
19
+ onLoadDone = jest.fn();
20
+ jest.clearAllMocks();
21
+ });
22
+
23
+ describe("initialization", () => {
24
+ it("should initialize with correct default state for zero components", () => {
25
+ const { result } = renderHook(() => useLoadingState(0, onLoadDone));
26
+
27
+ const initialState = result.current.loadingState.getValue();
28
+
29
+ expect(initialState).toEqual({
30
+ index: -1,
31
+ done: true,
32
+ waitForAllComponents: false,
33
+ });
34
+
35
+ expect(result.current.shouldShowLoadingError).toBe(false);
36
+ });
37
+
38
+ it("should initialize with correct default state for multiple components", () => {
39
+ const { result } = renderHook(() => useLoadingState(3, onLoadDone));
40
+
41
+ const initialState = result.current.loadingState.getValue();
42
+
43
+ expect(initialState).toEqual({
44
+ index: -1,
45
+ done: false,
46
+ waitForAllComponents: false,
47
+ });
48
+
49
+ expect(result.current.shouldShowLoadingError).toBe(false);
50
+ });
51
+
52
+ it("should return a BehaviorSubject for loadingState", () => {
53
+ const { result } = renderHook(() => useLoadingState(3, onLoadDone));
54
+
55
+ expect(result.current.loadingState).toBeInstanceOf(BehaviorSubject);
56
+ });
57
+ });
58
+
59
+ describe("arePreviousComponentsLoaded", () => {
60
+ it("should return true for index 0 (first component)", () => {
61
+ const { result } = renderHook(() => useLoadingState(3, onLoadDone));
62
+
63
+ expect(result.current.arePreviousComponentsLoaded(0)).toBe(true);
64
+ });
65
+
66
+ it("should return false when previous components are not loaded", () => {
67
+ const { result } = renderHook(() => useLoadingState(3, onLoadDone));
68
+
69
+ expect(result.current.arePreviousComponentsLoaded(1)).toBe(false);
70
+ expect(result.current.arePreviousComponentsLoaded(2)).toBe(false);
71
+ });
72
+
73
+ it("should return true when all previous components are loaded", () => {
74
+ const { result } = renderHook(() => useLoadingState(3, onLoadDone));
75
+
76
+ act(() => {
77
+ result.current.onLoadFinished(0);
78
+ });
79
+
80
+ expect(result.current.arePreviousComponentsLoaded(1)).toBe(true);
81
+ expect(result.current.arePreviousComponentsLoaded(2)).toBe(false);
82
+
83
+ act(() => {
84
+ result.current.onLoadFinished(1);
85
+ });
86
+
87
+ expect(result.current.arePreviousComponentsLoaded(2)).toBe(true);
88
+ });
89
+ });
90
+
91
+ describe("onLoadFinished", () => {
92
+ it("should update component state and loading state when component finishes loading", () => {
93
+ const { result } = renderHook(() => useLoadingState(3, onLoadDone));
94
+
95
+ act(() => {
96
+ result.current.onLoadFinished(0);
97
+ });
98
+
99
+ const state = result.current.loadingState.getValue();
100
+ expect(state.index).toBe(0);
101
+ expect(state.done).toBe(false);
102
+ });
103
+
104
+ it("should update index to highest loaded component", () => {
105
+ const { result } = renderHook(() => useLoadingState(3, onLoadDone));
106
+
107
+ act(() => {
108
+ result.current.onLoadFinished(2);
109
+ });
110
+
111
+ let state = result.current.loadingState.getValue();
112
+ expect(state.index).toBe(2);
113
+
114
+ act(() => {
115
+ result.current.onLoadFinished(1);
116
+ });
117
+
118
+ state = result.current.loadingState.getValue();
119
+ expect(state.index).toBe(2); // Should remain 2, not decrease to 1
120
+ });
121
+
122
+ it("should mark as done when all components are loaded", () => {
123
+ const { result } = renderHook(() => useLoadingState(2, onLoadDone));
124
+
125
+ act(() => {
126
+ result.current.onLoadFinished(0);
127
+ });
128
+
129
+ let state = result.current.loadingState.getValue();
130
+ expect(state.done).toBe(true); // True because arePreviousComponentsLoaded(1) returns true when component 0 is loaded
131
+ expect(onLoadDone).toHaveBeenCalledTimes(1);
132
+
133
+ act(() => {
134
+ result.current.onLoadFinished(1);
135
+ });
136
+
137
+ state = result.current.loadingState.getValue();
138
+ expect(state.done).toBe(true);
139
+ expect(onLoadDone).toHaveBeenCalledTimes(2); // Called again
140
+ });
141
+
142
+ it("should call onLoadDone when count is 0", () => {
143
+ const { result } = renderHook(() => useLoadingState(0, onLoadDone));
144
+
145
+ const state = result.current.loadingState.getValue();
146
+ expect(state.done).toBe(true);
147
+ // onLoadDone is not called on initialization for count 0, only when all components are loaded via dispatch
148
+ });
149
+
150
+ it("should handle loading components out of order", () => {
151
+ const { result } = renderHook(() => useLoadingState(3, onLoadDone));
152
+
153
+ // Load component 2 first
154
+ act(() => {
155
+ result.current.onLoadFinished(2);
156
+ });
157
+
158
+ let state = result.current.loadingState.getValue();
159
+ expect(state.done).toBe(false);
160
+
161
+ // Load component 0
162
+ act(() => {
163
+ result.current.onLoadFinished(0);
164
+ });
165
+
166
+ state = result.current.loadingState.getValue();
167
+ expect(state.done).toBe(false);
168
+
169
+ // Load component 1 - should complete loading
170
+ act(() => {
171
+ result.current.onLoadFinished(1);
172
+ });
173
+
174
+ state = result.current.loadingState.getValue();
175
+ expect(state.done).toBe(true);
176
+ expect(onLoadDone).toHaveBeenCalledTimes(1);
177
+ });
178
+
179
+ it("should call onLoadDone again on subsequent dispatches", () => {
180
+ const { result } = renderHook(() => useLoadingState(2, onLoadDone));
181
+
182
+ act(() => {
183
+ result.current.onLoadFinished(0);
184
+ result.current.onLoadFinished(1);
185
+ });
186
+
187
+ expect(onLoadDone).toHaveBeenCalledTimes(2); // Called for each dispatch when done is true
188
+
189
+ // Try loading again - onLoadDone will be called again because dispatch runs again
190
+ act(() => {
191
+ result.current.onLoadFinished(0);
192
+ });
193
+
194
+ expect(onLoadDone).toHaveBeenCalledTimes(3); // Will be called again
195
+ });
196
+ });
197
+
198
+ describe("onLoadFailed", () => {
199
+ it("should treat failed components as loaded when SHOULD_FAIL_ON_COMPONENT_LOADING is false", () => {
200
+ const { result } = renderHook(() => useLoadingState(2, onLoadDone));
201
+
202
+ const error = new Error("Load failed");
203
+
204
+ act(() => {
205
+ result.current.onLoadFailed({ error, index: 0 });
206
+ });
207
+
208
+ const state = result.current.loadingState.getValue();
209
+ expect(state.index).toBe(0);
210
+ expect(result.current.shouldShowLoadingError).toBe(false);
211
+ });
212
+
213
+ it("should complete loading when all components fail", () => {
214
+ const { result } = renderHook(() => useLoadingState(2, onLoadDone));
215
+
216
+ const error = new Error("Load failed");
217
+
218
+ act(() => {
219
+ result.current.onLoadFailed({ error, index: 0 });
220
+ result.current.onLoadFailed({ error, index: 1 });
221
+ });
222
+
223
+ const state = result.current.loadingState.getValue();
224
+ expect(state.done).toBe(true);
225
+ expect(onLoadDone).toHaveBeenCalledTimes(2); // Called for each failed component
226
+ });
227
+
228
+ it("should handle mixed success and failure", () => {
229
+ const { result } = renderHook(() => useLoadingState(3, onLoadDone));
230
+
231
+ const error = new Error("Load failed");
232
+
233
+ act(() => {
234
+ result.current.onLoadFinished(0);
235
+ result.current.onLoadFailed({ error, index: 1 });
236
+ result.current.onLoadFinished(2);
237
+ });
238
+
239
+ const state = result.current.loadingState.getValue();
240
+ expect(state.done).toBe(true);
241
+ expect(onLoadDone).toHaveBeenCalledTimes(2); // Called when all components 0,1,2 are handled
242
+ });
243
+ });
244
+
245
+ describe("loading state observable", () => {
246
+ it("should emit state changes through BehaviorSubject", () => {
247
+ const { result } = renderHook(() => useLoadingState(3, onLoadDone)); // Use 3 components so loading component 0 doesn't complete everything
248
+ const mockSubscriber = jest.fn();
249
+
250
+ result.current.loadingState.subscribe(mockSubscriber);
251
+
252
+ act(() => {
253
+ result.current.onLoadFinished(0);
254
+ });
255
+
256
+ // Should have been called twice: initial state + update
257
+ expect(mockSubscriber).toHaveBeenCalledTimes(2);
258
+
259
+ expect(mockSubscriber).toHaveBeenLastCalledWith({
260
+ index: 0,
261
+ done: false, // Will be false because we need components 1 and 2 as well
262
+ waitForAllComponents: false,
263
+ });
264
+ });
265
+
266
+ it("should preserve waitForAllComponents flag in state updates", () => {
267
+ const { result } = renderHook(() => useLoadingState(2, onLoadDone));
268
+
269
+ act(() => {
270
+ result.current.onLoadFinished(0);
271
+ });
272
+
273
+ const state = result.current.loadingState.getValue();
274
+ expect(state.waitForAllComponents).toBe(false);
275
+ });
276
+ });
277
+
278
+ describe("memoization", () => {
279
+ it("should return stable references for functions", () => {
280
+ const { result, rerender } = renderHook(() =>
281
+ useLoadingState(2, onLoadDone)
282
+ );
283
+
284
+ const firstRender = {
285
+ onLoadFinished: result.current.onLoadFinished,
286
+ onLoadFailed: result.current.onLoadFailed,
287
+ arePreviousComponentsLoaded: result.current.arePreviousComponentsLoaded,
288
+ };
289
+
290
+ rerender();
291
+
292
+ expect(result.current.onLoadFinished).toBe(firstRender.onLoadFinished);
293
+ expect(result.current.onLoadFailed).toBe(firstRender.onLoadFailed);
294
+
295
+ expect(result.current.arePreviousComponentsLoaded).toBe(
296
+ firstRender.arePreviousComponentsLoaded
297
+ );
298
+ });
299
+
300
+ it("should return stable function references (current behavior)", () => {
301
+ const { result, rerender } = renderHook(
302
+ ({ onLoadDone }) => useLoadingState(2, onLoadDone),
303
+ { initialProps: { onLoadDone } }
304
+ );
305
+
306
+ const firstResult = result.current;
307
+
308
+ const newOnLoadDone = jest.fn();
309
+ rerender({ onLoadDone: newOnLoadDone });
310
+
311
+ // Functions should remain the same due to empty dependency arrays (this is the current behavior)
312
+ expect(result.current.onLoadFinished).toBe(firstResult.onLoadFinished);
313
+ expect(result.current.onLoadFailed).toBe(firstResult.onLoadFailed);
314
+ });
315
+ });
316
+
317
+ describe("edge cases", () => {
318
+ it("should handle duplicate load finished calls gracefully", () => {
319
+ const { result } = renderHook(() => useLoadingState(2, onLoadDone));
320
+
321
+ act(() => {
322
+ result.current.onLoadFinished(0);
323
+ result.current.onLoadFinished(0); // Duplicate call
324
+ });
325
+
326
+ const state = result.current.loadingState.getValue();
327
+ expect(state.index).toBe(0);
328
+ expect(state.done).toBe(true); // True because loading component 0 makes it done in a 2-component setup
329
+ });
330
+
331
+ it("should handle loading index greater than component count", () => {
332
+ const { result } = renderHook(() => useLoadingState(2, onLoadDone));
333
+
334
+ act(() => {
335
+ result.current.onLoadFinished(5); // Index out of bounds
336
+ });
337
+
338
+ const state = result.current.loadingState.getValue();
339
+ expect(state.index).toBe(5);
340
+ expect(state.done).toBe(false); // Should not be done as not all components loaded
341
+ });
342
+
343
+ it("should handle negative indices", () => {
344
+ const { result } = renderHook(() => useLoadingState(2, onLoadDone));
345
+
346
+ act(() => {
347
+ result.current.onLoadFinished(-1);
348
+ });
349
+
350
+ const state = result.current.loadingState.getValue();
351
+ expect(state.index).toBe(-1); // Should remain -1
352
+ });
353
+ });
354
+
355
+ describe("component count changes", () => {
356
+ it("should handle changing component count", () => {
357
+ const { result, rerender } = renderHook(
358
+ ({ count }) => useLoadingState(count, onLoadDone),
359
+ { initialProps: { count: 2 } }
360
+ );
361
+
362
+ act(() => {
363
+ result.current.onLoadFinished(0);
364
+ });
365
+
366
+ // Change count
367
+ rerender({ count: 3 });
368
+
369
+ // The hook should work with the new count
370
+ act(() => {
371
+ result.current.onLoadFinished(1);
372
+ result.current.onLoadFinished(2);
373
+ });
374
+
375
+ const state = result.current.loadingState.getValue();
376
+ expect(state.done).toBe(true);
377
+ });
378
+ });
379
+ });
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { isNil, set, lensIndex, T, slice } from "ramda";
2
+ import { isNil, set, lensIndex, slice } from "ramda";
3
3
  import { BehaviorSubject } from "rxjs";
4
4
  import { useRefWithInitialValue } from "@applicaster/zapp-react-native-utils/reactHooks/state/useRefWithInitialValue";
5
5
 
@@ -53,7 +53,7 @@ export const useLoadingState = (
53
53
 
54
54
  const componentsBefore = slice(0, index, componentStateRef.current);
55
55
 
56
- return componentsBefore.every(T);
56
+ return componentsBefore.every(Boolean);
57
57
  }, []);
58
58
 
59
59
  const dispatch = React.useCallback(({ payload }) => {
@@ -10,11 +10,13 @@ import { useLocalizedStrings } from "@applicaster/zapp-react-native-utils/locali
10
10
  import { useAnalytics } from "@applicaster/zapp-react-native-utils/analyticsUtils";
11
11
  import { useSendAnalyticsEventWithFunction } from "@applicaster/zapp-react-native-utils/analyticsUtils/helpers/hooks";
12
12
  import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useCurrentScreenData";
13
- import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
14
- import { useDispatch } from "react-redux";
15
13
  import { useShallow } from "zustand/react/shallow";
16
14
  import { useScreenContextV2 } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
17
15
  import { useSafeAreaInsets } from "react-native-safe-area-context";
16
+ import {
17
+ ZappPipes,
18
+ useAppDispatch,
19
+ } from "@applicaster/zapp-react-native-redux";
18
20
 
19
21
  const BRIGHTNESS_THRESHOLD = 160;
20
22
  const ABOVE_DEFAULT_COLOR = "gray";
@@ -61,7 +63,7 @@ export const usePullToRefresh = (
61
63
  ) => {
62
64
  const isPipesV1 = !!pullToRefreshPipesV1RefreshingStateUpdater;
63
65
 
64
- const dispatch = useDispatch();
66
+ const dispatch = useAppDispatch();
65
67
 
66
68
  const [refreshing, setRefreshing] = React.useState(false);
67
69
 
@@ -81,7 +83,7 @@ export const usePullToRefresh = (
81
83
  if (refreshing && !isPipesV1) {
82
84
  feeds.forEach((feed) => {
83
85
  dispatch(
84
- loadPipesData(feed, {
86
+ ZappPipes.loadPipesData(feed, {
85
87
  silentRefresh: true,
86
88
  clearCache: true,
87
89
  callback: () => {
@@ -4,10 +4,6 @@ import * as React from "react";
4
4
  import { Text } from "react-native";
5
5
  import * as R from "ramda";
6
6
 
7
- import {
8
- useFeedLoader,
9
- useLayoutVersion,
10
- } from "@applicaster/zapp-react-native-utils/reactHooks";
11
7
  import { GeneralContentScreen } from "../../GeneralContentScreen";
12
8
  import { ScreenResolver } from "@applicaster/zapp-react-native-ui-components/Components/ScreenResolver";
13
9
  import { utilsLogger } from "@applicaster/zapp-react-native-utils/logger";
@@ -21,6 +17,7 @@ type Props = {
21
17
  screenId: string;
22
18
  screenData: ZappRiver | ZappEntry;
23
19
  feedUrl?: string;
20
+ feedData?: PipesDataObject["data"];
24
21
  extraProps?: any;
25
22
  screenResolverExtraProps?: any;
26
23
  componentsMapExtraProps?: any;
@@ -32,7 +29,7 @@ type Props = {
32
29
  export const River = (props: Props) => {
33
30
  const {
34
31
  screenId,
35
- feedUrl,
32
+ feedData,
36
33
  extraProps,
37
34
  screenResolverExtraProps,
38
35
  componentsMapExtraProps,
@@ -46,7 +43,6 @@ export const River = (props: Props) => {
46
43
  useSetNavbarState();
47
44
 
48
45
  const rivers = useRivers();
49
- const isV2 = useLayoutVersion({ isV2: true });
50
46
 
51
47
  const river = React.useMemo(() => rivers?.[screenId], [screenId]);
52
48
 
@@ -55,17 +51,6 @@ export const River = (props: Props) => {
55
51
  [screenId]
56
52
  );
57
53
 
58
- const connectedScreenUrl = React.useMemo(() => {
59
- // Avoid using feedUrl or content.src on layouts v2
60
- if (isV2) return null;
61
-
62
- return feedUrl || R.path(["content", "src"], screenData);
63
- }, [feedUrl, screenData]);
64
-
65
- const { data: feedData } = useFeedLoader({
66
- feedUrl: connectedScreenUrl,
67
- });
68
-
69
54
  const stringOrEmpty = (value: string | number | undefined): string =>
70
55
  R.isNil(value) ? "" : String(value);
71
56
 
@@ -2,8 +2,10 @@ import { compose } from "ramda";
2
2
  import { River as RiverComponent } from "./River";
3
3
  import { withTvEventHandler } from "./withTVEventHandler";
4
4
  import { withComponentsMapOffsetContext } from "../../../Contexts/ComponentsMapOffsetContext";
5
+ import { withRiverDataLoader } from "./withRiverDataLoader";
5
6
 
6
7
  export const River = compose(
7
8
  withTvEventHandler,
8
- withComponentsMapOffsetContext
9
+ withComponentsMapOffsetContext,
10
+ withRiverDataLoader
9
11
  )(RiverComponent);
@@ -0,0 +1,43 @@
1
+ import React, { useMemo } from "react";
2
+ import { path } from "ramda";
3
+
4
+ import {
5
+ useFeedLoader,
6
+ useRivers,
7
+ } from "@applicaster/zapp-react-native-utils/reactHooks";
8
+
9
+ type Props = {
10
+ screenId: string;
11
+ screenData: ZappRiver | ZappEntry;
12
+ feedUrl?: string;
13
+ river?: ZappRiver | ZappEntry;
14
+ };
15
+
16
+ export const withPipesV1DataLoader = (
17
+ WrappedComponent: React.ComponentType<any>
18
+ ) => {
19
+ return function WithPipesV1DataLoaderComponent(props: Props) {
20
+ const { screenId, feedUrl } = props;
21
+
22
+ const rivers = useRivers();
23
+
24
+ const river = React.useMemo(() => rivers?.[screenId], [screenId]);
25
+
26
+ const screenData = React.useMemo(
27
+ () => props.screenData || props.river || river,
28
+ [screenId]
29
+ );
30
+
31
+ const connectedScreenUrl = useMemo(() => {
32
+ // Avoid using feedUrl or content.src on layouts v2
33
+
34
+ return feedUrl || path(["content", "src"], screenData);
35
+ }, [feedUrl, screenData]);
36
+
37
+ const { data: feedData } = useFeedLoader({
38
+ feedUrl: connectedScreenUrl,
39
+ });
40
+
41
+ return <WrappedComponent {...props} feedData={feedData} />;
42
+ };
43
+ };
@@ -0,0 +1,17 @@
1
+ import { useLayoutVersion } from "@applicaster/zapp-react-native-utils/reactHooks";
2
+ import React from "react";
3
+ import { withPipesV1DataLoader } from "./withPipesV1DataLoader";
4
+
5
+ export const withRiverDataLoader = (
6
+ WrappedComponent: React.ComponentType<any>
7
+ ) => {
8
+ return function WithRiverDataLoaderComponent(props) {
9
+ const isV2 = useLayoutVersion({ isV2: true });
10
+
11
+ if (isV2) {
12
+ return <WrappedComponent {...props} />;
13
+ }
14
+
15
+ return withPipesV1DataLoader(WrappedComponent)(props);
16
+ };
17
+ };
@@ -8,7 +8,7 @@ export const withTvEventHandler = (Component) => {
8
8
  return function WithTVEventHandler(props) {
9
9
  const navigator = useNavigation();
10
10
 
11
- const remoteHandler = (_, event) => {
11
+ const remoteHandler = (event) => {
12
12
  const { eventType } = event;
13
13
 
14
14
  const canGoBack = navigator.canGoBack();