@applicaster/zapp-react-dom-app 14.0.0-rc.8 → 15.0.0-rc.1

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.
@@ -0,0 +1,160 @@
1
+ import React from "react";
2
+ import { render } from "@testing-library/react-native";
3
+ import { withBackToTopActionHOC } from "../withBackToTopAction";
4
+
5
+ // Mock focusManager and hook
6
+ jest.mock("@applicaster/zapp-react-native-utils/appUtils", () => ({
7
+ focusManager: {
8
+ isFocusOnMenu: jest.fn(),
9
+ isFocusOnContent: jest.fn(),
10
+ isTabsScreenContentFocused: jest.fn(),
11
+ },
12
+ }));
13
+
14
+ jest.mock("../hooks", () => ({
15
+ useCurrentScreenIsHome: jest.fn(),
16
+ useCurrentScreenIsRoot: jest.fn(),
17
+ useCurrentScreenIsTabs: jest.fn(),
18
+ }));
19
+
20
+ import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils";
21
+ import {
22
+ useCurrentScreenIsHome,
23
+ useCurrentScreenIsRoot,
24
+ useCurrentScreenIsTabs,
25
+ } from "../hooks";
26
+
27
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks", () => ({
28
+ useNavigation: jest.fn(),
29
+ }));
30
+
31
+ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
32
+
33
+ describe("withBackToTopActionHOC", () => {
34
+ let receivedProps: any;
35
+
36
+ const BaseComponent = (props) => {
37
+ receivedProps = props; // capture injected props
38
+
39
+ return <></>;
40
+ };
41
+
42
+ const Wrapped = withBackToTopActionHOC(BaseComponent);
43
+
44
+ beforeEach(() => {
45
+ jest.clearAllMocks();
46
+ });
47
+
48
+ it("returns PLATFORM_BACK when on root screen, and startup hooks", () => {
49
+ expect.assertions(1);
50
+
51
+ (useCurrentScreenIsRoot as jest.Mock).mockReturnValue(true);
52
+
53
+ (useNavigation as jest.Mock).mockReturnValue({
54
+ startUpHooks: ["some_startup_hook"],
55
+ });
56
+
57
+ render(<Wrapped />);
58
+
59
+ expect(receivedProps.backToTopAction()).toBe("PLATFORM_BACK");
60
+ });
61
+
62
+ it("returns PLATFORM_BACK when on root screen, focus on menu, and is home", () => {
63
+ expect.assertions(1);
64
+
65
+ (useCurrentScreenIsRoot as jest.Mock).mockReturnValue(true);
66
+ (useCurrentScreenIsHome as jest.Mock).mockReturnValue(true);
67
+ (useCurrentScreenIsTabs as jest.Mock).mockReturnValue(false);
68
+
69
+ (useNavigation as jest.Mock).mockReturnValue({
70
+ startUpHooks: [],
71
+ });
72
+
73
+ (focusManager.isFocusOnMenu as jest.Mock).mockReturnValue(true);
74
+ (focusManager.isFocusOnContent as jest.Mock).mockReturnValue(false);
75
+
76
+ render(<Wrapped />);
77
+
78
+ expect(receivedProps.backToTopAction()).toBe("PLATFORM_BACK");
79
+ });
80
+
81
+ it("returns GO_HOME when on root screen, focus on menu, and not home", () => {
82
+ expect.assertions(1);
83
+
84
+ (useCurrentScreenIsRoot as jest.Mock).mockReturnValue(true);
85
+ (useCurrentScreenIsHome as jest.Mock).mockReturnValue(false);
86
+ (useCurrentScreenIsTabs as jest.Mock).mockReturnValue(false);
87
+
88
+ (useNavigation as jest.Mock).mockReturnValue({
89
+ startUpHooks: [],
90
+ });
91
+
92
+ (focusManager.isFocusOnMenu as jest.Mock).mockReturnValue(true);
93
+ (focusManager.isFocusOnContent as jest.Mock).mockReturnValue(false);
94
+
95
+ render(<Wrapped />);
96
+ expect(receivedProps.backToTopAction()).toBe("GO_HOME");
97
+ });
98
+
99
+ it("returns FOCUS_ON_SELECTED_TOP_MENU_ITEM when on root screen and focus on content without tabs_screen", () => {
100
+ (useCurrentScreenIsRoot as jest.Mock).mockReturnValue(true);
101
+ (useCurrentScreenIsHome as jest.Mock).mockReturnValue(false);
102
+ (useCurrentScreenIsTabs as jest.Mock).mockReturnValue(false);
103
+
104
+ (useNavigation as jest.Mock).mockReturnValue({
105
+ startUpHooks: [],
106
+ });
107
+
108
+ (focusManager.isFocusOnMenu as jest.Mock).mockReturnValue(false);
109
+ (focusManager.isFocusOnContent as jest.Mock).mockReturnValue(true);
110
+
111
+ render(<Wrapped />);
112
+
113
+ expect(receivedProps.backToTopAction()).toBe(
114
+ "FOCUS_ON_SELECTED_TOP_MENU_ITEM"
115
+ );
116
+ });
117
+
118
+ it("returns FOCUS_ON_SELECTED_TAB_ITEM when on root screen and focus on content with tabs_screen", () => {
119
+ (useCurrentScreenIsRoot as jest.Mock).mockReturnValue(true);
120
+ (useCurrentScreenIsHome as jest.Mock).mockReturnValue(false);
121
+ (useCurrentScreenIsTabs as jest.Mock).mockReturnValue(true);
122
+
123
+ (useNavigation as jest.Mock).mockReturnValue({
124
+ startUpHooks: [],
125
+ });
126
+
127
+ (focusManager.isFocusOnMenu as jest.Mock).mockReturnValue(false);
128
+ (focusManager.isFocusOnContent as jest.Mock).mockReturnValue(true);
129
+
130
+ (focusManager.isTabsScreenContentFocused as jest.Mock).mockReturnValue(
131
+ true
132
+ );
133
+
134
+ render(<Wrapped />);
135
+
136
+ expect(receivedProps.backToTopAction()).toBe("FOCUS_ON_SELECTED_TAB_ITEM");
137
+ });
138
+
139
+ it("returns GO_BACK in default case", () => {
140
+ expect.assertions(1);
141
+
142
+ (useCurrentScreenIsRoot as jest.Mock).mockReturnValue(false);
143
+ (useCurrentScreenIsHome as jest.Mock).mockReturnValue(false);
144
+ (useCurrentScreenIsTabs as jest.Mock).mockReturnValue(false);
145
+
146
+ (useNavigation as jest.Mock).mockReturnValue({
147
+ startUpHooks: [],
148
+ });
149
+
150
+ (focusManager.isFocusOnMenu as jest.Mock).mockReturnValue(false);
151
+ (focusManager.isFocusOnContent as jest.Mock).mockReturnValue(false);
152
+
153
+ (focusManager.isTabsScreenContentFocused as jest.Mock).mockReturnValue(
154
+ false
155
+ );
156
+
157
+ render(<Wrapped />);
158
+ expect(receivedProps.backToTopAction()).toBe("GO_BACK");
159
+ });
160
+ });
@@ -0,0 +1,34 @@
1
+ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
2
+ import {
3
+ useHomeRiver,
4
+ useRivers,
5
+ } from "@applicaster/zapp-react-native-utils/reactHooks/state";
6
+ import { last } from "@applicaster/zapp-react-native-utils/utils";
7
+
8
+ export const useCurrentScreenIsHome = (): boolean => {
9
+ const navigator = useNavigation();
10
+ const homeRiver = useHomeRiver();
11
+
12
+ const homePath = `/river/${homeRiver.id}`;
13
+
14
+ return homePath === navigator.currentRoute;
15
+ };
16
+
17
+ export const useCurrentScreenIsRoot = (): boolean => {
18
+ const { mainStack = [] } = useNavigation();
19
+
20
+ // root screen is the bottom(first pushed, deepest) element of the stack
21
+ return mainStack.length <= 1;
22
+ };
23
+
24
+ export const useCurrentScreenIsTabs = (): boolean => {
25
+ const navigator = useNavigation();
26
+
27
+ const riverId = last(navigator.currentRoute.split("/"));
28
+
29
+ const rivers = useRivers();
30
+
31
+ const river = rivers[riverId];
32
+
33
+ return river?.type === "tabs_screen";
34
+ };
@@ -0,0 +1,4 @@
1
+ export {
2
+ withBackToTopActionHOC,
3
+ type BackToTopAction,
4
+ } from "./withBackToTopAction";
@@ -0,0 +1,76 @@
1
+ import * as React from "react";
2
+ import { isFilledArray } from "@applicaster/zapp-react-native-utils/arrayUtils";
3
+ import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils";
4
+
5
+ import { useSubscriberFor } from "@applicaster/zapp-react-native-utils/reactHooks/useSubscriberFor";
6
+ import { QBUIComponentEvents } from "@applicaster/zapp-react-native-ui-components/events";
7
+
8
+ import {
9
+ useCurrentScreenIsHome,
10
+ useCurrentScreenIsRoot,
11
+ useCurrentScreenIsTabs,
12
+ } from "./hooks";
13
+ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
14
+
15
+ export type BACK_TO_TOP_ACTION =
16
+ | "PLATFORM_BACK"
17
+ | "GO_HOME"
18
+ | "GO_BACK"
19
+ | "FOCUS_ON_SELECTED_TOP_MENU_ITEM"
20
+ | "FOCUS_ON_SELECTED_TAB_ITEM";
21
+
22
+ export type BackToTopAction = () => BACK_TO_TOP_ACTION;
23
+
24
+ export function withBackToTopActionHOC(Component) {
25
+ return function WrappedComponent(props) {
26
+ const isHome = useCurrentScreenIsHome();
27
+ const isRoot = useCurrentScreenIsRoot();
28
+ const isTabsScreen = useCurrentScreenIsTabs();
29
+
30
+ const navigator = useNavigation();
31
+
32
+ const isStartUpHook = isFilledArray(navigator.startUpHooks);
33
+
34
+ const emitFocusOnSelectedTab = useSubscriberFor(
35
+ QBUIComponentEvents.focusOnSelectedTab
36
+ );
37
+
38
+ const emitFocusOnSelectedTopMenuItem = useSubscriberFor(
39
+ QBUIComponentEvents.focusOnSelectedTopMenuItem
40
+ );
41
+
42
+ const backToTopAction = React.useCallback((): BACK_TO_TOP_ACTION => {
43
+ if (isRoot && isStartUpHook) {
44
+ return "PLATFORM_BACK";
45
+ }
46
+
47
+ if (isRoot && focusManager.isFocusOnMenu() && isHome) {
48
+ return "PLATFORM_BACK";
49
+ }
50
+
51
+ if (isRoot && focusManager.isFocusOnMenu() && !isHome) {
52
+ return "GO_HOME";
53
+ }
54
+
55
+ if (isRoot && isTabsScreen && focusManager.isTabsScreenContentFocused()) {
56
+ return "FOCUS_ON_SELECTED_TAB_ITEM";
57
+ }
58
+
59
+ if (isRoot && focusManager.isFocusOnContent()) {
60
+ return "FOCUS_ON_SELECTED_TOP_MENU_ITEM";
61
+ }
62
+
63
+ // default
64
+ return "GO_BACK";
65
+ }, [isHome, isRoot, isTabsScreen, isStartUpHook]);
66
+
67
+ return (
68
+ <Component
69
+ {...props}
70
+ backToTopAction={backToTopAction}
71
+ emitFocusOnSelectedTab={emitFocusOnSelectedTab}
72
+ emitFocusOnSelectedTopMenuItem={emitFocusOnSelectedTopMenuItem}
73
+ />
74
+ );
75
+ };
76
+ }
@@ -1,19 +1,22 @@
1
1
  import * as React from "react";
