@applicaster/zapp-react-native-utils 16.0.0-alpha.8443457654 → 16.0.0-alpha.8716141508

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 (104) hide show
  1. package/actionsExecutor/ActionExecutor.ts +8 -10
  2. package/actionsExecutor/ActionExecutorContext.tsx +43 -326
  3. package/actionsExecutor/actions/appRestart.ts +24 -0
  4. package/actionsExecutor/actions/confirmDialog.ts +53 -0
  5. package/actionsExecutor/actions/index.ts +30 -0
  6. package/actionsExecutor/actions/localStorageRemove.ts +27 -0
  7. package/actionsExecutor/actions/localStorageSet.ts +28 -0
  8. package/actionsExecutor/actions/localStorageToggleFlag.ts +28 -0
  9. package/actionsExecutor/actions/navigateToScreen.ts +123 -0
  10. package/actionsExecutor/actions/refreshComponent.ts +79 -0
  11. package/actionsExecutor/actions/screenSetVariable.ts +35 -0
  12. package/actionsExecutor/actions/screenToggleFlag.ts +38 -0
  13. package/actionsExecutor/actions/sendCloudEvent.ts +88 -0
  14. package/actionsExecutor/actions/sessionStorageRemove.ts +19 -0
  15. package/actionsExecutor/actions/sessionStorageSet.ts +20 -0
  16. package/actionsExecutor/actions/sessionStorageToggleFlag.ts +15 -0
  17. package/actionsExecutor/actions/showToast.ts +31 -0
  18. package/actionsExecutor/actions/switchLayout.ts +40 -0
  19. package/actionsExecutor/types.ts +59 -0
  20. package/analyticsUtils/AnalyticsEvents/sendMenuClickEvent.ts +2 -2
  21. package/analyticsUtils/PlayerAnalyticsManager.ts +11 -1
  22. package/analyticsUtils/__tests__/analyticsMapper.test.ts +35 -0
  23. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testACP_events.json +1 -1
  24. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testBlockUnlistedParams_rules.json +1 -1
  25. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testEmptyRenameKeepsName_events.json +4 -0
  26. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testEmptyRenameKeepsName_rules.json +6 -0
  27. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testEventRegex_events.json +3 -9
  28. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testIgnoreOrdering_events.json +18 -0
  29. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testIgnoreOrdering_rules.json +16 -0
  30. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexEventNoFallback_events.json +4 -0
  31. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexEventNoFallback_rules.json +6 -0
  32. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexMultiGroupRename_events.json +4 -0
  33. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexMultiGroupRename_rules.json +6 -0
  34. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexNonNamedFullMatch_events.json +4 -0
  35. package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexNonNamedFullMatch_rules.json +6 -0
  36. package/analyticsUtils/__tests__/fixtures/index.js +20 -0
  37. package/analyticsUtils/analyticsMapper.ts +4 -1
  38. package/analyticsUtils/playerAnalyticsTracker.ts +26 -3
  39. package/appUtils/contextKeysManager/__tests__/getKey/failure.test.ts +1 -1
  40. package/appUtils/contextKeysManager/__tests__/removeKey/failure.test.ts +1 -1
  41. package/appUtils/contextKeysManager/__tests__/setKey/failure/invalidKey.test.ts +4 -4
  42. package/appUtils/contextKeysManager/index.ts +1 -1
  43. package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +12 -6
  44. package/appUtils/playerManager/conts.ts +6 -0
  45. package/arrayUtils/__tests__/{anyThruthy.test.ts → anyTruthy.test.ts} +8 -0
  46. package/arrayUtils/__tests__/arrayUtils.test.ts +165 -108
  47. package/arrayUtils/__tests__/isEmptyArray.test.ts +11 -0
  48. package/arrayUtils/__tests__/isFilledArray.test.ts +12 -0
  49. package/arrayUtils/__tests__/isFirst.test.ts +17 -0
  50. package/arrayUtils/__tests__/isIndexInRange.test.ts +14 -0
  51. package/arrayUtils/__tests__/isLast.test.ts +31 -0
  52. package/arrayUtils/__tests__/makeListOf.test.ts +31 -0
  53. package/arrayUtils/__tests__/makeListOfIndexes.test.ts +20 -0
  54. package/arrayUtils/__tests__/sample.test.ts +61 -0
  55. package/arrayUtils/index.ts +57 -20
  56. package/bottomSheet/__tests__/scrollContext.test.tsx +35 -0
  57. package/bottomSheet/index.ts +17 -0
  58. package/cellUtils/index.ts +3 -5
  59. package/colorUtils/__tests__/isTransparentColor.test.ts +76 -0
  60. package/colorUtils/__tests__/isValidColor.test.ts +70 -0
  61. package/colorUtils/index.ts +50 -0
  62. package/manifestUtils/_internals/index.js +6 -0
  63. package/manifestUtils/defaultManifestConfigurations/generalContent.js +35 -0
  64. package/manifestUtils/defaultManifestConfigurations/player.js +19 -19
  65. package/manifestUtils/fieldUtils/__tests__/fieldUtils.test.js +84 -0
  66. package/manifestUtils/fieldUtils/index.js +125 -0
  67. package/manifestUtils/keys.js +9 -0
  68. package/manifestUtils/mobileAction/button/index.js +16 -0
  69. package/manifestUtils/mobileAction/container/index.js +3 -1
  70. package/manifestUtils/mobileAction/groups/defaults.js +3 -1
  71. package/manifestUtils/platformIsTV.js +1 -0
  72. package/numberUtils/__tests__/isMinusZero.test.ts +20 -0
  73. package/numberUtils/__tests__/isZero.test.ts +27 -0
  74. package/numberUtils/__tests__/requireNumber.test.ts +50 -0
  75. package/numberUtils/__tests__/toNumber.test.ts +27 -0
  76. package/numberUtils/__tests__/toNumberWithDefault.test.ts +64 -0
  77. package/numberUtils/__tests__/toNumberWithDefaultZero.test.ts +48 -0
  78. package/numberUtils/index.ts +27 -8
  79. package/package.json +2 -2
  80. package/pipesUtils/__tests__/buildUrlWithQuery.test.ts +33 -0
  81. package/pipesUtils/__tests__/withPipesEndpoint.test.tsx +56 -0
  82. package/pipesUtils/index.ts +1 -0
  83. package/pipesUtils/withPipesEndpoint.tsx +54 -0
  84. package/reactHooks/actions/index.ts +51 -1
  85. package/reactHooks/cell-click/index.ts +18 -10
  86. package/reactHooks/feed/__mocks__/useMarkPipesDataStale.ts +4 -0
  87. package/reactHooks/feed/__tests__/useInflatedUrl.test.tsx +25 -0
  88. package/reactHooks/feed/index.ts +5 -1
  89. package/reactHooks/feed/useBatchLoading.ts +9 -1
  90. package/reactHooks/feed/{usePipesCacheReset.ts → useMarkPipesDataStale.ts} +12 -4
  91. package/reactHooks/layout/index.ts +1 -1
  92. package/reactHooks/navigation/__mocks__/index.ts +4 -0
  93. package/reactHooks/navigation/__tests__/useIsScreenActive.test.ts +42 -0
  94. package/reactHooks/navigation/index.ts +1 -1
  95. package/reactHooks/navigation/useIsScreenActive.ts +29 -8
  96. package/reactHooks/state/useComponentScreenState.ts +1 -1
  97. package/reactHooks/utils/index.ts +3 -2
  98. package/riverComponetsMeasurementProvider/index.tsx +12 -8
  99. package/stringUtils/__tests__/stringUtils.test.js +42 -0
  100. package/stringUtils/index.ts +2 -2
  101. package/uiActionsRegistrator/index.ts +203 -0
  102. package/zappFrameworkUtils/__tests__/localStorageHelper.test.ts +146 -0
  103. package/zappFrameworkUtils/localStorageHelper.ts +9 -13
  104. package/reactHooks/feed/__mocks__/usePipesCacheReset.ts +0 -1
