@applicaster/zapp-react-native-utils 15.0.0-rc.11 → 15.0.0-rc.110
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.
- package/README.md +0 -6
- package/actionsExecutor/ActionExecutorContext.tsx +3 -6
- package/actionsExecutor/feedDecorator.ts +6 -6
- package/adsUtils/__tests__/createVMAP.test.ts +419 -0
- package/adsUtils/index.ts +2 -2
- package/analyticsUtils/README.md +1 -1
- package/analyticsUtils/analyticsMapper.ts +10 -2
- package/appDataUtils/__tests__/urlScheme.test.ts +678 -0
- package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +0 -188
- package/appUtils/HooksManager/__tests__/hooksManager.test.js +16 -2
- package/appUtils/HooksManager/index.ts +10 -10
- package/appUtils/RiverFocusManager/{index.js → index.ts} +25 -18
- package/appUtils/accessibilityManager/__tests__/utils.test.ts +360 -0
- package/appUtils/accessibilityManager/const.ts +4 -0
- package/appUtils/accessibilityManager/hooks.ts +20 -13
- package/appUtils/accessibilityManager/index.ts +28 -1
- package/appUtils/accessibilityManager/utils.ts +59 -8
- package/appUtils/contextKeysManager/__tests__/getKeys/failure.test.ts +7 -2
- package/appUtils/contextKeysManager/__tests__/getKeys/success.test.ts +48 -0
- package/appUtils/contextKeysManager/contextResolver.ts +51 -22
- package/appUtils/contextKeysManager/index.ts +65 -10
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +4 -0
- package/appUtils/focusManager/index.ios.ts +59 -3
- package/appUtils/focusManager/treeDataStructure/Tree/__tests__/Tree.test.js +46 -0
- package/appUtils/focusManager/treeDataStructure/Tree/index.js +18 -18
- package/appUtils/focusManagerAux/utils/index.ios.ts +122 -0
- package/appUtils/focusManagerAux/utils/index.ts +21 -5
- package/appUtils/focusManagerAux/utils/utils.ios.ts +234 -0
- package/appUtils/keyCodes/keys/keys.web.ts +1 -4
- package/appUtils/orientationHelper.ts +2 -4
- package/appUtils/platform/platformUtils.ts +117 -18
- package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +94 -4
- package/appUtils/playerManager/OverlayObserver/utils.ts +32 -20
- package/appUtils/playerManager/player.ts +4 -0
- package/appUtils/playerManager/playerNative.ts +31 -17
- package/appUtils/playerManager/usePlayerState.tsx +14 -2
- package/arrayUtils/__tests__/allTruthy.test.ts +24 -0
- package/arrayUtils/__tests__/anyThruthy.test.ts +24 -0
- package/arrayUtils/index.ts +5 -0
- package/cellUtils/index.ts +32 -0
- package/cloudEventsUtils/__tests__/index.test.ts +529 -0
- package/cloudEventsUtils/index.ts +65 -1
- package/configurationUtils/__tests__/imageSrcFromMediaItem.test.ts +38 -0
- package/configurationUtils/__tests__/manifestKeyParser.test.ts +26 -26
- package/configurationUtils/index.ts +17 -11
- package/dateUtils/__tests__/dayjs.test.ts +330 -0
- package/enumUtils/__tests__/getEnumKeyByEnumValue.test.ts +207 -0
- package/errorUtils/__tests__/GeneralError.test.ts +97 -0
- package/errorUtils/__tests__/HttpStatusCode.test.ts +344 -0
- package/errorUtils/__tests__/MissingPluginError.test.ts +113 -0
- package/errorUtils/__tests__/NetworkError.test.ts +202 -0
- package/errorUtils/__tests__/getParsedResponse.test.ts +188 -0
- package/errorUtils/__tests__/invariant.test.ts +112 -0
- package/focusManager/aux/index.ts +1 -1
- package/headersUtils/__tests__/headersUtils.test.js +11 -1
- package/headersUtils/index.ts +2 -1
- package/manifestUtils/defaultManifestConfigurations/player.js +109 -11
- package/manifestUtils/keys.js +21 -0
- package/manifestUtils/platformIsTV.js +13 -0
- package/manifestUtils/sharedConfiguration/screenPicker/utils.js +1 -0
- package/manifestUtils/tvAction/container/index.js +1 -1
- package/navigationUtils/index.ts +15 -5
- package/numberUtils/__tests__/toNumber.test.ts +12 -0
- package/numberUtils/__tests__/toPositiveNumber.test.ts +165 -0
- package/numberUtils/index.ts +19 -1
- package/package.json +4 -4
- package/playerUtils/usePlayerTTS.ts +8 -3
- package/pluginUtils/index.ts +4 -0
- package/reactHooks/advertising/index.ts +2 -2
- package/reactHooks/analytics/__tests__/useSendAnalyticsOnPress.test.ts +537 -0
- package/reactHooks/app/__tests__/useAppState.test.ts +1 -1
- package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
- package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +1 -2
- package/reactHooks/cell-click/__tests__/index.test.js +1 -3
- package/reactHooks/configuration/__tests__/index.test.tsx +1 -1
- package/reactHooks/connection/__tests__/index.test.js +1 -1
- package/reactHooks/debugging/__tests__/index.test.js +4 -4
- package/reactHooks/dev/__tests__/useReRenderLog.test.ts +188 -0
- package/reactHooks/device/useIsTablet.tsx +14 -19
- package/reactHooks/device/useMemoizedIsTablet.ts +3 -3
- package/reactHooks/events/index.ts +20 -0
- package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +32 -23
- package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +19 -19
- package/reactHooks/feed/__tests__/useEntryScreenId.test.tsx +4 -1
- package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +42 -30
- package/reactHooks/feed/__tests__/{useInflatedUrl.test.ts → useInflatedUrl.test.tsx} +62 -7
- package/reactHooks/feed/index.ts +0 -2
- package/reactHooks/feed/useBatchLoading.ts +7 -1
- package/reactHooks/feed/useEntryScreenId.ts +2 -2
- package/reactHooks/feed/useInflatedUrl.ts +43 -17
- package/reactHooks/feed/usePipesCacheReset.ts +3 -1
- package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +13 -16
- package/reactHooks/hookModal/hooks/useHookModalScreenData.ts +12 -8
- package/reactHooks/index.ts +2 -0
- package/reactHooks/layout/__tests__/index.test.tsx +1 -1
- package/reactHooks/layout/__tests__/useLayoutVersion.test.tsx +1 -1
- package/reactHooks/layout/index.ts +1 -1
- package/reactHooks/layout/useDimensions/__tests__/{useDimensions.test.ts → useDimensions.test.tsx} +105 -25
- package/reactHooks/layout/useDimensions/useDimensions.ts +2 -2
- package/reactHooks/navigation/__tests__/index.test.tsx +40 -9
- package/reactHooks/navigation/index.ts +27 -11
- package/reactHooks/navigation/useRoute.ts +11 -7
- package/reactHooks/player/TVSeekControlller/TVSeekController.ts +27 -10
- package/reactHooks/player/__tests__/useAutoSeek._test.tsx +1 -1
- package/reactHooks/player/__tests__/useTapSeek._test.ts +1 -1
- package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +1 -1
- package/reactHooks/resolvers/__tests__/useComponentResolver.test.tsx +1 -1
- package/reactHooks/resolvers/useCellResolver.ts +6 -2
- package/reactHooks/resolvers/useComponentResolver.ts +8 -2
- package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +2 -2
- package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +1 -1
- package/reactHooks/screen/__tests__/useScreenData.test.tsx +1 -1
- package/reactHooks/screen/__tests__/useTargetScreenData.test.tsx +12 -4
- package/reactHooks/screen/useTargetScreenData.ts +4 -2
- package/reactHooks/state/__tests__/useComponentScreenState.test.ts +246 -0
- package/reactHooks/state/index.ts +2 -0
- package/reactHooks/state/useComponentScreenState.ts +45 -0
- package/reactHooks/state/useRefWithInitialValue.ts +10 -0
- package/reactHooks/state/useRivers.ts +1 -1
- package/reactHooks/ui/__tests__/useFadeOutWhenBlurred.test.ts +580 -0
- package/reactHooks/usePluginConfiguration.ts +2 -2
- package/reactHooks/utils/__tests__/index.test.js +1 -1
- package/rectUtils/__tests__/index.test.ts +549 -0
- package/rectUtils/index.ts +2 -2
- package/refreshUtils/RefreshCoordinator/__tests__/refreshCoordinator.test.ts +161 -0
- package/refreshUtils/RefreshCoordinator/index.ts +216 -0
- package/refreshUtils/RefreshCoordinator/utils/__tests__/getDataRefreshConfig.test.ts +104 -0
- package/refreshUtils/RefreshCoordinator/utils/index.ts +29 -0
- package/screenPickerUtils/__tests__/index.test.ts +333 -0
- package/screenPickerUtils/index.ts +5 -0
- package/screenState/__tests__/index.test.ts +1 -1
- package/searchUtils/const.ts +7 -0
- package/searchUtils/index.ts +3 -0
- package/services/storageServiceSync.web.ts +1 -1
- package/stringUtils/index.ts +1 -1
- package/testUtils/index.tsx +30 -21
- package/time/__tests__/BackgroundTimer.test.ts +156 -0
- package/time/__tests__/Timer.test.ts +236 -0
- package/typeGuards/__tests__/isString.test.ts +21 -0
- package/typeGuards/index.ts +4 -0
- package/utils/__tests__/clone.test.ts +158 -0
- package/utils/__tests__/mapAccum.test.ts +73 -0
- package/utils/__tests__/mergeRight.test.ts +48 -0
- package/utils/__tests__/path.test.ts +7 -0
- package/utils/__tests__/selectors.test.ts +124 -0
- package/utils/clone.ts +7 -0
- package/utils/index.ts +22 -1
- package/utils/mapAccum.ts +23 -0
- package/utils/mergeRight.ts +5 -0
- package/utils/path.ts +6 -3
- package/utils/pathOr.ts +5 -1
- package/utils/selectors.ts +46 -0
- package/zappFrameworkUtils/HookCallback/callbackNavigationAction.ts +49 -12
- package/zappFrameworkUtils/HookCallback/hookCallbackManifestExtensions.config.js +1 -1
- package/reactHooks/componentsMap/index.ts +0 -55
- package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +0 -75
- package/reactHooks/feed/useFeedRefresh.tsx +0 -65
package/utils/index.ts
CHANGED
|
@@ -16,8 +16,13 @@ export { endsWith } from "./endsWith";
|
|
|
16
16
|
|
|
17
17
|
export { take } from "./take";
|
|
18
18
|
|
|
19
|
+
export { mapAccum } from "./mapAccum";
|
|
20
|
+
|
|
21
|
+
export { mergeRight } from "./mergeRight";
|
|
22
|
+
|
|
23
|
+
export { clone } from "./clone";
|
|
24
|
+
|
|
19
25
|
export {
|
|
20
|
-
cloneDeep as clone,
|
|
21
26
|
flatten,
|
|
22
27
|
drop,
|
|
23
28
|
size,
|
|
@@ -34,4 +39,20 @@ export {
|
|
|
34
39
|
last,
|
|
35
40
|
toLower,
|
|
36
41
|
isEqual as equals,
|
|
42
|
+
uniq,
|
|
43
|
+
uniqWith,
|
|
44
|
+
flowRight as compose,
|
|
45
|
+
partial,
|
|
46
|
+
clamp,
|
|
47
|
+
reverse,
|
|
48
|
+
takeRight,
|
|
49
|
+
fromPairs,
|
|
50
|
+
sortBy,
|
|
51
|
+
merge,
|
|
52
|
+
values,
|
|
53
|
+
head,
|
|
54
|
+
findIndex,
|
|
55
|
+
set,
|
|
56
|
+
compact,
|
|
57
|
+
identity,
|
|
37
58
|
} from "lodash";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { curry } from "lodash";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A native reimplementation of Ramda's mapAccum.
|
|
5
|
+
*
|
|
6
|
+
* @template A, B, C
|
|
7
|
+
* @param {(acc: A, value: B) => [A, C]} fn - Function returning [newAcc, mappedValue]
|
|
8
|
+
* @param {A} acc - Initial accumulator
|
|
9
|
+
* @param {B[]} list - List to process
|
|
10
|
+
* @returns {[A, C[]]} - Tuple of [final accumulator, mapped array]
|
|
11
|
+
*/
|
|
12
|
+
export const mapAccum = curry((fn, acc, list) => {
|
|
13
|
+
const result = [];
|
|
14
|
+
let currentAcc = acc;
|
|
15
|
+
|
|
16
|
+
for (let i = 0; i < list.length; i++) {
|
|
17
|
+
const [nextAcc, mapped] = fn(currentAcc, list[i]);
|
|
18
|
+
currentAcc = nextAcc;
|
|
19
|
+
result.push(mapped);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return [currentAcc, result];
|
|
23
|
+
});
|
package/utils/path.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { pathOr } from "./pathOr";
|
|
2
2
|
|
|
3
|
-
export const path =
|
|
4
|
-
|
|
3
|
+
export const path = <T = any>(
|
|
4
|
+
route: (string | number) | (string | number)[],
|
|
5
|
+
record: any
|
|
6
|
+
) => {
|
|
7
|
+
return pathOr<T>(undefined, route, record);
|
|
5
8
|
};
|
package/utils/pathOr.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { get } from "lodash";
|
|
2
2
|
|
|
3
|
-
export const pathOr =
|
|
3
|
+
export const pathOr = <T = any>(
|
|
4
|
+
defaultValue: T,
|
|
5
|
+
path: (number | string) | (number | string)[],
|
|
6
|
+
record: any
|
|
7
|
+
): T => {
|
|
4
8
|
return get(record, path, defaultValue);
|
|
5
9
|
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { get } from "lodash";
|
|
2
|
+
|
|
3
|
+
export type Selector<T> = (state: any) => T;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a selector for filtering plugins by path
|
|
7
|
+
* @param path - Path to check in plugin. Can be a dot notation string or array
|
|
8
|
+
* @returns A selector function that returns matching plugins
|
|
9
|
+
*/
|
|
10
|
+
export const createPluginsByPathSelector = (
|
|
11
|
+
path: string | string[]
|
|
12
|
+
): Selector<any[]> => {
|
|
13
|
+
return (state: any) => {
|
|
14
|
+
const plugins = state.plugins || [];
|
|
15
|
+
|
|
16
|
+
return plugins.filter((plugin: any) => get(plugin, path));
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Creates a selector for filtering plugins by module path
|
|
22
|
+
* @param modulePath - Module path to check in plugin (e.g., "urlScheme", "player")
|
|
23
|
+
* @returns A selector function that returns plugins with specified module
|
|
24
|
+
*/
|
|
25
|
+
export const createPluginsByModuleSelector = (
|
|
26
|
+
modulePath: string
|
|
27
|
+
): Selector<any[]> => {
|
|
28
|
+
return createPluginsByPathSelector(["module", modulePath]);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Creates a selector that combines multiple plugin selectors
|
|
33
|
+
* @param selectors - Array of plugin selectors to combine
|
|
34
|
+
* @returns A selector function that returns plugins matching all conditions
|
|
35
|
+
*/
|
|
36
|
+
export const combinePluginSelectors = (
|
|
37
|
+
...selectors: Selector<any[]>[]
|
|
38
|
+
): Selector<any[]> => {
|
|
39
|
+
return (state: any) => {
|
|
40
|
+
return selectors.reduce((filtered, selector) => {
|
|
41
|
+
const selected = selector(state);
|
|
42
|
+
|
|
43
|
+
return filtered.filter((plugin) => selected.includes(plugin));
|
|
44
|
+
}, state.plugins || []);
|
|
45
|
+
};
|
|
46
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useNavigation, useRivers, useScreenContext } from "../../reactHooks";
|
|
2
2
|
import { createLogger } from "../../logger";
|
|
3
|
-
import { useCallback, useMemo } from "react";
|
|
3
|
+
import { useCallback, useMemo, useRef, useEffect } from "react";
|
|
4
4
|
|
|
5
5
|
export enum NavigationCallbackOptions {
|
|
6
6
|
DEFAULT = "default",
|
|
@@ -17,6 +17,7 @@ export enum ResultType {
|
|
|
17
17
|
export type CallbackResult = hookCallbackArgs & {
|
|
18
18
|
options?: {
|
|
19
19
|
resultType?: ResultType;
|
|
20
|
+
navigator?: QuickBrickAppNavigator;
|
|
20
21
|
};
|
|
21
22
|
};
|
|
22
23
|
|
|
@@ -45,7 +46,7 @@ const legacyMappingKeys = {
|
|
|
45
46
|
actionType: "login_completion_action",
|
|
46
47
|
targetScreen: "navigate_to_login_screen",
|
|
47
48
|
},
|
|
48
|
-
"quick-brick-user-account-ui-component": {
|
|
49
|
+
"quick-brick-user-account-ui-component.login": {
|
|
49
50
|
actionType: "callbackAction",
|
|
50
51
|
},
|
|
51
52
|
"quick-brick-login-multi-login-providers.login": {
|
|
@@ -56,9 +57,23 @@ const legacyMappingKeys = {
|
|
|
56
57
|
actionType: "logout_completion_action",
|
|
57
58
|
targetScreen: "navigate_to_logout_screen",
|
|
58
59
|
},
|
|
60
|
+
"quick-brick-storefront": {
|
|
61
|
+
actionType: "purchase_completion_action",
|
|
62
|
+
targetScreen: "navigate_to_screen_after_purchase",
|
|
63
|
+
},
|
|
64
|
+
"zapp_login_plugin_oauth_tv_2_0.login": {
|
|
65
|
+
actionType: "login_completion_action",
|
|
66
|
+
targetScreen: "navigate_to_login_screen",
|
|
67
|
+
},
|
|
68
|
+
"zapp_login_plugin_oauth_tv_2_0.logout": {
|
|
69
|
+
actionType: "logout_completion_action",
|
|
70
|
+
targetScreen: "navigate_to_logout_screen",
|
|
71
|
+
},
|
|
59
72
|
};
|
|
60
73
|
|
|
61
|
-
const NAV_ACTIONS =
|
|
74
|
+
const NAV_ACTIONS = (
|
|
75
|
+
Object.values(NavigationCallbackOptions) as string[]
|
|
76
|
+
).filter((value) => value !== NavigationCallbackOptions.DEFAULT);
|
|
62
77
|
|
|
63
78
|
const isNavAction = (v: unknown): v is NavigationCallbackOptions =>
|
|
64
79
|
typeof v === "string" && NAV_ACTIONS.includes(v);
|
|
@@ -69,7 +84,8 @@ export const getNavigationKeys = (
|
|
|
69
84
|
): NavKeys => {
|
|
70
85
|
const general = (item?.general ?? {}) as General;
|
|
71
86
|
|
|
72
|
-
const pluginIdentifier =
|
|
87
|
+
const pluginIdentifier =
|
|
88
|
+
(item as any).identifier ?? item?.type ?? item?.component_type ?? "";
|
|
73
89
|
|
|
74
90
|
const legacy =
|
|
75
91
|
legacyMappingKeys[`${pluginIdentifier}.${resultType}`] ??
|
|
@@ -121,6 +137,12 @@ export const useCallbackNavigationAction = (
|
|
|
121
137
|
const rivers = useRivers();
|
|
122
138
|
const screenContext = useScreenContext();
|
|
123
139
|
|
|
140
|
+
const navigationRef = useRef(navigation);
|
|
141
|
+
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
navigationRef.current = navigation;
|
|
144
|
+
}, [navigation]);
|
|
145
|
+
|
|
124
146
|
const overrideCallbackFromComponent = useMemo(() => {
|
|
125
147
|
log_verbose(`${LogPrefix}: overridden callbackAction by component`);
|
|
126
148
|
|
|
@@ -154,20 +176,35 @@ export const useCallbackNavigationAction = (
|
|
|
154
176
|
return;
|
|
155
177
|
}
|
|
156
178
|
|
|
157
|
-
|
|
179
|
+
let data = getNavigationKeys(item, args.options?.resultType ?? null);
|
|
158
180
|
|
|
159
181
|
if (!data) {
|
|
160
|
-
hookCallback
|
|
182
|
+
const isScreen = !hookCallback;
|
|
161
183
|
|
|
162
|
-
|
|
184
|
+
if (isScreen && args.options?.resultType === ResultType.login) {
|
|
185
|
+
log_debug(
|
|
186
|
+
`${LogPrefix} no navigation data found, applying GO BACK for login screen`
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
data = {
|
|
190
|
+
action: NavigationCallbackOptions.GO_BACK,
|
|
191
|
+
targetScreenId: null,
|
|
192
|
+
};
|
|
193
|
+
} else {
|
|
194
|
+
hookCallback?.(args);
|
|
195
|
+
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
163
198
|
}
|
|
164
199
|
|
|
165
200
|
hookCallback?.({ ...args, success: false, cancelled: true });
|
|
201
|
+
const currentNavigation = navigationRef.current;
|
|
166
202
|
|
|
167
203
|
switch (data.action) {
|
|
168
204
|
case NavigationCallbackOptions.GO_BACK: {
|
|
169
|
-
if (
|
|
170
|
-
|
|
205
|
+
if (currentNavigation.canGoBack()) {
|
|
206
|
+
currentNavigation.goBack();
|
|
207
|
+
|
|
171
208
|
log_info(`${LogPrefix} performing 'GO BACK' action`);
|
|
172
209
|
} else {
|
|
173
210
|
log_info(`${LogPrefix} cannot perform 'GO BACK' action — ignoring`);
|
|
@@ -177,7 +214,7 @@ export const useCallbackNavigationAction = (
|
|
|
177
214
|
}
|
|
178
215
|
|
|
179
216
|
case NavigationCallbackOptions.GO_HOME: {
|
|
180
|
-
|
|
217
|
+
currentNavigation.goHome();
|
|
181
218
|
log_info(`${LogPrefix} performing 'GO HOME' action`);
|
|
182
219
|
break;
|
|
183
220
|
}
|
|
@@ -193,7 +230,7 @@ export const useCallbackNavigationAction = (
|
|
|
193
230
|
const screen = rivers[screenId];
|
|
194
231
|
|
|
195
232
|
if (screen) {
|
|
196
|
-
|
|
233
|
+
currentNavigation.replace(screen);
|
|
197
234
|
|
|
198
235
|
log_info(
|
|
199
236
|
`${LogPrefix} performing 'GO TO SCREEN' action to screen: ${screenId}`
|
|
@@ -210,7 +247,7 @@ export const useCallbackNavigationAction = (
|
|
|
210
247
|
}
|
|
211
248
|
}
|
|
212
249
|
},
|
|
213
|
-
[item,
|
|
250
|
+
[item, rivers]
|
|
214
251
|
);
|
|
215
252
|
|
|
216
253
|
return overrideCallbackFromComponent || callbackAction;
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
const layoutReducer = (state, { payload }) => {
|
|
4
|
-
return state.map((item, index, _state) => ({
|
|
5
|
-
height: index === payload.index ? payload.height : item.height,
|
|
6
|
-
y:
|
|
7
|
-
index > 0
|
|
8
|
-
? _state.slice(0, index).reduce((acc, value) => acc + value.height, 0)
|
|
9
|
-
: 0,
|
|
10
|
-
}));
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export const useComponentsLayout = (count, onFinishLoadingVisible) => {
|
|
14
|
-
const [itemsLayout, dispatchItemLayout] = React.useReducer(
|
|
15
|
-
layoutReducer,
|
|
16
|
-
Array.from({ length: count }, () => ({ height: 0, y: 0 }))
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
const notified = React.useRef(false);
|
|
20
|
-
const [listHeight, setListHeight] = React.useState<number>(0);
|
|
21
|
-
|
|
22
|
-
const onItemLayout = React.useCallback(
|
|
23
|
-
(index) => (event) => {
|
|
24
|
-
const { height } = event.nativeEvent.layout;
|
|
25
|
-
dispatchItemLayout({ payload: { index, height } });
|
|
26
|
-
},
|
|
27
|
-
[]
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
const onListLayout = React.useCallback((event) => {
|
|
31
|
-
const { height } = event.nativeEvent.layout;
|
|
32
|
-
setListHeight(height);
|
|
33
|
-
}, []);
|
|
34
|
-
|
|
35
|
-
React.useEffect(() => {
|
|
36
|
-
if (!notified.current) {
|
|
37
|
-
const finishLoadingVisible = !!itemsLayout.find(
|
|
38
|
-
(item) => item.y > listHeight
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
if (finishLoadingVisible) {
|
|
42
|
-
notified.current = true;
|
|
43
|
-
onFinishLoadingVisible?.();
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}, [itemsLayout, listHeight]);
|
|
47
|
-
|
|
48
|
-
return React.useMemo(
|
|
49
|
-
() => ({
|
|
50
|
-
onItemLayout,
|
|
51
|
-
onListLayout,
|
|
52
|
-
}),
|
|
53
|
-
[]
|
|
54
|
-
);
|
|
55
|
-
};
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { renderHook } from "@testing-library/react-hooks";
|
|
2
|
-
|
|
3
|
-
jest.useFakeTimers();
|
|
4
|
-
|
|
5
|
-
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
|
|
6
|
-
useIsScreenActive: () => true,
|
|
7
|
-
}));
|
|
8
|
-
|
|
9
|
-
const { useFeedRefresh, feedRefreshLogger } = require("..");
|
|
10
|
-
|
|
11
|
-
describe("useFeedRefresh", () => {
|
|
12
|
-
const reloadData = jest.fn();
|
|
13
|
-
|
|
14
|
-
const component = {
|
|
15
|
-
id: "foo",
|
|
16
|
-
rules: { enable_data_refreshing: true, refreshing_interval: 61 },
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
it("Calls reloadData after passed time lapses", () => {
|
|
20
|
-
renderHook(() => useFeedRefresh({ reloadData, component }));
|
|
21
|
-
|
|
22
|
-
expect(reloadData).not.toBeCalled();
|
|
23
|
-
jest.runOnlyPendingTimers();
|
|
24
|
-
expect(reloadData).toBeCalled();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it("Logs warning message if refresh time set below minimum value", () => {
|
|
28
|
-
const loggerSpy = jest.spyOn(feedRefreshLogger, "warning");
|
|
29
|
-
|
|
30
|
-
renderHook(() =>
|
|
31
|
-
useFeedRefresh({
|
|
32
|
-
reloadData,
|
|
33
|
-
component: {
|
|
34
|
-
...component,
|
|
35
|
-
rules: { enable_data_refreshing: true, refreshing_interval: 2 },
|
|
36
|
-
},
|
|
37
|
-
})
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
expect(loggerSpy).toBeCalled();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it("Calls reloadData on a Component that had a timer setup and was re-mounted", () => {
|
|
44
|
-
reloadData.mockReset();
|
|
45
|
-
|
|
46
|
-
// it is not called before rendering hook"
|
|
47
|
-
expect(reloadData).not.toBeCalled();
|
|
48
|
-
|
|
49
|
-
// it is not called when rendering new component (Not previously rendered)
|
|
50
|
-
renderHook(() =>
|
|
51
|
-
useFeedRefresh({ reloadData, component: { ...component, id: "bar" } })
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
expect(reloadData).not.toBeCalled();
|
|
55
|
-
|
|
56
|
-
// it is called when rendering previously rendered component",
|
|
57
|
-
renderHook(() => useFeedRefresh({ reloadData, component }));
|
|
58
|
-
expect(reloadData).toBeCalled();
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it("Doesn't refresh data when enable_data_refreshing if false", () => {
|
|
62
|
-
reloadData.mockReset();
|
|
63
|
-
|
|
64
|
-
renderHook(() =>
|
|
65
|
-
useFeedRefresh({
|
|
66
|
-
reloadData,
|
|
67
|
-
component: { ...component, rules: { enable_data_refreshing: false } },
|
|
68
|
-
})
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
jest.runOnlyPendingTimers();
|
|
72
|
-
|
|
73
|
-
expect(reloadData).not.toBeCalled();
|
|
74
|
-
});
|
|
75
|
-
});
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { path, max } from "ramda";
|
|
3
|
-
import { isTrue } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
4
|
-
import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
5
|
-
import { useIsScreenActive } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
6
|
-
|
|
7
|
-
import { reactHooksLogger } from "../logger";
|
|
8
|
-
import { ReloadDataFunction } from "./useFeedLoader";
|
|
9
|
-
|
|
10
|
-
export const feedRefreshLogger = reactHooksLogger.addSubsystem("feed-refresh");
|
|
11
|
-
|
|
12
|
-
type Props = {
|
|
13
|
-
reloadData?: ReloadDataFunction;
|
|
14
|
-
component: ZappUIComponent;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const previousTimersMap = {};
|
|
18
|
-
const minimumRefreshingInterval = 5;
|
|
19
|
-
const defaultRefreshInterval = 60;
|
|
20
|
-
|
|
21
|
-
export const useFeedRefresh = ({ reloadData, component }: Props): void => {
|
|
22
|
-
const isDataRefreshingEnabled = isTrue(
|
|
23
|
-
path(["rules", "enable_data_refreshing"], component)
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
const refreshing_interval = toNumberWithDefault(
|
|
27
|
-
defaultRefreshInterval,
|
|
28
|
-
component?.rules?.refreshing_interval
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
const refreshingIntervalInMilliseconds =
|
|
32
|
-
max(refreshing_interval, minimumRefreshingInterval) * 1000;
|
|
33
|
-
|
|
34
|
-
const isScreenActive = useIsScreenActive();
|
|
35
|
-
|
|
36
|
-
React.useEffect(() => {
|
|
37
|
-
if (isDataRefreshingEnabled && refreshing_interval && isScreenActive) {
|
|
38
|
-
if (refreshing_interval < minimumRefreshingInterval) {
|
|
39
|
-
feedRefreshLogger.warning({
|
|
40
|
-
message: `You set your feed refresh interval to ${refreshing_interval} when minimum value is ${minimumRefreshingInterval}seconds.Your feed will refresh after ${minimumRefreshingInterval}seconds.`,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (!reloadData || typeof reloadData !== "function") {
|
|
45
|
-
feedRefreshLogger.warning({
|
|
46
|
-
message:
|
|
47
|
-
"reloadData function is undefined, feed refresh feature won't work properly",
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (previousTimersMap[component?.id]) {
|
|
52
|
-
reloadData?.();
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const refreshInterval = setInterval(() => {
|
|
56
|
-
reloadData?.();
|
|
57
|
-
}, refreshingIntervalInMilliseconds);
|
|
58
|
-
|
|
59
|
-
return () => {
|
|
60
|
-
previousTimersMap[component?.id] = true;
|
|
61
|
-
clearInterval(refreshInterval);
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
}, [reloadData, isScreenActive]);
|
|
65
|
-
};
|