@applicaster/zapp-react-native-utils 14.0.0-alpha.3471443312 → 14.0.0-alpha.3514550494

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 (68) 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/AnalyticsEvents/helper.ts +1 -1
  7. package/analyticsUtils/AnalyticsEvents/sendHeaderClickEvent.ts +1 -1
  8. package/analyticsUtils/AnalyticsEvents/sendMenuClickEvent.ts +2 -1
  9. package/analyticsUtils/__tests__/analyticsUtils.test.js +0 -11
  10. package/analyticsUtils/index.tsx +3 -4
  11. package/analyticsUtils/manager.ts +1 -1
  12. package/appUtils/HooksManager/Hook.ts +4 -4
  13. package/appUtils/HooksManager/index.ts +11 -1
  14. package/appUtils/accessibilityManager/const.ts +13 -0
  15. package/appUtils/accessibilityManager/hooks.ts +35 -1
  16. package/appUtils/accessibilityManager/index.ts +150 -29
  17. package/appUtils/accessibilityManager/utils.ts +24 -0
  18. package/appUtils/contextKeysManager/contextResolver.ts +42 -1
  19. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +5 -0
  20. package/appUtils/focusManager/__tests__/focusManager.test.js +1 -1
  21. package/appUtils/focusManager/index.ios.ts +10 -0
  22. package/appUtils/focusManager/index.ts +82 -11
  23. package/appUtils/focusManager/treeDataStructure/Tree/index.js +1 -1
  24. package/appUtils/focusManagerAux/utils/index.ts +106 -3
  25. package/appUtils/platform/platformUtils.ts +31 -1
  26. package/arrayUtils/index.ts +1 -1
  27. package/componentsUtils/__tests__/isTabsScreen.test.ts +38 -0
  28. package/componentsUtils/index.ts +4 -1
  29. package/configurationUtils/__tests__/manifestKeyParser.test.ts +546 -0
  30. package/configurationUtils/manifestKeyParser.ts +57 -32
  31. package/index.d.ts +0 -9
  32. package/manifestUtils/defaultManifestConfigurations/player.js +16 -2
  33. package/package.json +2 -3
  34. package/playerUtils/PlayerTTS/PlayerTTS.ts +359 -0
  35. package/playerUtils/PlayerTTS/index.ts +1 -0
  36. package/playerUtils/index.ts +51 -0
  37. package/playerUtils/usePlayerTTS.ts +21 -0
  38. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +12 -13
  39. package/reactHooks/cell-click/__tests__/index.test.js +3 -0
  40. package/reactHooks/cell-click/index.ts +8 -1
  41. package/reactHooks/debugging/__tests__/index.test.js +0 -1
  42. package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +47 -90
  43. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +71 -31
  44. package/reactHooks/feed/index.ts +2 -0
  45. package/reactHooks/feed/useBatchLoading.ts +14 -9
  46. package/reactHooks/feed/useFeedLoader.tsx +36 -38
  47. package/reactHooks/feed/useLoadPipesDataDispatch.ts +57 -0
  48. package/reactHooks/flatList/useSequentialRenderItem.tsx +3 -3
  49. package/reactHooks/layout/isTablet/index.ts +7 -3
  50. package/reactHooks/navigation/index.ts +7 -5
  51. package/reactHooks/navigation/useRoute.ts +7 -2
  52. package/reactHooks/navigation/useScreenStateStore.ts +8 -0
  53. package/reactHooks/state/index.ts +1 -1
  54. package/reactHooks/state/useHomeRiver.ts +4 -2
  55. package/screenPickerUtils/index.ts +7 -0
  56. package/storage/ScreenSingleValueProvider.ts +204 -0
  57. package/storage/ScreenStateMultiSelectProvider.ts +293 -0
  58. package/storage/StorageMultiSelectProvider.ts +192 -0
  59. package/storage/StorageSingleSelectProvider.ts +108 -0
  60. package/testUtils/index.tsx +7 -8
  61. package/time/BackgroundTimer.ts +1 -1
  62. package/utils/__tests__/find.test.ts +36 -0
  63. package/utils/__tests__/pathOr.test.ts +37 -0
  64. package/utils/__tests__/startsWith.test.ts +30 -0
  65. package/utils/find.ts +3 -0
  66. package/utils/index.ts +7 -0
  67. package/utils/pathOr.ts +5 -0
  68. package/utils/startsWith.ts +9 -0
