@applicaster/zapp-react-native-utils 12.0.0-alpha.4440903139 → 12.0.0-alpha.4484269996

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.
@@ -77,6 +77,8 @@ describe("useBatchLoading", () => {
77
77
 
78
78
  const actions = store.getActions();
79
79
 
80
+ expect(useDispatchSpy).toBeCalledTimes(1);
81
+
80
82
  expect(actions).toHaveLength(2);
81
83
 
82
84
  expect(actions[0]).toMatchObject({
@@ -127,8 +129,6 @@ describe("useBatchLoading", () => {
127
129
  // ... more items
128
130
  ];
129
131
 
130
- expect(useDispatchSpy).toBeCalledTimes(0);
131
-
132
132
  renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
133
133
  wrapper,
134
134
  initialProps: { store },
@@ -136,6 +136,8 @@ describe("useBatchLoading", () => {
136
136
 
137
137
  const actions = store.getActions();
138
138
 
139
+ expect(useDispatchSpy).toBeCalledTimes(1);
140
+
139
141
  expect(actions).toHaveLength(1);
140
142
 
141
143
  expect(actions[0]).toMatchObject({
@@ -170,6 +172,8 @@ describe("useBatchLoading", () => {
170
172
  initialProps: { store },
171
173
  });
172
174
 
175
+ expect(useDispatchSpy).toBeCalledTimes(1);
176
+
173
177
  const actions = store.getActions();
174
178
 
175
179
  expect(actions).toHaveLength(3);
@@ -214,73 +218,6 @@ describe("useBatchLoading", () => {
214
218
 
215
219
  expect(result.current).toBe(true);
216
220
  });
217
-
218
- it("gallery-qb: loadPipesData should be called only once for first component in the gallery", () => {
219
- const store = mockStore({
220
- zappPipes: {},
221
- test: "true",
222
- });
223
-
224
- useDispatchSpy.mockReturnValue(store.dispatch);
225
-
226
- const initialBatchSize = 3;
227
- const riverId = "123";
228
-
229
- const data = [
230
- {
231
- component_type: "gallery-qb",
232
- ui_components: [{ data: { source: "url1" } }],
233
- },
234
- { data: { source: "url2" } },
235
- { data: { source: "url3" } },
236
- { data: { source: "url4" } },
237
- { data: { source: "url5" } },
238
- { data: { source: "url6" } },
239
- // ... more items
240
- ];
241
-
242
- renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
243
- wrapper,
244
- initialProps: { store },
245
- });
246
-
247
- const actions = store.getActions();
248
-
249
- expect(actions).toHaveLength(1);
250
- });
251
-
252
- it("gallery-qb: initial batch ready when all initial items loaded", () => {
253
- const store = mockStore({
254
- zappPipes: {
255
- url1: {
256
- loading: false,
257
- error: false,
258
- data: {},
259
- },
260
- },
261
- });
262
-
263
- useDispatchSpy.mockReturnValue(store.dispatch);
264
-
265
- const initialBatchSize = 3;
266
- const riverId = "123";
267
-
268
- const data: Partial<ZappUIComponent>[] = [
269
- {
270
- component_type: "gallery-qb",
271
- ui_components: [{ data: { source: "url1" } }],
272
- },
273
- { data: { source: "url2" } },
274
- { data: { source: "url3" } },
275
- ];
276
-
277
- const { result } = renderHook(
278
- () => useBatchLoading(data, { initialBatchSize, riverId }),
279
- { wrapper, initialProps: { store } }
280
- );
281
-
282
- expect(result.current).toBe(true);
283
- });
284
221
  });
285
222
 
286
223
  describe("allFeedsIsReady", () => {
@@ -45,23 +45,19 @@ const filterEmptyData = (data) => {
45
45
  return true;
46
46
  };
47
47
 
48
- const getData = (rawData) =>
49
- rawData.component_type === "gallery-qb"
50
- ? rawData.ui_components[0].data
51
- : rawData.data;
52
-
53
- const extractData = compose(uniq, map(getData));
48
+ const extractData = compose(uniq, map(dataOf));
54
49
 
55
50
  export const allFeedsIsReady = (
56
51
  feeds: ZappPipesCollection,
57
52
  urls: (ZappDataSourceSource | null)[]
58
53
  ): boolean =>
59
- urls.every((url) =>
60
- isNil(url) ? true : url && feeds[url] ? checkFeedIsReady(feeds[url]) : false
61
- );
54
+ urls
55
+ .filter(complement(isNil))
56
+ .map((url) => (url ? checkFeedIsReady(feeds[url]) : false))
57
+ .every(Boolean);
62
58
 
63
59
  export const useBatchLoading = (
64
- componentsToRender: { data?: ZappDataSource; component_type: string }[],
60
+ data: { data?: ZappDataSource }[],
65
61
  options: Options
66
62
  ) => {
67
63
  const dispatch = useDispatch();
@@ -69,18 +65,10 @@ export const useBatchLoading = (
69
65
  const [searchContext] = ZappPipesSearchContext.useZappPipesContext();
70
66
  const [hasEverBeenReady, setHasEverBeenReady] = React.useState(false);
71
67
 
72
- // if first component is gallery-qb, take only one component for initial load
73
- const takeSize =
74
- componentsToRender?.[0]?.component_type === "gallery-qb"
75
- ? 1
76
- : min(
77
- options.initialBatchSize ?? DEFAULT_BATCH_SIZE,
78
- componentsToRender.length
79
- );
80
-
81
- const takeBatchSize = React.useCallback(take(takeSize), [takeSize]);
68
+ const takeBatchSize = take(
69
+ min(options.initialBatchSize ?? DEFAULT_BATCH_SIZE, data.length)
70
+ );
82
71
 
83
- // Prepare inflated url for datasource
84
72
  const getUrl = React.useCallback(
85
73
  (data) => {
86
74
  const mappedFeed = data.mapping
@@ -100,16 +88,13 @@ export const useBatchLoading = (
100
88
  [entryContext, screenContext, searchContext]
101
89
  );
102
90
 
103
- // components for initial load
104
- const batchComponents = takeBatchSize(componentsToRender);
91
+ const batchData = takeBatchSize(data);
105
92
 
106
- // contains datasources from batch components loading
107
93
  const feedData: ZappDataSource[] = React.useMemo(
108
- () => extractData(batchComponents).filter(filterEmptyData),
109
- [batchComponents]
94
+ () => extractData(batchData).filter(filterEmptyData),
95
+ [batchData]
110
96
  );
111
97
 
112
- // contains inflated urls from batch components loading
113
98
  const feedUrls: ZappDataSourceSource[] = React.useMemo(
114
99
  () =>
115
100
  feedData.map((data) => {
@@ -117,43 +102,34 @@ export const useBatchLoading = (
117
102
 
118
103
  return mappedFeedUrl;
119
104
  }),
120
- []
105
+ [] // No watchers as batch loaders is used only for initial load
121
106
  );
122
107
 
123
108
  const feeds = useZappPipesFeeds(feedUrls);
124
109
 
125
- // dispatch loadPipesData for each feed that is not loaded
126
- const runBatchLoading = React.useCallback(() => {
127
- batchComponents.forEach((rawData: any) => {
128
- // 1. get data (dataOf)
129
-
130
- const data = getData(rawData);
110
+ React.useEffect(() => {
111
+ const datasources = map(dataOf, batchData)
112
+ .filter(filterEmptyData)
113
+ .filter((data) => {
114
+ const feed = feeds[data.source];
131
115
 
132
- // 2. filter out empty data filterEmptyData
133
- if (!filterEmptyData(data)) return false;
116
+ if (!feed) return true;
134
117
 
135
- // 3. filter out data that is already loaded (feeds[data.source]) & !feedHasData(feed) && !feedIsLoading(feed);
136
- const feed = feeds[data?.source];
118
+ return !feedHasData(feed) && !feedIsLoading(feed);
119
+ });
137
120
 
138
- if (!feed || (!feedHasData(feed) && !feedIsLoading(feed))) {
139
- const mappedFeedUrl = getUrl(data);
121
+ datasources.forEach((data) => {
122
+ const mappedFeedUrl = getUrl(data);
140
123
 
141
- if (mappedFeedUrl) {
142
- // 4. load data
143
- return dispatch(
144
- loadPipesData(mappedFeedUrl, { riverId: options.riverId })
145
- );
146
- }
124
+ if (mappedFeedUrl) {
125
+ return dispatch(
126
+ loadPipesData(mappedFeedUrl, { riverId: options.riverId })
127
+ );
147
128
  }
148
129
  });
149
- }, [feedUrls]);
150
-
151
- React.useEffect(() => {
152
- runBatchLoading();
153
- }, []);
130
+ }, []); // No watchers as batch loaders is used only for initial load
154
131
 
155
132
  React.useEffect(() => {
156
- // check if all feeds are ready and set hasEverBeenReady to true
157
133
  if (allFeedsIsReady(feeds, feedUrls) && !hasEverBeenReady) {
158
134
  setHasEverBeenReady(true);
159
135
  }
@@ -17,7 +17,7 @@ import {
17
17
  QUICK_BRICK_NAVBAR,
18
18
  QUICK_BRICK_CONTENT,
19
19
  } from "@applicaster/quick-brick-core/const";
20
- import { useZappHooksModalState } from "@applicaster/zapp-react-dom-ui-components/Components/ZappHooksModal/hooks/useZappHooksModalState";
20
+ import { useZappHooksModalState } from "@applicaster/zapp-react-dom-ui-components/Components/ZappHooksModal/ZappHooksModal";
21
21
  import { ZappHookModalContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
22
22
  import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
23
23
  import { HookModalContextT } from "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext";
@@ -1,4 +1,5 @@
1
1
  import React, { useEffect, useState } from "react";
2
+ import * as R from "ramda";
2
3
  import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
3
4
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
4
5
  import {
@@ -42,7 +43,7 @@ export const useAutoSeek = (resetHUDTimer = noop) => {
42
43
  if (!player) return;
43
44
 
44
45
  if (direction) {
45
- player[direction](Math.min(MAX_SEEK_TIME, SKIP_TIME_BASE * multiplier));
46
+ player[direction](R.min(MAX_SEEK_TIME, SKIP_TIME_BASE * multiplier));
46
47
  resetHUDTimer();
47
48
  }
48
49
  }, [multiplier, direction]);
@@ -50,9 +51,7 @@ export const useAutoSeek = (resetHUDTimer = noop) => {
50
51
  useEffect(() => {
51
52
  if (isRunning && isRunning !== prevRunning) {
52
53
  setIntervalTimer(() => {
53
- setMultiplier((prev) => {
54
- return prev + 1;
55
- });
54
+ setMultiplier(R.add(1));
56
55
  });
57
56
  } else if (!isRunning && isRunning !== prevRunning) {
58
57
  resetState();
@@ -67,7 +67,7 @@ export const useConfiguration = ({
67
67
  if (component) {
68
68
  const remappedStylesConfiguration = remapUpdatedKeys(
69
69
  pluginManifest,
70
- component
70
+ component.styles
71
71
  );
72
72
 
73
73
  R.forEachObjIndexed((value, key) => {
@@ -83,7 +83,7 @@ export const useConfiguration = ({
83
83
 
84
84
  const styles = populateConfigurationValues(
85
85
  pluginManifest?.styles?.fields,
86
- remappedStylesConfiguration.styles,
86
+ remappedStylesConfiguration,
87
87
  skipDefaults
88
88
  );
89
89
 
@@ -7,11 +7,9 @@ import { Provider } from "react-redux";
7
7
  import thunk from "redux-thunk";
8
8
  import configureStore from "redux-mock-store";
9
9
  import { SafeAreaProvider } from "react-native-safe-area-context";
10
- import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
11
10
 
12
11
  import { render } from "@testing-library/react-native";
13
12
  import { AnalyticsProvider } from "../analyticsUtils";
14
- import { ThemeContext } from "../theme";
15
13
 
16
14
  export { getByTestId } from "./getByTestId";
17
15
 
@@ -61,9 +59,7 @@ const initialState = {
61
59
  appSettings: {},
62
60
  plugins: [],
63
61
  appState: { appReady: true, appLaunched: true },
64
- pluginConfigurations: {},
65
62
  appData: { layoutVersion: "v1" },
66
- zappPipes: {},
67
63
  contentTypes: null,
68
64
  };
69
65
 
@@ -72,49 +68,20 @@ export const WrappedWithProviders = ({
72
68
  store: storeObj = {},
73
69
  }: any) => {
74
70
  const _store = configureStore([thunk])(
75
- R.mergeDeepRight(initialState, { ...storeObj })
71
+ R.mergeDeepWith(R.concat, { ...initialState }, storeObj)
76
72
  );
77
73
 
78
- appStore.set(_store);
79
-
80
74
  return (
81
- <ThemeContext.Provider
82
- value={{
83
- themes: {
84
- light: {
85
- component_margin_top: 0,
86
- component_margin_bottom: 0,
87
- component_margin_left: 0,
88
- component_margin_right: 0,
89
- component_padding_top: 0,
90
- component_padding_bottom: 0,
91
- component_padding_left: 0,
92
- component_padding_right: 0,
93
- component_gutter_vertical: 0,
94
- component_gutter_horizontal: 0,
95
- component_corner_radius: 0,
96
- app_background_color: "rgba(0,0,0,0)",
97
- screen_margin_top: 0,
98
- screen_margin_bottom: 0,
99
- component_anchor_point_y: 0,
100
- assets: "",
101
- },
102
- },
103
- selectedThemeId: "light",
104
- setSelectedThemeId: () => {},
75
+ <SafeAreaProvider
76
+ initialMetrics={{
77
+ insets: { top: 0, left: 0, right: 0, bottom: 0 },
78
+ frame: { x: 0, y: 0, width: 0, height: 0 },
105
79
  }}
106
80
  >
107
- <SafeAreaProvider
108
- initialMetrics={{
109
- insets: { top: 0, left: 0, right: 0, bottom: 0 },
110
- frame: { x: 0, y: 0, width: 0, height: 0 },
111
- }}
112
- >
113
- <Provider store={_store}>
114
- <AnalyticsProvider>{children}</AnalyticsProvider>
115
- </Provider>
116
- </SafeAreaProvider>
117
- </ThemeContext.Provider>
81
+ <Provider store={_store}>
82
+ <AnalyticsProvider>{children}</AnalyticsProvider>
83
+ </Provider>
84
+ </SafeAreaProvider>
118
85
  );
119
86
  };
120
87
 
@@ -1,57 +0,0 @@
1
- import { useState, useEffect, useCallback } from "react";
2
- import { Player } from "../player";
3
- import { usePlayer } from "../usePlayer";
4
- import { useThrottle } from "../../../functionUtils";
5
-
6
- /**
7
- *
8
- * @param listenerId - A unique identifier for the listener.
9
- * @param playerId - (Optional) The ID of the player to observe.
10
- * @returns The current playback time in seconds.
11
- */
12
- export const usePlayerCurrentTime = (
13
- listenerId: string,
14
- playerId?: string
15
- ): number | null => {
16
- const [currentTime, setCurrentTime] = useState<number | null>(null);
17
- const player: Player = usePlayer(playerId);
18
-
19
- const updateCurrentTime = useCallback(() => {
20
- if (player) {
21
- const newCurrentTime = player.getContentPosition();
22
-
23
- setCurrentTime((prevTime) =>
24
- prevTime !== newCurrentTime ? newCurrentTime : prevTime
25
- );
26
- }
27
- }, [player]);
28
-
29
- const { throttledFunction: throttledUpdate, cancel } = useThrottle(
30
- updateCurrentTime,
31
- 1000
32
- );
33
-
34
- useEffect(() => {
35
- if (player) {
36
- throttledUpdate();
37
-
38
- const listeners = {
39
- onVideoProgress: throttledUpdate,
40
- };
41
-
42
- const id = `${listenerId}_player_current_time`;
43
-
44
- player.addListener({
45
- id: id,
46
- listener: listeners,
47
- });
48
-
49
- return () => {
50
- player.removeListener(id);
51
- cancel();
52
- };
53
- }
54
- }, [player, listenerId, throttledUpdate, cancel]);
55
-
56
- return currentTime;
57
- };
@@ -1,66 +0,0 @@
1
- import { toPositiveNumberWithDefault } from "..";
2
-
3
- describe("toNumber", () => {
4
- const DEFAULT = 5;
5
-
6
- it("return number if input is positive number", () => {
7
- const inputs = [0, 1, 2, 100, 200.12, Infinity];
8
- expect.assertions(inputs.length);
9
-
10
- inputs.forEach((input) => {
11
- const output = toPositiveNumberWithDefault(DEFAULT, input);
12
- expect(output).toBe(input);
13
- });
14
- });
15
-
16
- it("return number if input is positive number as string", () => {
17
- const inputs = ["0", "1", "2", "100", "200.12"];
18
- expect.assertions(inputs.length);
19
-
20
- inputs.forEach((input) => {
21
- const output = toPositiveNumberWithDefault(DEFAULT, input);
22
- expect(output).toBe(Number(input));
23
- });
24
- });
25
-
26
- it("return default number if input is negative number", () => {
27
- const inputs = [-1, -2, -100, -Infinity];
28
- expect.assertions(inputs.length);
29
-
30
- inputs.forEach((input) => {
31
- const output = toPositiveNumberWithDefault(DEFAULT, input);
32
- expect(output).toBe(DEFAULT);
33
- });
34
- });
35
-
36
- it("return default number if input is negative number as string", () => {
37
- const inputs = ["-1", "-2", "-100"];
38
- expect.assertions(inputs.length);
39
-
40
- inputs.forEach((input) => {
41
- const output = toPositiveNumberWithDefault(DEFAULT, input);
42
- expect(output).toBe(DEFAULT);
43
- });
44
- });
45
-
46
- it("return default if input is not a number or infinite", () => {
47
- const inputs = [
48
- "vfdvf",
49
- null,
50
- undefined,
51
- NaN,
52
- "",
53
- {},
54
- { test: 1 },
55
- [],
56
- [1],
57
- ];
58
-
59
- expect.assertions(inputs.length);
60
-
61
- inputs.forEach((input) => {
62
- const output = toPositiveNumberWithDefault(DEFAULT, input);
63
- expect(output).toBe(DEFAULT);
64
- });
65
- });
66
- });
@@ -1,66 +0,0 @@
1
- import { toPositiveNumberWithDefaultZero } from "..";
2
-
3
- const DEFAULT = 0;
4
-
5
- describe("toNumber", () => {
6
- it("return number if input is positive number", () => {
7
- const inputs = [0, 1, 2, 100, 200.12];
8
- expect.assertions(inputs.length);
9
-
10
- inputs.forEach((input) => {
11
- const output = toPositiveNumberWithDefaultZero(input);
12
- expect(output).toBe(input);
13
- });
14
- });
15
-
16
- it("return number if input is positive number as string", () => {
17
- const inputs = ["0", "1", "2", "100", "200.12"];
18
- expect.assertions(inputs.length);
19
-
20
- inputs.forEach((input) => {
21
- const output = toPositiveNumberWithDefaultZero(input);
22
- expect(output).toBe(Number(input));
23
- });
24
- });
25
-
26
- it("return default number if input is negative number", () => {
27
- const inputs = [-1, -2, -100];
28
- expect.assertions(inputs.length);
29
-
30
- inputs.forEach((input) => {
31
- const output = toPositiveNumberWithDefaultZero(input);
32
- expect(output).toBe(DEFAULT);
33
- });
34
- });
35
-
36
- it("return default number if input is negative number as string", () => {
37
- const inputs = ["-1", "-2", "-100"];
38
- expect.assertions(inputs.length);
39
-
40
- inputs.forEach((input) => {
41
- const output = toPositiveNumberWithDefaultZero(input);
42
- expect(output).toBe(DEFAULT);
43
- });
44
- });
45
-
46
- it("return default if input is not a number or infinite", () => {
47
- const inputs = [
48
- "vfdvf",
49
- null,
50
- undefined,
51
- NaN,
52
- "",
53
- {},
54
- { test: 1 },
55
- [],
56
- [1],
57
- ];
58
-
59
- expect.assertions(inputs.length);
60
-
61
- inputs.forEach((input) => {
62
- const output = toPositiveNumberWithDefaultZero(input);
63
- expect(output).toBe(DEFAULT);
64
- });
65
- });
66
- });