@applicaster/zapp-react-native-utils 12.0.0-alpha.5350212300 → 12.0.0-alpha.5400461972

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.
@@ -7,6 +7,10 @@ import { sendHeaderClickEvent } from "./sendHeaderClickEvent";
7
7
  import { sendHardwareBackButtonClickEvent } from "./sendHardwareBackButtonClickEvent";
8
8
  import { sendDownloadsEvent } from "./sendDownloadsEvent";
9
9
  import { sendScreenEvent } from "./sendScreenEvent";
10
+ import {
11
+ sendSearchCanceledEvent,
12
+ sendSearchExecutedEvent,
13
+ } from "./searchEvents";
10
14
 
11
15
  export {
12
16
  sendScreenEvent,
@@ -18,4 +22,6 @@ export {
18
22
  sendHeaderClickEvent,
19
23
  sendHardwareBackButtonClickEvent,
20
24
  sendDownloadsEvent,
25
+ sendSearchCanceledEvent,
26
+ sendSearchExecutedEvent,
21
27
  };
@@ -0,0 +1,21 @@
1
+ import { log_debug } from "../logger";
2
+ import { postAnalyticEvent } from "../manager";
3
+ import { ANALYTICS_CORE_EVENTS } from "../events";
4
+
5
+ export const sendSearchCanceledEvent = (analyticsProps) => {
6
+ const eventName = ANALYTICS_CORE_EVENTS.SEARCH_CANCELED;
7
+ postAnalyticEvent(eventName, analyticsProps);
8
+
9
+ log_debug(`sendSearchCanceledEvent: send event: ${eventName}`, {
10
+ analyticsProps,
11
+ });
12
+ };
13
+
14
+ export const sendSearchExecutedEvent = (analyticsProps) => {
15
+ const eventName = ANALYTICS_CORE_EVENTS.SEARCH_EXECUTED;
16
+ postAnalyticEvent(eventName, analyticsProps);
17
+
18
+ log_debug(`sendSearchExecutedEvent: send event: ${eventName}`, {
19
+ analyticsProps,
20
+ });
21
+ };
@@ -0,0 +1,25 @@
1
+ import * as R from "ramda";
2
+ import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
3
+
4
+ export const getVideojsAnalyticPluginsConfig = async (entry: ZappEntry) => {
5
+ let videojsConfiguration = {};
6
+
7
+ const plugins = appStore.get("plugins");
8
+ const analyticPlugins = R.filter(R.propEq("type", "analytics"), plugins);
9
+
10
+ const configurations = await Promise.all(
11
+ analyticPlugins.map(async (plugin) => {
12
+ const { configuration, module } = plugin;
13
+
14
+ return module?.getPlayerConfiguration?.(configuration, entry);
15
+ })
16
+ );
17
+
18
+ configurations.forEach((analyticConfig) => {
19
+ if (typeof analyticConfig === "object" && analyticConfig !== null) {
20
+ videojsConfiguration = { ...videojsConfiguration, ...analyticConfig };
21
+ }
22
+ });
23
+
24
+ return videojsConfiguration;
25
+ };
@@ -23,10 +23,16 @@ export const TAPPING_EVENTS = {
23
23
  TAP_NAVBAR_BACK_BUTTON: "tap_navbar_back_button",
24
24
  };
25
25
 
26
+ export const SEARCH_EVENTS = {
27
+ SEARCH_EXECUTED: "search_executed",
28
+ SEARCH_CANCELED: "search_canceled",
29
+ };
30
+
26
31
  export const ANALYTICS_CORE_EVENTS = {
27
32
  ...LEGACY_EVENTS,
28
33
  ...SCREEN_VIEW_EVENTS,
29
34
  ...TAPPING_EVENTS,
35
+ ...SEARCH_EVENTS,
30
36
  };
31
37
 
32
38
  export const WEBVIEW_EVENTS = {
@@ -18,6 +18,8 @@ import {
18
18
  sendHardwareBackButtonClickEvent,
19
19
  sendDownloadsEvent,
20
20
  sendScreenEvent,
21
+ sendSearchCanceledEvent,
22
+ sendSearchExecutedEvent,
21
23
  } from "./AnalyticsEvents";
22
24
 
23
25
  import { postAnalyticEvent } from "./manager";
@@ -66,6 +68,8 @@ type AnalyticsFunctions = {
66
68
  item: ZappEntry;
67
69
  state: OfflineItemState;
68
70
  }) => void;
71
+ sendSearchCanceledEvent: (props: AnalyticsDefaultProperties) => void;
72
+ sendSearchExecutedEvent: (props: AnalyticsDefaultProperties) => void;
69
73
  };