@@ -2,17 +2,11 @@
2
2
  {
3
3
  "first": {
4
4
  "name": "Screen viewed: Ads & redirects",
5
- "params": {
6
- "ignored_param": "removed_value",
7
- "kept_param": "kept_value"
8
- }
5
+ "params": {}
9
6
  },
10
7
  "second": {
11
8
  "name": "Screen Ads & redirects",
12
- "params": {
13
- "ignored_param": "removed_value",
14
- "kept_param": "kept_value"
15
- }
9
+ "params": {}
16
10
  }
17
11
  }
18
- ]
12
+ ]
@@ -0,0 +1,18 @@
1
+ [
2
+ {
3
+ "first": {
4
+ "name": "screen_view",
5
+ "params": {}
6
+ },
7
+ "second": {
8
+ "name": "page_view",
9
+ "params": {}
10
+ }
11
+ },
12
+ {
13
+ "first": {
14
+ "name": "player_presented",
15
+ "params": {}
16
+ }
17
+ }
18
+ ]
@@ -0,0 +1,16 @@
1
+ {
2
+ "rules": [
3
+ {
4
+ "event": "player_presented",
5
+ "ignore": true,
6
+ "strategy": "allowUnlisted"
7
+ },
8
+ {
9
+ "event": "screen_view",
10
+ "ignore": false,
11
+ "rename": "page_view",
12
+ "strategy": "allowUnlisted"
13
+ }
14
+ ],
15
+ "strategy": "allowUnlisted"
16
+ }
@@ -0,0 +1,4 @@
1
+ [
2
+ { "first": { "name": "my_event", "params": {} },
3
+ "second": { "name": "my_event", "params": {} } }
4
+ ]
@@ -0,0 +1,6 @@
1
+ {
2
+ "rules": [
3
+ { "event": "my_event", "ignore": false, "rename": "should_not_apply", "regex": "wont_match_.*", "strategy": "allowUnlisted" }
4
+ ],
5
+ "strategy": "allowUnlisted"
6
+ }
@@ -0,0 +1,4 @@
1
+ [
2
+ { "first": { "name": "play-video", "params": {} },
3
+ "second": { "name": "play_video", "params": {} } }
4
+ ]
@@ -0,0 +1,6 @@
1
+ {
2
+ "rules": [
3
+ { "ignore": false, "rename": "$<first>_$<second>", "regex": "(?<first>[a-z]+)-(?<second>[a-z]+)", "strategy": "allowUnlisted" }
4
+ ],
5
+ "strategy": "allowUnlisted"
6
+ }
@@ -0,0 +1,4 @@
1
+ [
2
+ { "first": { "name": "screen_view", "params": {} },
3
+ "second": { "name": "renamed", "params": {} } }
4
+ ]
@@ -0,0 +1,6 @@
1
+ {
2
+ "rules": [
3
+ { "ignore": false, "rename": "renamed", "regex": "screen_view", "strategy": "allowUnlisted" }
4
+ ],
5
+ "strategy": "allowUnlisted"
6
+ }
@@ -14,6 +14,16 @@ import blockUnlistedEventEvents from "./analytics_mapper_testBlockUnlistedEvents
14
14
  import blockUnlistedEventRules from "./analytics_mapper_testBlockUnlistedEvents_rules.json";