@@ -208,7 +208,7 @@ function getPlayerConfiguration({ platform, version }) {
208
208
  {
209
209
  key: "accessibility_forward_label",
210
210
  label: "Accessibility forward label",
211
- initial_value: "Forward button",
211
+ initial_value: "Fast forward button",
212
212
  label_tooltip: "Label for forward button accessibility",
213
213
  type: "text_input",
214
214
  },
@@ -292,7 +292,7 @@ function getPlayerConfiguration({ platform, version }) {
292
292
  {
293
293
  key: "accessibility_back_label",
294
294
  label: "Accessibility back label",
295
- initial_value: "Back button",
295
+ initial_value: "Exit player button",
296
296
  label_tooltip: "Label for back button accessibility",
297
297
  type: "text_input",
298
298
  },
@@ -317,6 +317,20 @@ function getPlayerConfiguration({ platform, version }) {
317
317
  label_tooltip: "Hint for fullscreen button accessibility",
318
318
  type: "text_input",
319
319
  },
320
+ {
321
+ key: "accessibility_skip_intro_label",
322
+ label: "Accessibility skip intro label",
323
+ initial_value: "Skip intro - button",
324
+ label_tooltip: "Label for skip intro button accessibility",
325
+ type: "text_input",
326
+ },
327
+ {
328
+ key: "accessibility_skip_intro_hint",
329
+ label: "Accessibility skip intro hint",
330
+ initial_value: "Press to skip intro",
331
+ label_tooltip: "Hint for skip intro button accessibility",
332
+ type: "text_input",
333
+ },
320
334
  ],
321
335
  };
322
336
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "14.0.0-alpha.3471443312",
3
+ "version": "14.0.0-alpha.3514550494",
4
4
  "description": "Applicaster Zapp React Native utilities package",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "homepage": "https://github.com/applicaster/quickbrick#readme",