70
74
 
71
75
  type GetAnalyticsFunctions = (
@@ -102,6 +106,8 @@ export function getAnalyticsFunctions({
102
106
  sendHardwareBackButtonClickEvent,
103
107
  sendScreenEvent,
104
108
  sendDownloadsEvent,
109
+ sendSearchCanceledEvent,
110
+ sendSearchExecutedEvent,
105
111
  };
106
112
  }
107
113
 
@@ -1,20 +1,9 @@
1
1
  import * as R from "ramda";
2
- import {
3
- isNilOrEmpty,
4
- isNotNil,
5
- } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
6
-
7
2
  import { Tree } from "./treeDataStructure/Tree";
8
3
  import { findFocusableNode, findPriorityItem } from "./treeDataStructure/Utils";
9
4
  import { subscriber } from "../../functionUtils";
10
5
  import * as FOCUS_EVENTS from "./events";
11
6
  import { coreLogger } from "../../logger";
12
- import {
13
- waitForActiveScreen,
14
- waitForContent,
15
- getContentNode,
16
- getActiveScreen,
17
- } from "./utils";
18
7
 
19
8
  const logger = coreLogger.addSubsystem("focusManager");
20
9
 
@@ -57,7 +46,7 @@ export const focusManager = (function () {
57
46
  let lastFocusedId = null;
58
47
  let initialFocusOnContent = null;
59
48
  let focusDisabled = false;
60
- let focusAutoEnabled = false;
49
+ let focusAutoEnabled = true;
61
50
  const eventHandler = subscriber();
62
51
 
63
52
  function disableAutomaticFocus() {
@@ -104,7 +93,7 @@ export const focusManager = (function () {
104
93
  !currentFocusable.isGroup &&
105
94
  currentFocusable.isMounted()
106
95
  ) {
107
- currentFocusable.blur(direction);
96
+ currentFocusable.blur(currentFocusable, direction);
108
97
  currentFocusable.hasLostFocus(getCurrentFocus(), direction);
109
98
  }
110
99
  }
@@ -230,55 +219,38 @@ export const focusManager = (function () {
230
219
  /**
231
220
  * sets the initial focus when the screen loads, or when focus is lost
232
221
  */
233
- function setInitialFocus(lastAddedParentNode?: any, fallback?: () => void) {
222
+ function setInitialFocus(lastAddedParentNode?: any) {
234
223
  const preferredFocus = findPriorityItem(
235
224
  lastAddedParentNode?.children || focusableTree.root.children
236
225
  );
237
226
 
238
227
  logger.log({ message: "setInitialFocus", data: { preferredFocus } });
239
228
 
240
- if (isNilOrEmpty(preferredFocus)) {
241
- fallback?.();
242
- return;
243
- }
244
-
245
- const focusCandidate = preferredFocus[0];
246
- const focusableItem = focusCandidate.component;
247
-
248
- const currentFocusedId = R.path(["props", "id"], getCurrentFocus());
249
- const nextFocusedId = R.path(["props", "id"], focusableItem);
250
-
251
- if (currentFocusedId === nextFocusedId) {
252
- // we are going to move focus to the same node(already focused) -> nothing to do
253
- return;
254
- }
229
+ if (preferredFocus && preferredFocus.length > 0) {
230
+ const focusCandidate = preferredFocus[0];
231
+ const focusableItem = focusCandidate.component;
232
+
233
+ if (
234
+ focusableItem &&
235
+ !focusableItem.isGroup &&
236
+ isFocusEnabled(focusableItem)
237
+ ) {
238
+ if (initialFocusOnContent) {
239
+ blur();
240
+ initialFocusOnContent = false;
241
+ }
255
242
 
256
- if (preferredFocus.length === 1 && focusableItem && focusableItem.isGroup) {
257
- // we've found only one FocusableGroup as a candidate to focus, try to use fallback
258
- fallback?.();
259
- return;
260
- }
243
+ logger.log({
244
+ message: "setInitialFocus – currentFocusNode",
245
+ data: {
246
+ focusableItem,
247
+ },
248
+ });
261
249
 
262
- if (
263
- focusableItem &&
264
- !focusableItem.isGroup &&
265
- isFocusEnabled(focusableItem)
266
- ) {
267
- if (initialFocusOnContent) {
268
- blur();
269
- initialFocusOnContent = false;
250
+ currentFocusNode = focusCandidate;
251
+ focusableItem.willReceiveFocus(focusableItem, null);
252
+ focusableItem && setFocus(focusCandidate.id, null);
270
253
  }
271
-
272
- logger.log({
273
- message: "setInitialFocus – currentFocusNode",
274
- data: {
275
- focusableItem,
276
- },
277
- });
278
-
279
- currentFocusNode = focusCandidate;
280
- focusableItem.willReceiveFocus(focusableItem, null);
281
- focusableItem && setFocus(focusCandidate.id, null);
282
254
  }
283
255
  }
284
256
 
@@ -351,8 +323,6 @@ export const focusManager = (function () {
351
323
  * @returns {React.Component} the registered component
352
324
  */
353
325
  function registerGroup(id, component) {
354
- // console.log("debug_2", "FM registerGroup", { id, component });
355
-
356
326
  focusableTree.addNode({ id, component });
357
327
 
358
328
  return component;
@@ -368,8 +338,6 @@ export const focusManager = (function () {
368
338
  * @returns {React.Component} the registered component
369
339
  */
370
340
  function registerItem(id, component) {
371
- // console.log("debug_2", "FM registerItem", { id, component });
372
-
373
341
  focusableTree.addNode({ id, component });
374
342
 
375
343
  if (!currentFocusNode && id === lastFocusedId && !id.includes("menu")) {
@@ -386,8 +354,6 @@ export const focusManager = (function () {
386
354
  * @param {String} id of the group to unregister
387
355
  */
388
356
  function unregisterGroup(id) {
389
- // console.log("debug_2", "FM unregisterGroup", { id });
390
-
391
357
  focusableTree.findAndRemoveNode(id);
392
358
  }
393
359
 
@@ -399,8 +365,6 @@ export const focusManager = (function () {
399
365
  * @param {String} id of the Focusable to unregister
400
366
  */
401
367
  function unregisterItem(id) {
402
- // console.log("debug_2", "FM unregisterItem", { id });
403
-
404
368
  focusableTree.findAndRemoveNode(id);
405
369
 
406
370
  if (currentFocusNode && currentFocusNode.id === id) {
@@ -439,8 +403,6 @@ export const focusManager = (function () {
439
403
  }
440
404
 
441
405
  function setupInitialFocus(id: string, focusOnContent?: boolean) {
442
- console.log("debug_2", "FM - setupInitialFocus", { id, focusOnContent });
443
-
444
406
  if (focusOnContent) {
445
407
  initialFocusOnContent = focusOnContent;
446
408
  } else {
@@ -448,62 +410,6 @@ export const focusManager = (function () {
448
410
  }
449
411
  }
450
412
 
451
- async function setFocusOnMenu(currentRoute: string) {
452
- console.log("debug_2", "FM - setFocusOnMenu", { currentRoute });
453
-
454
- try {
455
- await waitForActiveScreen(currentRoute, focusableTree);
456
-
457
- const navbar = R.find(
458
- (child) => R.startsWith("navbar", child.id),
459
- getActiveScreen(focusableTree).children
460
- );
461
-
462
- const selectedMenuItemId = R.find(
463
- (child) => child.component.props.selected,
464
- navbar?.children || []
465
- )?.id;
466
-
467
- if (selectedMenuItemId) {
468
- // set focus on selected menu item
469
- setFocus(selectedMenuItemId);
470
- return;
471
- }
472
-
473
- const firstMenuItemId = R.path(["children", 0, "id"], navbar);
474
-
475
- if (firstMenuItemId) {
476
- // set focus on first menu item
477
- setFocus(firstMenuItemId);
478
- }
479
- } catch (error) {
480
- // failed to put focus on top-menu => log it
481
- }
482
- }
483
-
484
- async function setFocusOnContent(currentRoute: string) {
485
- console.log("debug_2", "FM - setFocusOnContent", { currentRoute });
486
-
487
- // we need to put focus on content here
488
- // For doing it we have to wait registration of first focusable node into focusableTree
489
- // this is the temporary hack with waiting until content node starts having children
490
- try {
491
- await waitForActiveScreen(currentRoute, focusableTree);
492
- await waitForContent(focusableTree);
493
-
494
- const content = getContentNode(focusableTree);
495
-
496
- const fallback = () => {
497
- throw Error("Failed to land focus on content");
498
- };
499
-
500
- setInitialFocus(content, fallback);
501
- } catch (e) {
502
- // we've failed to put initial focus on content, put focus on menu as a last chance
503
- setFocusOnMenu(currentRoute);
504
- }
505
- }
506
-
507
413
  /**
508
414
  * moves the focus in a provided direction
509
415
  * @public
@@ -516,13 +422,6 @@ export const focusManager = (function () {
516
422
  currentFocusNode.component.willLoseFocus(currentFocusNode, direction);
517
423
  const nextFocusable = findFocusableNode(direction, currentFocusNode);
518
424
 
519
- // console.log("debug_2", "FM moveFocus", {
520
- // direction: direction?.value,
521
- // currentFocusNode,
522
- // focusableTree,
523
- // nextFocusable,
524
- // });
525
-
526
425
  if (nextFocusable?.component?.isMounted?.()) {
527
426
  const nextRect = nextFocusable.component.getRect();
528
427
 
@@ -619,7 +518,5 @@ export const focusManager = (function () {
619
518
  enableAutomaticFocus,
620
519
  getGroupRootById,
621
520
  isGroupItemFocused,
622
- setFocusOnMenu,
623
- setFocusOnContent,
624
521
  };
625
522
  })();
@@ -1,4 +1,4 @@
1
- import { allPass, pathOr, startsWith, isNil } from "ramda";
1
+ import * as R from "ramda";
2
2
  import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
3
3
 
4
4
  import { rejectItemByPath } from "../../../../objectUtils";
@@ -143,49 +143,7 @@ const hasChildren = (target) =>
143
143
 
144
144
  const hasComponent = (target) => !!target?.component;
145
145
 
146
- const hasComponentAndChildren = allPass([hasComponent, hasChildren]);
147
-
148
- const positiveOrZero = (value) => value >= 0;
149
-
150
- const excludeFromFocusSearching = pathOr(false, [
151
- "component",
152
- "props",
153
- "excludeFromFocusSearching",
154
- ]);
155
-
156
- // const isAllScreens = all(excludeFromFocusSearching);
157
-
158
- const isNavBar = (target) => startsWith("navbar", target?.id);
159
-
160
- const ignoreMenuIfMultipleTargets = (nodes) => {
161
- if (nodes.length > 1 && nodes.map((n) => n?.target?.id).includes("navbar")) {
162
- return nodes.filter((n) => !isNavBar(n?.target));
163
- }
164
-
165
- return nodes;
166
- };
167
-
168
- const toDistance = ({ target, direction, comparisonRect }) => {
169
- const componentRect = target.component?.getRect();
170
-
171
- const orientationDistance = measureDistance(
172
- direction,
173
- comparisonRect,
174
- componentRect
175
- );
176
-
177
- if (orientationDistance === -1) {
178
- // ignores offscreen targets when moving up/down
179
- return null;
180
- }
181
-
182
- const euclidDistance = measureEuclidianDistanceToCenter(
183
- comparisonRect,
184
- componentRect
185
- );
186
-
187
- return orientationDistance > 0 ? euclidDistance : orientationDistance;
188
- };
146
+ const hasComponentAndChildren = R.allPass([hasComponent, hasChildren]);
189
147
 
190
148
  /**
191
149
  * Get target in shortest distance in specified direction
@@ -215,32 +173,52 @@ export function getTargetInDirection(
215
173
 
216
174
  const distances = targets
217
175
  .filter(hasComponentAndChildren)
218
- .filter((target) => !excludeFromFocusSearching(target))
219
- .map((target) => ({
220
- distance: toDistance({ target, direction, comparisonRect }),
221
- target,
222
- }))
223
- .filter(({ distance }) => positiveOrZero(distance));
176
+ .map((target) => {
177
+ const componentRect = target.component?.getRect();
178
+
179
+ const distance = measureDistance(
180
+ direction,
181
+ comparisonRect,
182
+ componentRect
183
+ );
184
+
185
+ if (distance === -1) {
186
+ // ignores offscreen targets when moving up/down
187
+ return null;
188
+ }
224
189
 
225
- // if (isAllScreens(targets)) {
226
- // return last(targets);
227
- // }
190
+ const orientationDistance = measureDistance(
191
+ direction,
192
+ comparisonRect,
193
+ componentRect
194
+ );
195
+
196
+ const euclidDistance = measureEuclidianDistanceToCenter(
197
+ comparisonRect,
198
+ componentRect
199
+ );
200
+
201
+ return {
202
+ distance:
203
+ orientationDistance > 0 ? euclidDistance : orientationDistance,
204
+ target,
205
+ };
206
+ })
207
+ .filter((obj) => obj && obj.distance >= 0);
228
208
 
229
209
  const match = distances
230
210
  .sort((a, b) => a.distance - b.distance) // sorts the distances
231
211
  .filter(ignoreMenuIfMultipleTargets)[0]; // filters out multiple targets if necessary // gets the first element
232
212
 
233
- // console.log("debug_2", "FM getTargetInDirection", {
234
- // direction: direction?.value,
235
- // currentNode,
236
- // targetNodes,
237
- // targets,
238
- // comparisonRect,
239
- // distances,
240
- // match,
241
- // });
242
-
243
- return match?.target;
213
+ return distances && distances.length > 0 ? match.target : null;
214
+ }
215
+
216
+ function ignoreMenuIfMultipleTargets(nodes) {
217
+ if (nodes.length > 1 && nodes.map((n) => n?.target?.id).includes("navbar")) {
218
+ return nodes.filter((n) => n?.target?.id !== "navbar");
219
+ }
220
+
221
+ return nodes;
244
222
  }
245
223
 
246
224
  /**
@@ -331,36 +309,3 @@ export function hasPriorityInDirection(direction, component) {
331
309
 
332
310
  return (prioritiseFocusOn & mappedDirection) > 0;
333
311
  }
334
-
335
- export const getNodeBeforeRoot = (node) => {
336
- if (isNil(node)) {
337
- return undefined;
338
- }
339
-
340
- if (node.parent.id === "root") {
341
- return node;
342
- }
343
-
344
- return getNodeBeforeRoot(node.parent);
345
- };
346
-
347
- export const isAllowedToMoveTo = (currentNode, nextNode) => {
348
- const screenForCurrentNode = getNodeBeforeRoot(currentNode);
349
- const screenForNextNode = getNodeBeforeRoot(nextNode);
350
-
351
- return screenForCurrentNode.id === screenForNextNode.id;
352
-
353
- // console.log("debug_2", "isAllowedToMoveTo", {
354
- // nodeBeforeRoot,
355
- // });
356
-
357
- // if (nodeBeforeRoot?.id === "navbar") {
358
- // return true;
359
- // }
360
-
361
- // if (nodeBeforeRoot?.component?.props?.isActive) {
362
- // return true;
363
- // }
364
-
365
- // return false;
366
- };
@@ -4,6 +4,7 @@ import { useEffect } from "react";
4
4
  import { playerManager } from "./index";
5
5
  import { useValidatePlayerConfig } from "../../playerUtils/useValidatePlayerConfig";
6
6
  import { PlayerRole } from "./conts";
7
+ import { isAppleTV } from "@applicaster/zapp-react-native-ui-components/Helpers/Platform";
7
8
 
8
9
  // TODO: Rename to ControllerType
9
10
  export const usePlayerControllerSetup = ({
@@ -34,10 +35,14 @@ export const usePlayerControllerSetup = ({
34
35
  useValidatePlayerConfig(config);
35
36
 
36
37
  useEffect(() => {
38
+ const newConfig = isAppleTV()
39
+ ? { supports_native_controls: true, ...config }
40
+ : config;
41
+
37
42
  const newPlayerController = new ControllerType({
38
43
  player: ref,
39
44
  listener: props as any,
40
- config,
45
+ config: newConfig,
41
46
  playerId,
42
47
  entry,
43
48
  playerPluginId: pluginId,
@@ -24,7 +24,6 @@ import {
24
24
  EMPTY,
25
25
  FALLBACK,
26
26
  TRANSFORM,
27
- defaultColor,
28
27
  } from "./fixtures";
29
28
 
30
29
  describe("getKeyForLabel", () => {
@@ -395,9 +394,7 @@ describe("getColorFromData", () => {
395
394
  it("should return value directly if valid color", () => {
396
395
  const result = getColorFromData({
397
396
  data: entry,
398
- key: "background_color",
399
- getValue: getValue(componentStyle),
400
- defaultColor,
397
+ valueFromLayout: "#123456",
401
398
  });
402
399
 
403
400
  expect(result).toBe("#123456");
@@ -406,9 +403,7 @@ describe("getColorFromData", () => {
406
403
  it("should return valid rgba color name", () => {
407
404
  const result = getColorFromData({
408
405
  data: entry,
409
- key: "component_background_color",
410
- getValue: getValue(componentStyle),
411
- defaultColor,
406
+ valueFromLayout: "rgba(255, 255, 255, 0)",
412
407
  });
413
408
 
414
409
  expect(result).toBe("rgba(255, 255, 255, 0)");
@@ -417,33 +412,27 @@ describe("getColorFromData", () => {
417
412
  it("should return path value if path value is set and is valid color", () => {
418
413
  const result = getColorFromData({
419
414
  data: entry,
420
- key: VAL.colorKeyPath,
421
- getValue: getValue(componentStyle),
422
- defaultColor,
415
+ valueFromLayout: "background_color",
423
416
  });
424
417
 
425
418
  expect(result).toBe("#123456");
426
419
  });
427
420
 
428
- it("should return defaultColor if key value and path value are invalid", () => {
421
+ it("should return path value if path value is set, nested and is valid color", () => {
429
422
  const result = getColorFromData({
430
423
  data: entry,
431
- key: VAL.invalidColorKey,
432
- getValue: getValue(componentStyle),
433
- defaultColor,
424
+ valueFromLayout: "extensions.background_color",
434
425
  });
435
426
 
436
- expect(result).toBe(defaultColor);
427
+ expect(result).toBe("#123456");
437
428
  });
438
429
 
439
- it("should return defaultColor if path does not exist", () => {
430
+ it("should return valueFromLayout if path does not exist", () => {
440
431
  const result = getColorFromData({
441
432
  data: entry,
442
- key: VAL.invalidColorKeyPath,
443
- getValue: getValue(componentStyle),
444
- defaultColor,
433
+ valueFromLayout: "invalid_color",
445
434
  });
446
435
 
447
- expect(result).toBe(defaultColor);
436
+ expect(result).toBe("invalid_color");
448
437
  });
449
438
  });
@@ -447,30 +447,24 @@ export const toResizeMode = (
447
447
 
448
448
  type GetColorFromData = {
449
449
  data: Record<string, any>;
450
- key: string;
451
- getValue: Function;
452
- defaultColor: string;
450
+ valueFromLayout: string;
453
451
  };
454
452
 
455
453
  export const getColorFromData = ({
456
454
  data,
457
- key,
458
- getValue,
459
- defaultColor,
455
+ valueFromLayout,
460
456
  }: GetColorFromData): string => {
461
- const value = getValue(key);
462
-
463
457
  // Temporary hack to fix color validation when alpha is floating point number
464
458
  // https://github.com/dreamyguy/validate-color/issues/44
465
- if (validateColor(value.replace(".00", ""))) {
466
- return value;
459
+ if (validateColor(valueFromLayout.replace(".00", ""))) {
460
+ return valueFromLayout;
467
461
  }
468
462
 
469
- const pathValue = R.path(value.split("."), data);
463
+ const pathValue = R.path(valueFromLayout.split("."), data);
470
464
 
471
465
  if (pathValue && validateColor(pathValue)) {
472
466
  return pathValue;
473
467
  }
474
468
 
475
- return defaultColor;
469
+ return valueFromLayout;
476
470
  };
@@ -0,0 +1,11 @@
1
+ import dayjs from "dayjs";
2
+ import utc from "dayjs/plugin/utc";
3
+ import timezone from "dayjs/plugin/timezone";
4
+ import isoWeek from "dayjs/plugin/isoWeek";
5
+
6
+ // Extend dayjs with plugins
7
+ dayjs.extend(utc);
8
+ dayjs.extend(timezone);
9
+ dayjs.extend(isoWeek);
10
+
11
+ export { dayjs };
@@ -28,5 +28,6 @@ export const getAppDataHeaders = (screenId: string) => {
28
28
  "x-applicaster-signed-device-info-token": appData.signedDeviceInfoToken,
29
29
  "x-applicaster-device-make": appData.deviceMake,
30
30
  "x-applicaster-device-model": appData.deviceModel,
31
+ "x-applicaster-uuid": appData?.uuid,
31
32
  };
32
33
  };