15
15
  import ACPEventEvents from "./analytics_mapper_testACP_events.json";
16
16
  import ACPEventRules from "./analytics_mapper_testACP_rules.json";
17
+ import emptyRenameRules from "./analytics_mapper_testEmptyRenameKeepsName_rules.json";
18
+ import emptyRenameEvents from "./analytics_mapper_testEmptyRenameKeepsName_events.json";
19
+ import ignoreOrderingRules from "./analytics_mapper_testIgnoreOrdering_rules.json";
20
+ import ignoreOrderingEvents from "./analytics_mapper_testIgnoreOrdering_events.json";
21
+ import regexEventNoFallbackRules from "./analytics_mapper_testRegexEventNoFallback_rules.json";
22
+ import regexEventNoFallbackEvents from "./analytics_mapper_testRegexEventNoFallback_events.json";
23
+ import regexMultiGroupRenameRules from "./analytics_mapper_testRegexMultiGroupRename_rules.json";
24
+ import regexMultiGroupRenameEvents from "./analytics_mapper_testRegexMultiGroupRename_events.json";
25
+ import regexNonNamedFullMatchRules from "./analytics_mapper_testRegexNonNamedFullMatch_rules.json";
26
+ import regexNonNamedFullMatchEvents from "./analytics_mapper_testRegexNonNamedFullMatch_events.json";
17
27
 