2
2
  import * as R from "ramda";
3
3
 
4
- import { connectToStore } from "@applicaster/zapp-react-native-redux";
4
+ import { connectToStore } from "@applicaster/zapp-react-native-redux/utils/connectToStore";
5
5
 
6
6
  import {
7
7
  QUICK_BRICK_EVENTS,
8
8
  sendQuickBrickEvent,
9
9
  } from "@applicaster/zapp-react-native-bridge/QuickBrick";
10
10
 
11
+ import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
12
+
11
13
  import {
12
14
  debounce,
13
15
  noop,
14
16
  } from "@applicaster/zapp-react-native-utils/functionUtils";
15
17
 
16
18
  import {
19
+ AccessibilityManager,
17
20
  ARROW_KEYS,
18
21
  focusManager,
19
22
  keyCode,
@@ -50,17 +53,20 @@ import {
50
53
  import { OnScreenKeyboard } from "@applicaster/zapp-react-dom-ui-components/Components/OnScreenKeyboard";
51
54
  import { KeyboardLongPressManager } from "@applicaster/zapp-react-dom-ui-components/Utils/KeyboardLongPressManager";
52
55
  import { KeyInputHandler } from "@applicaster/zapp-react-native-utils/appUtils/keyInputHandler/KeyInputHandler";
56
+ import { getHomeRiver } from "@applicaster/zapp-react-native-utils/reactHooks/state";
57
+ import { withBackToTopActionHOC, BackToTopAction } from "./hoc";
53
58
 
54
59
  const { withXray } = getXray();
55
60
  const globalAny: any = global;
56
61
 
57
- const { log_debug, log_warning } = createLogger({
62
+ const { log_debug, log_warning, log_info } = createLogger({
58
63
  category: "InteractionManager",
59
64
  subsystem: "zapp-react-dom-app",
60
65
  });
61
66
 
62
67
  const shouldUseOnScreenKeyboard = () =>
63
- isVizioPlatform() || window.applicaster.useOnScreenKeyboard;
68
+ isVizioPlatform() ||
69
+ toBooleanWithDefaultFalse(window?.applicaster?.useOnScreenKeyboard);
64
70
 
65
71
  type Props = {
66
72
  displayState: string;
@@ -70,6 +76,9 @@ type Props = {
70
76
  rivers: {};
71
77
  xray: XRayContext;
72
78
  confirmDialog: typeof confirmationDialogStore;
79
+ backToTopAction: BackToTopAction;
80
+ emitFocusOnSelectedTopMenuItem: Callback;
81
+ emitFocusOnSelectedTab: Callback;
73
82
  };
74
83
 
75
84
  interface State {
@@ -80,8 +89,8 @@ interface State {
80
89
 
81
90
  type KeyCode = { code: string; keyCode: number | string };
82
91
 
83
- export const alertConfirmationMesage =
84
- "Are you sure you want to exit application?";
92
+ const VIDEO_PLAYER_CONTROLS_NAVIGATION_MESSAGE =
93
+ "Video player controls - use left/right to navigate";
85
94
 
86
95
  class InteractionManagerClass extends React.Component<Props, State> {
87
96
  onKeyDownListener: (keyCode: KeyCode) => void;
@@ -98,6 +107,8 @@ class InteractionManagerClass extends React.Component<Props, State> {
98
107
  private confirmDialog: ConfirmationDialogState =
99
108
  confirmationDialogStore.getState();
100
109
 
110
+ accessibilityManager: AccessibilityManager;
111
+
101
112
  state: State = {
102
113
  isKeyboardVisible: false,
103
114
  keyboardInput: "",
@@ -139,14 +150,9 @@ class InteractionManagerClass extends React.Component<Props, State> {
139
150
  this.handleInputBlur = this.handleInputBlur.bind(this);
140
151
  this.handleKeyboardInput = this.handleKeyboardInput.bind(this);
141
152
  this.handleKeyboardDismiss = this.handleKeyboardDismiss.bind(this);
142
- this.onKeyDownListener = this.onKeyDown.bind(this);
143
- this.onKeyUp = this.onKeyUp.bind(this);
144
153
  this.onMouseMoveListener = this.onMouseMove.bind(this);
145
154
  this.onScrollListener = this.onScroll.bind(this);
146
155
  this.onMouseDownListener = this.onMouseDown.bind(this);
147
- this.onKeyboardStateChange = this.onKeyboardStateChange.bind(this);
148
- this.onConfirmDialogOpen = this.onConfirmDialogOpen.bind(this);
149
- this.onConfirmDialogClose = this.onConfirmDialogClose.bind(this);
150
156
 
151
157
  this.handlePhysicalKeyboardDismiss =
152
158
  this.handlePhysicalKeyboardDismiss.bind(this);
@@ -154,6 +160,7 @@ class InteractionManagerClass extends React.Component<Props, State> {
154
160
  this.confirmDialog.setConfirmAction(this.performExit);
155
161
  this.confirmDialog.setCancelAction(this.onConfirmDialogClose);
156
162
  this.longPressDetector = new KeyboardLongPressManager();
163
+ this.accessibilityManager = AccessibilityManager.getInstance();
157
164
  }
158
165
 
159
166
  componentDidMount() {
@@ -259,7 +266,6 @@ class InteractionManagerClass extends React.Component<Props, State> {
259
266
  */
260
267
  showConfirmationDialog({
261
268
  title: "",
262
- message: alertConfirmationMesage,
263
269
  confirmCompletion: this.performExit,
264
270
  });
265
271
  }
@@ -282,7 +288,6 @@ class InteractionManagerClass extends React.Component<Props, State> {
282
288
  } else {
283
289
  showConfirmationDialog({
284
290
  title: "",
285
- message: alertConfirmationMesage,
286
291
  confirmCompletion: this.performExit,
287
292
  cancelCompletion: this.onConfirmDialogClose,
288
293
  });
@@ -318,13 +323,9 @@ class InteractionManagerClass extends React.Component<Props, State> {
318
323
  const { navigator } = this.props;
319
324
  const { rivers } = this.props;
320
325
 
321
- const homeId = R.compose(
322
- R.prop("id"),
323
- R.find(R.prop("home")),
324
- R.values
325
- )(rivers);
326
+ const homeRiver = getHomeRiver(rivers);
326
327
 
327
- const homePath = `/river/${homeId}`;
328
+ const homePath = `/river/${homeRiver?.id}`;
328
329
 
329
330
  return homePath === navigator.currentRoute;
330
331
  }
@@ -332,7 +333,7 @@ class InteractionManagerClass extends React.Component<Props, State> {
332
333
  goToHome() {
333
334
  const { navigator } = this.props;
334
335
  const { rivers } = this.props;
335
- const homeRiver = R.find(R.propEq("home", true), R.values(rivers));
336
+ const homeRiver = getHomeRiver(rivers);
336
337
 
337
338
  navigator.replace(homeRiver);
338
339
  }
@@ -393,7 +394,15 @@ class InteractionManagerClass extends React.Component<Props, State> {
393
394
  note: backspace affects the keyboard input, so it behaves differently
394
395
  */
395
396
  onBackPress(event) {
396
- const { displayState, setDisplayState, navigator } = this.props;
397
+ const {
398
+ displayState,
399
+ setDisplayState,
400
+ navigator,
401
+ backToTopAction,
402
+ emitFocusOnSelectedTopMenuItem,
403
+ emitFocusOnSelectedTab,
404
+ } = this.props;
405
+
397
406
  const { isDialogVisible } = confirmationDialogStore.getState();
398
407
  const { isKeyboardVisible } = this.state;
399
408
 
@@ -412,8 +421,47 @@ class InteractionManagerClass extends React.Component<Props, State> {
412
421
  return;
413
422
  }
414
423
 
424
+ const action = backToTopAction();
425
+
415
426
  switch (displayState) {
416
427
  case DISPLAY_STATES.DEFAULT:
428
+ if (action === "PLATFORM_BACK") {
429
+ log_info(action);
430
+
431
+ this.platformBack();
432
+ }
433
+
434
+ if (action === "GO_HOME") {
435
+ log_info(action);
436
+
437
+ this.goToHome();
438
+ }
439
+
440
+ if (action === "FOCUS_ON_SELECTED_TOP_MENU_ITEM") {
441
+ log_info(action);
442
+
443
+ // we don't have enough context at this point to set focus properly on selected top-menu-item, just emit event about it.
444
+ // TopMenu component is supposed to handle this event.
445
+ emitFocusOnSelectedTopMenuItem();
446
+ }
447
+
448
+ if (action === "FOCUS_ON_SELECTED_TAB_ITEM") {
449
+ log_info(action);
450
+
451
+ // we don't have enough context at this point to set focus properly on selected tab-menu-item, just emit event about it
452
+ // Tabs component is supposed to handle this event.
453
+ emitFocusOnSelectedTab();
454
+ }
455
+
456
+ if (action === "GO_BACK") {
457
+ log_info(action);
458
+
459
+ if (navigator.canGoBack()) {
460
+ navigator.goBack();
461
+ }
462
+ }
463
+
464
+ break;
417
465
  case DISPLAY_STATES.PLAYER:
418
466
  if (isDialogVisible) {
419
467
  this.onConfirmDialogClose();
@@ -553,6 +601,13 @@ class InteractionManagerClass extends React.Component<Props, State> {
553
601
  ) {
554
602
  if (displayState === DISPLAY_STATES.PLAYER) {
555
603
  setDisplayState(DISPLAY_STATES.HUD);
604
+
605
+ this.accessibilityManager.addHeading(
606
+ VIDEO_PLAYER_CONTROLS_NAVIGATION_MESSAGE
607
+ );
608
+
609
+ focusManager.recoverFocus();
610
+ this.resetHudTimeout();
556
611
  } else {
557
612
  focusManager.pressIn();
558
613
  focusManager.press();
@@ -597,6 +652,12 @@ class InteractionManagerClass extends React.Component<Props, State> {
597
652
  this.resetHudTimeout();
598
653
  }
599
654
 
655
+ if (displayState === DISPLAY_STATES.PLAYER) {
656
+ this.accessibilityManager.addHeading(
657
+ VIDEO_PLAYER_CONTROLS_NAVIGATION_MESSAGE
658
+ );
659
+ }
660
+
600
661
  return true;
601
662
  }
602
663
  }
@@ -653,8 +714,13 @@ class InteractionManagerClass extends React.Component<Props, State> {
653
714
  onConfirmDialogClose() {
654
715
  this.confirmDialog.hideDialog();
655
716
 
656
- // restore initial focus after closing dialog
657
- focusManager.setInitialFocus();
717
+ const context: FocusManager.FocusContext = {
718
+ source: "cancel",
719
+ preserveScroll: true,
720
+ };
721
+
722
+ // restore initial focus after closing dialog(with preserve scrolling)
723
+ focusManager.setInitialFocus(undefined, context);
658
724
  }
659
725
 
660
726
  handleInputFocus = (event: FocusEvent) => {
@@ -852,5 +918,6 @@ export const InteractionManager = R.compose(
852
918
  withXray,
853
919
  connectToStore(R.pick(["rivers"])),
854
920
  PlayerContentContext.withConsumer,
855
- DisplayStateContext.withConsumer
921
+ DisplayStateContext.withConsumer,
922
+ withBackToTopActionHOC
856
923
  )(InteractionManagerClass);
@@ -1,4 +1,5 @@
1
1
  import * as React from "react";
2
+ import { createPortal } from "react-dom";
2
3
 
3
4
  import { Background } from "@applicaster/zapp-react-dom-ui-components/Components/Background";
4
5
  import { ConfirmDialog } from "@applicaster/zapp-react-dom-ui-components/Components/ConfirmDialog";
@@ -29,7 +30,7 @@ export function Layout({ children }: Props) {
29
30
  >
30
31
  {children}
31
32
  </LayoutComponent>
32
- <ConfirmDialog />
33
+ {createPortal(<ConfirmDialog />, document.body)}
33
34
  </>
34
35
  );
35
36
  }
@@ -3,7 +3,7 @@ import * as React from "react";
3
3
  import * as R from "ramda";
4
4
  import PropTypes from "prop-types";
5
5
 
6
- import { connectToStore } from "@applicaster/zapp-react-native-redux";
6
+ import { connectToStore } from "@applicaster/zapp-react-native-redux/utils/connectToStore";
7
7
  import { QUICK_BRICK_EVENTS } from "@applicaster/zapp-react-native-bridge/QuickBrick";
8
8
 
9
9
  import { QuickBrickEvents } from "../../Polyfills/QuickBrickCommunicationModule";
@@ -1,14 +1,12 @@
1
- import * as R from "ramda";
2
1
  import { NativeModules } from "react-native";
3
2
  import uuidv4 from "uuid/v4";
4
3
 
5
4
  import { isEmptyOrNil } from "@applicaster/zapp-react-native-utils/cellUtils";
6
- import { mapKeys } from "@applicaster/zapp-react-native-utils/objectUtils";
7
5
  import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
8
6
  import { sessionStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/SessionStorage";
9
7
  import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
10
8
 
11
- import { renameKeys, getDeviceData } from "./utils/platform";
9
+ import { renameKeys, getDeviceData, getUserAgent } from "./utils/platform";
12
10
  import { desiredKeysMap } from "./utils/const";
13
11
 
14
12
  /**
@@ -55,6 +53,9 @@ export const loadPluginDataIntoSession = async (plugins = null) => {
55
53
  async function gatherData(uuid) {
56
54
  const deviceData = await getDeviceData();
57
55
 
56
+ // Prevent the device sdkVersion from overriding the build time value
57
+ delete deviceData.sdkVersion;
58
+
58
59
  const { languageLocale, countryLocale } =
59
60
  NativeModules?.QuickBrickCommunicationModule || {};
60
61
 
@@ -63,7 +64,9 @@ async function gatherData(uuid) {
63
64
  ...NativeModules?.QuickBrickCommunicationModule,
64
65
  // Device data retrieved from native device apis
65
66
  ...deviceData,
66
- uuid: uuid || uuidv4(),
67
+ userAgent: deviceData.userAgent || getUserAgent(),
68
+ uuid: uuid || uuidv4(), // Created on first session, persisted in local thereafter
69
+ sessionId: uuidv4(), // Created on every session
67
70
  locale: `{language=${languageLocale}, country=${countryLocale}}`,
68
71
  };
69
72
 
@@ -78,21 +81,23 @@ async function gatherData(uuid) {
78
81
  * @param {Object} desiredKeys - The map of original key names to desired key names.
79
82
  */
80
83
  function storeData(data, desiredKeys) {
81
- // Pick only the keys we want and need, map them to the correct name, and reject any unusuable data
82
- const filteredData = R.compose(
83
- R.reject(isEmptyOrNil),
84
- R.reject(R.either(R.is(Object), R.is(Function))),
85
- mapKeys(renameKeys),
86
- R.pick(Object.keys(desiredKeys))
87
- )(data);
88
-
89
- R.forEachObjIndexed((value, key) => {
90
- if (key === "uuid") {
91
- localStorage.setItem(key, value);
84
+ const desiredKeysList = Object.keys(desiredKeys);
85
+
86
+ Object.entries(data).forEach(([key, value]) => {
87
+ if (!desiredKeysList.includes(key)) return;
88
+
89
+ if (isEmptyOrNil(value)) return;
90
+
91
+ if (typeof value === "object" || typeof value === "function") return;
92
+
93
+ const renamedKey = renameKeys(key);
94
+
95
+ if (renamedKey === "uuid") {
96
+ localStorage.setItem(renamedKey, value);
92
97
  }
93
98
 
94
- sessionStorage.setItem(key, value);
95
- }, filteredData);
99
+ sessionStorage.setItem(renamedKey, value);
100
+ });
96
101
  }
97
102
 
98
103
  /**
@@ -37,6 +37,7 @@ export const desiredKeysMap = {
37
37
  osVersion: "osVersion",
38
38
  platform: "platform",
39
39
  quickBrickVersion: "quickBrickVersion",
40
+ sessionId: "sessionId",
40
41
  sdkVersion: "sdk_version",
41
42
  store: "store",
42
43
  timeZoneOffset: "timeZoneOffset",
@@ -257,26 +257,7 @@ export const getTizenInfo = () => {
257
257
  */
258
258
  export const getDeviceData = async () => {
259
259
  try {
260
- let deviceData = {
261
- modelName: null,
262
- version: null,
263
- versionMajor: null,
264
- versionMinor: null,
265
- versionDot: null,
266
- sdkVersion: null,
267
- screenWidth: null,
268
- screenHeight: null,
269
- uhd: null,
270
- oled: null,
271
- ddrSize: null,
272
- uhd8K: null,
273
- hdr10: null,
274
- dolbyVision: null,
275
- dolbyAtmos: null,
276
- name: null,
277
- osVersion: null,
278
- networkType: null,
279
- };
260
+ let deviceData = {};
280
261
 
281
262
  if (isLgPlatform()) {
282
263
  const [webOSInfo, webOSConnectionInfo] = await Promise.all([
@@ -308,7 +289,6 @@ export const getDeviceData = async () => {
308
289
  platform: "vizio",
309
290
  deviceMake: "Vizio",
310
291
  deviceType: "tv",
311
- userAgent: getUserAgent(),
312
292
  deviceWidth: window.innerWidth,
313
293
  deviceHeight: window.innerHeight,
314
294
  };
@@ -1,4 +1,4 @@
1
- import { connectToStore } from "@applicaster/zapp-react-native-redux";
1
+ import { connectToStore } from "@applicaster/zapp-react-native-redux/utils/connectToStore";
2
2
  import * as R from "ramda";
3
3
 
4
4
  import { SplashComponent } from "./Splash";
@@ -1,10 +1,5 @@
1
1
  import * as R from "ramda";
2
- import {
3
- getStorageModule,
4
- applyNamespaceToKeyName,
5
- STORAGE_TYPES,
6
- DEFAULT_NAMESPACE,
7
- } from "../";
2
+ import { getStorageModule, STORAGE_TYPES } from "../";
8
3
 
9
4
  import { StorageMock } from "./StorageMocks";
10
5
 
@@ -37,7 +32,6 @@ describe("storageObject", () => {
37
32
  const value = "bar";
38
33
  const namespaceValue = "baz";
39
34
  const namespace = "baz";
40
- const keyName = applyNamespaceToKeyName(key, namespace);
41
35
  const failKey = "fail_key";
42
36
 
43
37
  beforeEach(clearStorage);
@@ -54,16 +48,11 @@ describe("storageObject", () => {
54
48
  it.each(storages)("sets a property in the storage", async (storage) => {
55
49
  const result = await storage.setItem(key, value, null);
56
50
 
57
- const keyWithDefaultNameSpace = applyNamespaceToKeyName(
58
- key,
59
- DEFAULT_NAMESPACE
60
- );
61
-
62
51
  expect(result).toBe(true);
63
52
 
64
- expect(storage.getItem(keyWithDefaultNameSpace)).resolves.toEqual(
65
- value
66
- );
53
+ const res = await storage.getItem(key, null);
54
+
55
+ expect(res).toEqual(value);
67
56
  });
68
57
 
69
58
  it.each(storages)(
@@ -73,7 +62,9 @@ describe("storageObject", () => {
73
62
 
74
63
  expect(result).toBe(true);
75
64
 
76
- expect(storage.getItem(keyName)).resolves.toEqual(namespaceValue);
65
+ const res = await storage.getItem(key, namespace);
66
+
67
+ expect(res).toEqual(namespaceValue);
77
68
  }
78
69
  );
79
70
 
@@ -108,7 +99,7 @@ describe("storageObject", () => {
108
99
  "gets properties from the storage with a namespace",
109
100
  (storage) => {
110
101
  expect(storage.getItem(key, namespace)).resolves.toEqual(
111
- "namespaceValue"
102
+ namespaceValue
112
103
  );
113
104
  }
114
105
  );
@@ -1,8 +1,5 @@
1
- import { QuickBrickCommunicationModule } from "./QuickBrickCommunicationModule";
2
- import { AnalyticsBridge } from "./AnalyticsBridge";
3
1
  import { getStorageModule } from "./Storage";
4
2
  import { DeviceEventEmitter } from "./DeviceEventEmitter";
5
- import { AppLoaderBridge } from "./AppLoaderBridge";
6
3
  import { isSamsungPlatform, isLgPlatform } from "../App/Loader/utils/platform";
7
4
 
8
5
  // Polyfill for abort controller required by shaka-player 4.x.x
@@ -24,11 +21,13 @@ const PLATFORM_KEYS = {
24
21
  // const DESKTOP_BROWSER = [PLATFORMS.linux, PLATFORMS.mac, PLATFORMS.win];
25
22
 
26
23
  export function registerNativeModulesPolyfills(NativeModules) {
27
- NativeModules.QuickBrickCommunicationModule = QuickBrickCommunicationModule;
28
24
  NativeModules.LocalStorage = getStorageModule("localStorage");
29
25
  NativeModules.SessionStorage = getStorageModule("sessionStorage");
30
- NativeModules.AnalyticsBridge = AnalyticsBridge;
31
- NativeModules.AppLoaderBridge = AppLoaderBridge;
26
+ NativeModules.AnalyticsBridge = require("./AnalyticsBridge").AnalyticsBridge;
27
+ NativeModules.AppLoaderBridge = require("./AppLoaderBridge").AppLoaderBridge;
28
+
29
+ NativeModules.QuickBrickCommunicationModule =
30
+ require("./QuickBrickCommunicationModule").QuickBrickCommunicationModule;
32
31
  }
33
32
 
34
33
  function getWebPlatform(fallbackPlatform) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-dom-app",
3
- "version": "14.0.0-rc.8",
3
+ "version": "15.0.0-rc.1",
4
4
  "description": "Zapp App Component for Applicaster's Quick Brick React Native App",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -22,11 +22,11 @@
22
22
  },
23
23
  "homepage": "https://github.com/applicaster/zapp-react-dom-app#readme",
24
24
  "dependencies": {
25
- "@applicaster/zapp-react-dom-ui-components": "14.0.0-rc.8",
26
- "@applicaster/zapp-react-native-bridge": "14.0.0-rc.8",
27
- "@applicaster/zapp-react-native-redux": "14.0.0-rc.8",
28
- "@applicaster/zapp-react-native-ui-components": "14.0.0-rc.8",
29
- "@applicaster/zapp-react-native-utils": "14.0.0-rc.8",
25
+ "@applicaster/zapp-react-dom-ui-components": "15.0.0-rc.1",
26
+ "@applicaster/zapp-react-native-bridge": "15.0.0-rc.1",
27
+ "@applicaster/zapp-react-native-redux": "15.0.0-rc.1",
28
+ "@applicaster/zapp-react-native-ui-components": "15.0.0-rc.1",
29
+ "@applicaster/zapp-react-native-utils": "15.0.0-rc.1",
30
30
  "abortcontroller-polyfill": "^1.7.5",
31
31
  "typeface-montserrat": "^0.0.54",
32
32
  "video.js": "7.14.3",
@@ -37,13 +37,9 @@
37
37
  "@applicaster/zapp-pipes-v2-client": "*",
38
38
  "@react-native-community/netinfo": "*",
39
39
  "core-js": "3.29.1",
40
- "immer": "*",
41
40
  "react": "*",
42
- "react-dom": "*",
43
41
  "react-native": "*",
44
- "react-native-safe-area-context": "*",
45
42
  "react-native-svg": "*",
46
- "react-native-web": "*",
47
43
  "uglify-js": "*",
48
44
  "validate-color": "*",
49
45
  "zustand": "*"