29
29
  "dependencies": {
30
- "@applicaster/applicaster-types": "14.0.0-alpha.3471443312",
30
+ "@applicaster/applicaster-types": "14.0.0-alpha.3514550494",
31
31
  "buffer": "^5.2.1",
32
32
  "camelize": "^1.0.0",
33
33
  "dayjs": "^1.11.10",
@@ -38,7 +38,6 @@
38
38
  "peerDependencies": {
39
39
  "@applicaster/zapp-pipes-v2-client": "*",
40
40
  "@react-native-community/netinfo": "*",
41
- "immer": "*",
42
41
  "react": "*",
43
42
  "react-native": "*",
44
43
  "uglify-js": "*",
@@ -0,0 +1,359 @@
1
+ import uuidv4 from "uuid/v4";
2
+ import { AccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager";
3
+ import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
4
+ import { Player } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/player";
5
+
6
+ const { log_debug, log_error } = createLogger({
7
+ subsystem: "Player",
8
+ category: "PlayerTTS",
9
+ });
10
+
11
+ enum SEEK_DIRECTION {
12
+ FORWARD = "forward",
13
+ REWIND = "back",
14
+ }
15
+
16
+ const hasPrerollAds = (entry: ZappEntry): boolean => {
17
+ const videoAds = entry?.extensions?.video_ads;
18
+
19
+ if (!videoAds) {
20
+ return false;
21
+ }
22
+
23
+ // If it's a string (VMAP URL), assume it might have preroll
24
+ if (typeof videoAds === "string") {
25
+ return true;
26
+ }
27
+
28
+ // If it's an array, check for preroll offset
29
+ if (Array.isArray(videoAds)) {
30
+ return videoAds.some(
31
+ (ad: ZappVideoAdExtension) => ad.offset === "preroll" || ad.offset === 0
32
+ );
33
+ }
34
+
35
+ return false;
36
+ };
37
+
38
+ export class PlayerTTS {
39
+ private player: Player;
40
+ private accessibilityManager: AccessibilityManager;
41
+ private seekStartPosition: number | null = null;
42
+ private isSeeking: boolean = false;
43
+ private listenerId: string;
44
+ private isInitialPlayerOpen: boolean = true;
45
+ private isPrerollActive: boolean = false;
46
+ private hasPrerollAds: boolean = false; // Track if preroll ads are expected
47
+
48
+ constructor(player: Player, accessibilityManager: AccessibilityManager) {
49
+ this.player = player;
50
+ this.accessibilityManager = accessibilityManager;
51
+ this.listenerId = `player-tts-${uuidv4()}`;
52
+ this.hasPrerollAds = hasPrerollAds(player.entry);
53
+
54
+ log_debug("PlayerTTS initialized", {
55
+ hasPrerollAds: this.hasPrerollAds,
56
+ listenerId: this.listenerId,
57
+ entryTitle: player.entry.title,
58
+ });
59
+ }
60
+
61
+ private numberToWords(num: number): string {
62
+ const ones = [
63
+ "",
64
+ "one",
65
+ "two",
66
+ "three",
67
+ "four",
68
+ "five",
69
+ "six",
70
+ "seven",
71
+ "eight",
72
+ "nine",
73
+ "ten",
74
+ "eleven",
75
+ "twelve",
76
+ "thirteen",
77
+ "fourteen",
78
+ "fifteen",
79
+ "sixteen",
80
+ "seventeen",
81
+ "eighteen",
82
+ "nineteen",
83
+ ];
84
+
85
+ const tens = [
86
+ "",
87
+ "",
88
+ "twenty",
89
+ "thirty",
90
+ "forty",
91
+ "fifty",
92
+ "sixty",
93
+ "seventy",
94
+ "eighty",
95
+ "ninety",
96
+ ];
97
+
98
+ if (num === 0) return "zero";
99
+ if (num < 20) return ones[num];
100
+
101
+ const ten = Math.floor(num / 10);
102
+ const one = num % 10;
103
+
104
+ return one === 0 ? tens[ten] : `${tens[ten]} ${ones[one]}`;
105
+ }
106
+
107
+ private secondsToTime(
108
+ seconds: number,
109
+ format: "natural" | "standard" = "natural"
110
+ ): string {
111
+ if (seconds < 0) return format === "natural" ? "zero" : "0";
112
+
113
+ const minutes = Math.floor(seconds / 60);
114
+ const remainingSeconds = Math.floor(seconds % 60);
115
+
116
+ if (format === "standard") {
117
+ const parts = [];
118
+
119
+ if (minutes > 0) {
120
+ parts.push(`${minutes} minute${minutes !== 1 ? "s" : ""}`);
121
+ }
122
+
123
+ if (remainingSeconds > 0) {
124
+ parts.push(
125
+ `${remainingSeconds} second${remainingSeconds !== 1 ? "s" : ""}`
126
+ );
127
+ }
128
+
129
+ return parts.length > 0 ? parts.join(" ") : "0";
130
+ } else {
131
+ if (minutes === 0) {
132
+ if (remainingSeconds === 0) return "zero";
133
+
134
+ if (remainingSeconds < 10) {
135
+ return `zero o ${this.numberToWords(remainingSeconds)}`;
136
+ }
137
+
138
+ return `zero ${this.numberToWords(remainingSeconds)}`;
139
+ }
140
+
141
+ if (remainingSeconds === 0) {
142
+ return `${this.numberToWords(minutes)}`;
143
+ }
144
+
145
+ if (remainingSeconds < 10) {
146
+ return `${this.numberToWords(minutes)} o ${this.numberToWords(remainingSeconds)}`;
147
+ }
148
+
149
+ return `${this.numberToWords(minutes)} ${this.numberToWords(remainingSeconds)}`;
150
+ }
151
+ }
152
+
153
+ private announcePause = () => {
154
+ if (!this.isSeeking) {
155
+ this.accessibilityManager.addHeading(
156
+ `Paused - ${this.secondsToTime(this.player.playerState.contentPosition, "standard")}`
157
+ );
158
+ }
159
+ };
160
+
161
+ private announceContentStart(
162
+ options: {
163
+ currentTime?: number;
164
+ duration?: number;
165
+ useReadText?: boolean;
166
+ } = {}
167
+ ): void {
168
+ const { currentTime, duration, useReadText = false } = options;
169
+ const state = this.player.playerState;
170
+
171
+ const timeRemaining =
172
+ (duration || state?.contentDuration || 0) -
173
+ (currentTime || state?.contentPosition || 0);
174
+
175
+ const title = (this.player.entry.title as string) || "";
176
+ const summary = (this.player.entry.summary as string) || "";
177
+
178
+ log_debug("Announcing content start", {
179
+ title,
180
+ currentTime: currentTime || state?.contentPosition || 0,
181
+ duration: duration || state?.contentDuration || 0,
182
+ timeRemaining,
183
+ useReadText,
184
+ });
185
+
186
+ this.accessibilityManager.addHeading(`Playing - ${title}`);
187
+ if (summary) this.accessibilityManager.addHeading(summary);
188
+
189
+ this.accessibilityManager.addHeading(
190
+ `Playing from ${this.secondsToTime(currentTime || state?.contentPosition || 0, "standard")}`
191
+ );
192
+
193
+ const remainingText = `${this.secondsToTime(Math.max(0, Math.floor(timeRemaining)), "standard")} remaining.`;
194
+
195
+ if (useReadText) {
196
+ this.accessibilityManager.readText({ text: remainingText });
197
+ } else {
198
+ this.accessibilityManager.addHeading(remainingText);
199
+ }
200
+
201
+ this.accessibilityManager.setInitialPlayerAnnouncementReady();
202
+ this.isInitialPlayerOpen = false;
203
+ }
204
+
205
+ private announceBufferComplete = (event: any) => {
206
+ // If preroll ads are expected, wait for them to finish before announcing content
207
+ if (this.hasPrerollAds && this.isInitialPlayerOpen) {
208
+ log_debug("Waiting for preroll ads to finish", {
209
+ hasPrerollAds: this.hasPrerollAds,
210
+ isInitialPlayerOpen: this.isInitialPlayerOpen,
211
+ });
212
+
213
+ return;
214
+ }
215
+
216
+ // Gate content announcement until preroll finishes
217
+ if (this.isInitialPlayerOpen && !this.isPrerollActive) {
218
+ log_debug("Buffer complete - announcing content", {
219
+ currentTime: event.currentTime,
220
+ duration: event.duration,
221
+ isPrerollActive: this.isPrerollActive,
222
+ });
223
+
224
+ this.announceContentStart({
225
+ currentTime: event.currentTime,
226
+ duration: event.duration,
227
+ });
228
+ }
229
+ };
230
+
231
+ private announceResume = () => {
232
+ if (!this.isSeeking && !this.isInitialPlayerOpen) {
233
+ log_debug("Player resumed", {
234
+ contentPosition: this.player.playerState.contentPosition,
235
+ isSeeking: this.isSeeking,
236
+ isInitialPlayerOpen: this.isInitialPlayerOpen,
237
+ });
238
+
239
+ this.accessibilityManager.addHeading(
240
+ `Playing - ${this.secondsToTime(this.player.playerState.contentPosition, "standard")}`
241
+ );
242
+ }
243
+ };
244
+
245
+ private handleVideoProgress = (event: any) => {
246
+ if (event.currentTime > 0) {
247
+ this.seekStartPosition = event.currentTime;
248
+ }
249
+ };
250
+
251
+ private handleSeekComplete = (event: any) => {
252
+ if (this.seekStartPosition !== null) {
253
+ const seekDirection =
254
+ event.currentTime > this.seekStartPosition
255
+ ? SEEK_DIRECTION.FORWARD
256
+ : SEEK_DIRECTION.REWIND;
257
+
258
+ const seekAmount = Math.round(
259
+ Math.abs(event.currentTime - this.seekStartPosition)
260
+ );
261
+
262
+ log_debug("Seek completed", {
263
+ seekDirection,
264
+ seekAmount,
265
+ fromPosition: this.seekStartPosition,
266
+ toPosition: event.currentTime,
267
+ });
268
+
269
+ this.accessibilityManager.readText({
270
+ text: `Skipped ${seekDirection} ${this.secondsToTime(seekAmount, "standard")}`,
271
+ });
272
+
273
+ this.seekStartPosition = event.currentTime;
274
+ }
275
+
276
+ this.isSeeking = false;
277
+ };
278
+
279
+ private handleSeekStart = () => {
280
+ log_debug("Seek started");
281
+ this.isSeeking = true;
282
+ };
283
+
284
+ private handlePlayerClose = () => {
285
+ log_debug("Player closed - resetting state");
286
+ this.isInitialPlayerOpen = true;
287
+ this.accessibilityManager.resetInitialPlayerAnnouncementReady();
288
+ };
289
+
290
+ private announceAdBegin = (event: any) => {
291
+ this.isPrerollActive = true;
292
+
293
+ log_debug("Ad started", {
294
+ adDuration: event?.ad?.data?.duration,
295
+ isPrerollActive: this.isPrerollActive,
296
+ });
297
+
298
+ if (event?.ad?.data?.duration) {
299
+ this.accessibilityManager.readText({
300
+ text: `Sponsored. Ends in ${this.secondsToTime(event.ad.data.duration, "standard")}`,
301
+ });
302
+ }
303
+ };
304
+
305
+ private handleAdEnd = (_event: any) => {
306
+ this.isPrerollActive = false;
307
+
308
+ log_debug("Ad ended", {
309
+ isPrerollActive: this.isPrerollActive,
310
+ isInitialPlayerOpen: this.isInitialPlayerOpen,
311
+ });
312
+
313
+ // If initial entry still pending, trigger content announcement using latest player state
314
+ if (this.isInitialPlayerOpen) {
315
+ this.announceContentStart({ useReadText: true });
316
+ }
317
+ };
318
+
319
+ public init(): () => void {
320
+ if (!this.player) {
321
+ log_error("Failed to initialize PlayerTTS - no player provided");
322
+
323
+ return () => {};
324
+ }
325
+
326
+ log_debug("Initializing PlayerTTS listeners", {
327
+ listenerId: this.listenerId,
328
+ });
329
+
330
+ return this.player.addListener({
331
+ id: this.listenerId,
332
+ listener: {
333
+ onBufferComplete: this.announceBufferComplete,
334
+ onPlayerResume: this.announceResume,
335
+ onPlayerPause: this.announcePause,
336
+ onVideoProgress: this.handleVideoProgress,
337
+ onPlayerSeekStart: this.handleSeekStart,
338
+ onPlayerSeekComplete: this.handleSeekComplete,
339
+ onPlayerClose: this.handlePlayerClose,
340
+ onAdBegin: this.announceAdBegin,
341
+ onAdEnd: this.handleAdEnd,
342
+ onAdBreakEnd: this.handleAdEnd,
343
+ },
344
+ });
345
+ }
346
+
347
+ public destroy(): void {
348
+ log_debug("Destroying PlayerTTS", {
349
+ listenerId: this.listenerId,
350
+ });
351
+
352
+ if (this.player) {
353
+ this.player.removeListener(this.listenerId);
354
+ }
355
+
356
+ this.seekStartPosition = null;
357
+ this.handlePlayerClose();
358
+ }
359
+ }
@@ -0,0 +1 @@
1
+ export { PlayerTTS } from "./PlayerTTS";
@@ -5,6 +5,7 @@ import { isFilledArray } from "@applicaster/zapp-react-native-utils/arrayUtils";
5
5
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
6
6
 
7
7
  import { getBoolFromConfigValue } from "../configurationUtils";
8
+ import { Dimensions } from "react-native";
8
9
 
9
10
  export { getPlayerActionButtons } from "./getPlayerActionButtons";
10
11
 
@@ -97,3 +98,53 @@ export const isAudioItem = (item: Option<ZappEntry>) => {
97
98
  export const isInlineTV = (screenData) => {
98
99
  return isTV() && isFilledArray(screenData?.ui_components);
99
100
  };
101
+
102
+ const isPercentage = (value: string | number): boolean => {
103
+ if (typeof value === "string") {
104
+ return value.includes("%");
105
+ }
106
+
107
+ return false;
108
+ };
109
+
110
+ const getPercentageOf = (percent: string, value: number) => {
111
+ const percentageValue = parseFloat(percent.replace("%", ""));
112
+
113
+ if (isNaN(percentageValue)) {
114
+ return value;
115
+ }
116
+
117
+ return (value * percentageValue) / 100;
118
+ };
119
+
120
+ type DimensionsT = {
121
+ width: number | string;
122
+ height: number | string | undefined;
123
+ aspectRatio?: number;
124
+ };
125
+
126
+ export const getTabletWidth = (
127
+ tablet_landscape_sidebar_width,
128
+ dimensions: DimensionsT
129
+ ) => {
130
+ const { width: SCREEN_WIDTH } = Dimensions.get("screen");
131
+
132
+ const { width } = dimensions;
133
+ let widthValue = Number(width);
134
+
135
+ if (isPercentage(width)) {
136
+ widthValue = getPercentageOf(width.toString(), SCREEN_WIDTH);
137
+ }
138
+
139
+ const sidebarWidth = Number(tablet_landscape_sidebar_width?.replace("%", ""));
140
+
141
+ if (tablet_landscape_sidebar_width?.includes("%")) {
142
+ return widthValue * (1 - sidebarWidth / 100);
143
+ }
144
+
145
+ if (Number.isNaN(sidebarWidth)) {
146
+ return widthValue * 0.65;
147
+ }
148
+
149
+ return widthValue - sidebarWidth;
150
+ };
@@ -0,0 +1,21 @@
1
+ import * as React from "react";
2
+ import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
3
+ import { useAccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
4
+ import { PlayerTTS } from "@applicaster/zapp-react-native-utils/playerUtils/PlayerTTS";
5
+
6
+ export const usePlayerTTS = () => {
7
+ const player = usePlayer();
8
+ const accessibilityManager = useAccessibilityManager({});
9
+
10
+ React.useEffect(() => {
11
+ if (player && accessibilityManager) {
12
+ const playerTTS = new PlayerTTS(player, accessibilityManager);
13
+ const unsubscribe = playerTTS.init();
14
+
15
+ return () => {
16
+ unsubscribe();
17
+ playerTTS.destroy();
18
+ };
19
+ }
20
+ }, [player, accessibilityManager]);
21
+ };
@@ -1,25 +1,27 @@
1
1
  import React from "react";
2
2
 
3
- import { act, renderHook } from "@testing-library/react-hooks";
3
+ import { renderHook } from "@testing-library/react-hooks";
4
+ import { act, waitFor } from "@testing-library/react-native";
4
5
  import { Provider } from "react-redux";
5
6
  import configureStore from "redux-mock-store";
7
+ import { useTrackedView } from "../useTrackedView";
6
8
 
7
9
  const mockUpdateComponentsPositions = jest.fn();
8
10
 
9
11
  jest.mock(
10
12
  "@applicaster/zapp-react-native-ui-components/Contexts/ScreenTrackedViewPositionsContext",
11
13
  () => ({
12
- useScreenTrackedViewPositionsContext: jest.fn().mockReturnValue({
14
+ useScreenTrackedViewPositionsContext: jest.fn(() => ({
13
15
  updateComponentsPositions: mockUpdateComponentsPositions,
14
16
  value: {
15
17
  "123": { componentId: "123", centerX: 0.4, centerY: 0.5 },
16
18
  "124": { componentId: "124", centerX: 0.2, centerY: 0.3 },
17
19
  },
18
- }),
20
+ })),
19
21
  })
20
22
  );
21
23
 
22
- jest.useFakeTimers({ legacyFakeTimers: true });
24
+ jest.useFakeTimers();
23
25
 
24
26
  jest.mock(
25
27
  "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation"
@@ -34,10 +36,8 @@ const Wrapper = ({ children }: { children: React.ReactChild }) => (
34
36
  <Provider store={store}>{children}</Provider>
35
37
  );
36
38
 
37
- const { useTrackedView } = require("../useTrackedView");
38
-
39
39
  describe("useTrackCurrentAutoScrollingElement", () => {
40
- it("should update position for selected component - onViewportEnter", () => {
40
+ it("should update position for selected component - onViewportEnter", async () => {
41
41
  const { result } = renderHook(() => useTrackedView("123"), {
42
42
  wrapper: Wrapper,
43
43
  });
@@ -48,14 +48,13 @@ describe("useTrackCurrentAutoScrollingElement", () => {
48
48
  rect: { left: 1, right: 1, top: 1, bottom: 1 },
49
49
  };
50
50
 
51
- act(async () => {
52
- await result.current.onPositionUpdated(mockRect);
51
+ act(() => {
52
+ result.current.onPositionUpdated(mockRect);
53
53
  });
54
54
 
55
- // Fast-forward until all timers have been executed
56
- jest.runAllTimers();
57
-
58
- expect(result.current.inViewPort).toBe(true);
55
+ await waitFor(() => {
56
+ expect(result.current.inViewPort).toBe(true);
57
+ });
59
58
 
60
59
  expect(mockUpdateComponentsPositions).toHaveBeenCalledWith(
61
60
  "123",
@@ -26,6 +26,9 @@ jest.mock("@applicaster/zapp-react-native-utils/analyticsUtils/", () => ({
26
26
  }));
27
27
 
28
28
  jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen", () => ({
29
+ ...jest.requireActual(
30
+ "@applicaster/zapp-react-native-utils/reactHooks/screen"
31
+ ),
29
32
  useTargetScreenData: jest.fn(() => ({})),
30
33
  useCurrentScreenData: jest.fn(() => ({})),
31
34
  }));
@@ -16,7 +16,8 @@ import { ActionExecutorContext } from "@applicaster/zapp-react-native-utils/acti
16
16
  import { isFunction, noop } from "../../functionUtils";
17
17
  import { useSendAnalyticsOnPress } from "../analytics";
18
18
  import { logOnPress, warnEmptyContentType } from "./helpers";
19
- import { useCurrentScreenData } from "../screen";
19
+ import { useCurrentScreenData, useScreenContext } from "../screen";
20
+ import { useScreenStateStore } from "../navigation/useScreenStateStore";
20
21
 
21
22
  /**
22
23
  * If onCellTap is defined execute the function and
@@ -42,10 +43,12 @@ export const useCellClick = ({
42
43
  }: Props): onPressReturnFn => {
43
44
  const { push, currentRoute } = useNavigation();
44
45
  const { pathname } = useRoute();
46
+ const screenStateStore = useScreenStateStore();
45
47
 
46
48
  const onCellTap: Option<Function> = React.useContext(CellTapContext);
47
49
  const actionExecutor = React.useContext(ActionExecutorContext);
48
50
  const screenData = useCurrentScreenData();
51
+ const screenState = useScreenContext()?.options;
49
52
 
50
53
  const cellSelectable = toBooleanWithDefaultTrue(
51
54
  component?.rules?.component_cells_selectable
@@ -83,6 +86,9 @@ export const useCellClick = ({
83
86
  await actionExecutor?.handleEntryActions(selectedItem, {
84
87
  component,
85
88
  screenData,
89
+ screenState,
90
+ screenRoute: pathname,
91
+ screenStateStore,
86
92
  });
87
93
  }
88
94
 
@@ -117,6 +123,7 @@ export const useCellClick = ({
117
123
  push,
118
124
  sendAnalyticsOnPress,
119
125
  screenData,
126
+ screenState,
120
127
  ]
121
128
  );
122
129
 
@@ -12,7 +12,6 @@ describe("Debug utils", () => {
12
12
  // Clear the timers object
13
13
  Object.keys(timers).forEach((key) => delete timers[key]);
14
14
 
15
- // Mock performance.now()
16
15
  // eslint-disable-next-line no-undef
17
16
  performanceNowMock = jest.spyOn(performance, "now");
18
17
  performanceNowMock.mockReturnValue(0); // Initial value