18
28
  export const fixtures = {
19
29
  renameRules,
@@ -32,4 +42,14 @@ export const fixtures = {
32
42
  blockUnlistedEventRules,
33
43
  ACPEventEvents,
34
44
  ACPEventRules,
45
+ emptyRenameRules,
46
+ emptyRenameEvents,
47
+ ignoreOrderingRules,
48
+ ignoreOrderingEvents,
49
+ regexEventNoFallbackRules,
50
+ regexEventNoFallbackEvents,
51
+ regexMultiGroupRenameRules,
52
+ regexMultiGroupRenameEvents,
53
+ regexNonNamedFullMatchRules,
54
+ regexNonNamedFullMatchEvents,
35
55
  };
@@ -76,7 +76,10 @@ class StateHolder {
76
76
  delete this.pluckedParams[prefix];
77
77
  }
78
78
 
79
- return this._cap?.[suffix];
79
+ // Stringify so values match the native iOS/Android mappers (which coerce
80
+ // analyticsCustomProperties values to strings) — keeps GA4 data consistent
81
+ // across web/LG/Samsung and native platforms.
82
+ return this._cap?.[suffix]?.toString() ?? null;
80
83
  }
81
84
 
82
85
  private async getFromLocalAndSession(
@@ -4,8 +4,14 @@ import { isTrue } from "@applicaster/zapp-react-native-utils/booleanUtils";
4
4
  import { postAnalyticEvent } from "./manager";
5
5
  import { isLive } from "../playerUtils";
6
6
  import { extensionsEvents } from "./AnalyticsEvents/helper";
7
- import { AD_EVENT, EVENT_TYPES, PLAYER_DISPLAY_STATES } from "./events";
7
+ import {
8
+ AD_EVENT,
9
+ EVENT_TYPES,
10
+ GENERAL_EVENT,
11
+ PLAYER_DISPLAY_STATES,
12
+ } from "./events";
8
13
  import { Player } from "../appUtils/playerManager/player";
14
+ import { isNil } from "@applicaster/zapp-react-native-utils/utils";
9
15
 
10
16
  export interface PlayerAnalyticsTrackerI {
11
17
  handleAnalyticEvent(
@@ -13,6 +19,8 @@ export interface PlayerAnalyticsTrackerI {
13
19
  eventData?: QuickBrickPlayer.EventData
14
20
  ): void;
15
21
  setPlayer(player: Player): void;
22
+ onPlayerPresented(): void;
23
+ onPlayerClosed(): void;
16
24
  }
17
25
 
18
26
  export class PlayerAnalyticsTracker implements PlayerAnalyticsTrackerI {
@@ -26,6 +34,15 @@ export class PlayerAnalyticsTracker implements PlayerAnalyticsTrackerI {
26
34
  this.player = player;
27
35
  }
28
36
 
37
+ onPlayerPresented() {
38
+ this.handleAnalyticEvent(GENERAL_EVENT.player_presented);
39
+ }
40
+
41
+ onPlayerClosed() {
42
+ this.handleAnalyticEvent(GENERAL_EVENT.session_end);
43
+ this.handleAnalyticEvent(GENERAL_EVENT.player_closed);
44
+ }
45
+
29
46
  isAdBreak(event: string): boolean {
30
47
  const adBreakEvents = [
31
48
  AD_EVENT.ad_break_start,
@@ -180,7 +197,8 @@ export class PlayerAnalyticsTracker implements PlayerAnalyticsTrackerI {
180
197
  this.entry?.extensions?.free || this.entry?.extensions?.isFree;
181
198
 
182
199
  const title = this.entry?.title;
183
- const streamType = isLive(this.entry) ? "live" : "vod"; // Todo: determine other types, channel, podcast, aod
200
+ const isStreamLive = isLive(this.entry);
201
+ const streamType = isStreamLive ? "live" : "vod"; // Todo: determine other types, channel, podcast, aod
184
202
 
185
203
  const currentPosition = this.getCurrentPosition(
186
204
  event,
@@ -201,6 +219,7 @@ export class PlayerAnalyticsTracker implements PlayerAnalyticsTrackerI {
201
219
  );
202
220
 
203
221
  const playerState = this.getPlayerState();
222
+ const playerType = this.player?.playerPluginId;
204
223
 
205
224
  const analyticsCustomProperties = extensionsEvents(this.entry?.extensions);
206
225
 
@@ -210,7 +229,11 @@ export class PlayerAnalyticsTracker implements PlayerAnalyticsTrackerI {
210
229
  name: title,
211
230
  media_type: mediaType,
212
231
  stream_type: streamType,
213
- duration: mediaDuration,
232
+ player_type: playerType,
233
+ // We do not pass duration for live streams anymore (it's now seekableDuration),
234
+ // but we can't mark it as optional in Analytics Mapper yet,
235
+ // so we set it to -1 for live streams
236
+ duration: isStreamLive && isNil(mediaDuration) ? -1 : mediaDuration,
214
237
  current_position: currentPosition,
215
238
  player_state: playerState,
216
239
  stream_format: contentType,
@@ -46,7 +46,7 @@ describe("Context Keys Manager - getKey", () => {
46
46
 
47
47
  expect(mockedLogger.warn).toHaveBeenCalledWith({
48
48
  message:
49
- "Provided key is not valid - expecing an object with namespace and key properties",
49
+ "Provided key is not valid - expecting an object with namespace and key properties",
50
50
  data: { key: invalidKey },
51
51
  });
52
52
 
@@ -47,7 +47,7 @@ describe("Context Keys Manager - removeKey", () => {
47
47
 
48
48
  expect(mockedLogger.warn).toHaveBeenCalledWith({
49
49
  message:
50
- "Provided key is not valid - expecing an object with namespace and key properties",
50
+ "Provided key is not valid - expecting an object with namespace and key properties",
51
51
  data: { key },
52
52
  });
53
53
 
@@ -48,7 +48,7 @@ describe("Context Keys Manager - setKey", () => {
48
48
 
49
49
  expect(mockedLogger.warn).toHaveBeenCalledWith({
50
50
  message:
51
- "Provided key is not valid - expecing an object with namespace and key properties",
51
+ "Provided key is not valid - expecting an object with namespace and key properties",
52
52
  data: { key },
53
53
  });
54
54
 
@@ -105,7 +105,7 @@ describe("Context Keys Manager - setKey", () => {
105
105
 
106
106
  expect(mockedLogger.warn).toHaveBeenCalledWith({
107
107
  message:
108
- "Provided key is not valid - expecing an object with namespace and key properties",
108
+ "Provided key is not valid - expecting an object with namespace and key properties",
109
109
  data: { key },
110
110
  });
111
111
 
@@ -162,7 +162,7 @@ describe("Context Keys Manager - setKey", () => {
162
162
 
163
163
  expect(mockedLogger.warn).toHaveBeenCalledWith({
164
164
  message:
165
- "Provided key is not valid - expecing an object with namespace and key properties",
165
+ "Provided key is not valid - expecting an object with namespace and key properties",
166
166
  data: { key },
167
167
  });
168
168
 
@@ -217,7 +217,7 @@ describe("Context Keys Manager - setKey", () => {
217
217
 
218
218
  expect(mockedLogger.warn).toHaveBeenCalledWith({
219
219
  message:
220
- "Provided key is not valid - expecing an object with namespace and key properties",
220
+ "Provided key is not valid - expecting an object with namespace and key properties",
221
221
  data: { key },
222
222
  });
223
223
 
@@ -109,7 +109,7 @@ export class ContextKeysManager {
109
109
  if (!keyIsValid(parsedKey)) {
110
110
  this._logger.warn({
111
111
  message:
112
- "Provided key is not valid - expecing an object with namespace and key properties",
112
+ "Provided key is not valid - expecting an object with namespace and key properties",
113
113
  data: { key },
114
114
  });
115
115
 
@@ -59,6 +59,7 @@ type PlayNextConfig = {
59
59
  export type PlayNextState = PlayNextConfig & {
60
60
  triggerTime: number;
61
61
  handleUserCancelPlayNext: () => void;
62
+ hidePlayNext: () => void;
62
63
  };
63
64
 
64
65
  export class OverlaysObserver {
@@ -76,7 +77,7 @@ export class OverlaysObserver {
76
77
  private chapterMarkerEvents: ChapterMarkerEvent[];
77
78
  readonly player: Player;
78
79
  private playNextConfig?: PlayNextConfig;
79
- private isCanceledByUser = false;
80
+ private isPlayNextSuppressed = false;
80
81
 
81
82
  constructor({ player }: ChapterMarkersObserverProps) {
82
83
  this.chapterSubject = new BehaviorSubject(null);
@@ -143,11 +144,15 @@ export class OverlaysObserver {
143
144
  return this.titleSummarySubject.asObservable().pipe(distinctUntilChanged());
144
145
  }
145
146
 
146
- handleUserCancelPlayNext = () => {
147
- this.isCanceledByUser = true;
147
+ hidePlayNext = () => {
148
+ this.isPlayNextSuppressed = true;
148
149
  this.playNextSubject.next(null);
149
150
  };
150
151
 
152
+ handleUserCancelPlayNext = () => {
153
+ this.hidePlayNext();
154
+ };
155
+
151
156
  preparePlayNext = async () => {
152
157
  try {
153
158
  const plugins = appStore.get("plugins");
@@ -270,7 +275,7 @@ export class OverlaysObserver {
270
275
 
271
276
  // TODO: Hack for video end, will be replaced with playlist prev/next in the future
272
277
  getPlayNextEntry = () =>
273
- !this.isCanceledByUser ? this.playNextConfig?.entry : null;
278
+ !this.isPlayNextSuppressed ? this.playNextConfig?.entry : null;
274
279
 
275
280
  prepareChapterMarkers = () => {
276
281
  const chapterMarkers: ChapterMarkerOriginal[] =
@@ -353,7 +358,7 @@ export class OverlaysObserver {
353
358
  const shouldPlayNextBeVisible = currentTime > triggerTime;
354
359
 
355
360
  if (shouldPlayNextBeVisible) {
356
- if (this.isCanceledByUser) {
361
+ if (this.isPlayNextSuppressed) {
357
362
  return;
358
363
  }
359
364
 
@@ -361,10 +366,11 @@ export class OverlaysObserver {
361
366
  ...this.playNextConfig,
362
367
  triggerTime,
363
368
  handleUserCancelPlayNext: this.handleUserCancelPlayNext,
369
+ hidePlayNext: this.hidePlayNext,
364
370
  });
365
371
  } else {
366
372
  this.playNextSubject.next(null);
367
- this.isCanceledByUser = false;
373
+ this.isPlayNextSuppressed = false;
368
374
  }
369
375
  };
370
376
 
@@ -67,3 +67,9 @@ export enum PlayerRole {
67
67
  Chromecast = "Chromecast",
68
68
  Unspecified = "Unspecified",
69
69
  }
70
+
71
+ export enum PLAYER_EVENTS {
72
+ PlayNextTriggered = "play_next_triggered",
73
+ }
74
+
75
+ export type PlayNextTriggeredEvent = { id: string };
@@ -21,4 +21,12 @@ describe("anyTruthy", () => {
21
21
  expect(anyTruthy([true])).toBe(true);
22
22
  expect(anyTruthy([false])).toBe(false);
23
23
  });
24
+
25
+ it("should return true when the first value is true", () => {
26
+ expect(anyTruthy([true, false, false])).toBe(true);
27
+ });
28
+
29
+ it("should return true when only the last value is true", () => {
30
+ expect(anyTruthy([false, false, true])).toBe(true);
31
+ });
24
32
  });