@applicaster/zapp-react-native-ui-components 16.0.0-alpha.7501599877 → 16.0.0-alpha.7845362739

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 (48) hide show
  1. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +47 -21
  2. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +34 -6
  3. package/Components/MasterCell/DefaultComponents/Image/hoc/utils/__tests__/withDimensions.test.ts +420 -125
  4. package/Components/MasterCell/DefaultComponents/Image/hoc/utils/index.ts +114 -19
  5. package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +19 -8
  6. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -3
  7. package/Components/MasterCell/DefaultComponents/PressableView.tsx +29 -9
  8. package/Components/MasterCell/DefaultComponents/Text/hooks/useText.ts +4 -0
  9. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +154 -100
  10. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx +15 -4
  11. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +56 -22
  12. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Spacer.ts +6 -4
  13. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +3 -1
  14. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +32 -21
  15. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +15 -4
  16. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +23 -16
  17. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +8 -3
  18. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +2 -2
  19. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/insertButtonsBetweenLabels.test.ts +45 -13
  20. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +2 -2
  21. package/Components/MasterCell/contexts/PressedStateContext.ts +3 -0
  22. package/Components/MasterCell/hooks/index.ts +2 -0
  23. package/Components/MasterCell/hooks/usePressedState.ts +4 -0
  24. package/Components/ModalComponent/AudioPlayer/Components/Action.tsx +332 -0
  25. package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +402 -0
  26. package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +811 -0
  27. package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +671 -0
  28. package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +878 -0
  29. package/Components/ModalComponent/AudioPlayer/Components/index.ts +9 -0
  30. package/Components/ModalComponent/BottomSheetDragArea.tsx +33 -0
  31. package/Components/ModalComponent/BottomSheetModalContent.tsx +49 -26
  32. package/Components/ModalComponent/__tests__/BottomSheetDragArea.test.tsx +74 -0
  33. package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +4 -85
  34. package/Components/OfflineHandler/__tests__/index.test.tsx +78 -18
  35. package/Components/OfflineHandler/hooks.ts +123 -0
  36. package/Components/OfflineHandler/index.tsx +51 -73
  37. package/Components/OfflineHandler/utils/index.ts +1 -13
  38. package/Components/PreloaderWrapper/index.tsx +1 -1
  39. package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +5 -3
  40. package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +1 -1
  41. package/Components/TopCutoffOverlay/index.tsx +2 -2
  42. package/Components/Transitioner/Transitioner.tsx +28 -17
  43. package/package.json +5 -5
  44. package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +0 -112
  45. package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +0 -107
  46. package/Components/OfflineHandler/NotificationView/NotificationView.tsx +0 -153
  47. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -66
  48. package/Components/OfflineHandler/NotificationView/utils.ts +0 -34
@@ -1,105 +1,83 @@
1
- import React, { useCallback, useEffect, useRef, useState } from "react";
2
- import { View, StyleSheet } from "react-native";
3
- import { NotificationView as NotificationViewNative } from "./NotificationView/NotificationView";
4
- import { NotificationView as NotificationViewSamsung } from "./NotificationView/NotificationView.samsung";
5
- import { NotificationView as NotificationViewLG } from "./NotificationView/NotificationView.lg";
6
-
1
+ import React, { useCallback, useEffect } from "react";
7
2
  import { useConnectionInfo } from "@applicaster/zapp-react-native-utils/reactHooks/connection";
8
3
  import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
9
- import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
4
+ import { useSubscriberFor } from "@applicaster/zapp-react-native-utils/reactHooks/useSubscriberFor";
10
5
 
6
+ import { useOfflineHandlerProps } from "./hooks";
11
7
  import { componentsLogger } from "../../Helpers/logger";
12
8
  import { parseConnectionInfo } from "./utils";
13
9
 
14
10
  const logger = componentsLogger.addSubsystem("OfflineHandler");
15
11
 
12
+ // mirrors NOTIFICATION_TOAST_EVENTS.SHOW_TOAST in
13
+ // @applicaster/quick-brick-core/App/NotificationToastRenderer/NotificationToastManager
14
+ // (kept as a literal here since this package must not depend on quick-brick-core)
15
+ const SHOW_TOAST_EVENT = "showToast";
16
+ const OFFLINE_STATUS_TOAST_ID = "offline-status";
17
+
16
18
  type Props = {
17
19
  children?: React.ReactElement<any>;
18
20
  };
19
21
 
20
- const styles = StyleSheet.create({
21
- container: {
22
- flex: 1,
23
- position: "relative",
24
- },
25
- });
26
-
27
22
  const timers = {
28
23
  goingOffline: 5000,
29
24
  goingOnline: 2000,
30
25
  };
31
26
 
32
- export const NotificationView = platformSelect({
33
- samsung_tv: NotificationViewSamsung,
34
- lg_tv: NotificationViewLG,
35
- default: NotificationViewNative,
36
- });
37
-
38
27
  export const OfflineHandler = ({ children }: Props) => {
39
28
  const connectionInfo = useConnectionInfo(false);
40
- const { online, deviceOnline } = parseConnectionInfo(connectionInfo);
29
+ const { online } = parseConnectionInfo(connectionInfo);
30
+ const prevOnline = usePrevious(online);
41
31
 
42
- const [hidden, setHidden] = useState<boolean>(true);
43
- const previousOnline: boolean = usePrevious(online);
44
- const timer = useRef<NodeJS.Timeout | null>(null);
45
- const initialRender = useRef(false);
32
+ const emitShowToast = useSubscriberFor(SHOW_TOAST_EVENT);
46
33
 
47
- const dismiss = useCallback(() => {
48
- setHidden(true);
34
+ const { message, extraMessage, style } = useOfflineHandlerProps(online);
49
35
 
50
- if (timer.current) {
51
- clearTimeout(timer.current);
52
- timer.current = null;
53
- }
54
- }, []);
36
+ const showOnlineToast = useCallback(() => {
37
+ logger.log("Device is back online, emit toast");
55
38
 
56
- const setTimer = useCallback((cb, duration) => {
57
- if (timer.current) {
58
- clearTimeout(timer.current);
59
- }
39
+ emitShowToast({
40
+ id: OFFLINE_STATUS_TOAST_ID,
41
+ message,
42
+ extraMessage,
43
+ style,
44
+ timeout: timers.goingOnline,
45
+ });
46
+ }, [emitShowToast, message, extraMessage, style]);
47
+
48
+ const showOfflineToast = useCallback(() => {
49
+ logger.log("Device went offline, emit toast");
60
50
 
61
- timer.current = setTimeout(cb, duration);
62
- }, []);
51
+ emitShowToast({
52
+ id: OFFLINE_STATUS_TOAST_ID,
53
+ message,
54
+ extraMessage,
55
+ style,
56
+ timeout: timers.goingOffline,
57
+ });
58
+ }, [emitShowToast, message, extraMessage, style]);
63
59
 
64
60
  useEffect(() => {
65
- if (initialRender.current) {
66
- const wentOffline = previousOnline && online === false;
67
- const wentOnline = !previousOnline && online;
68
- const renderedOffline = !online && previousOnline === null;
69
-
70
- if (!deviceOnline || wentOffline || renderedOffline) {
71
- logger.log("Device went offline");
72
- setTimer(() => setHidden(true), timers.goingOffline);
73
- setHidden(false);
61
+ // On mount there is no previous state yet: only surface the offline toast
62
+ // for a device that starts offline. Don't announce "back online" for a
63
+ // device that was online to begin with.
64
+ if (prevOnline === undefined) {
65
+ if (!online) {
66
+ showOfflineToast();
74
67
  }
75
68
 
76
- if (wentOnline) {
77
- logger.log("Device is back online");
78
- setHidden(false);
79
- setTimer(() => setHidden(true), timers.goingOnline);
80
- }
81
- } else {
82
- initialRender.current = true;
69
+ return;
83
70
  }
84
71
 
85
- return () => {
86
- if (timer.current) {
87
- clearTimeout(timer.current);
88
- timer.current = null;
72
+ // On subsequent renders, only emit a toast when the online/offline state changes.
73
+ if (prevOnline !== online) {
74
+ if (!online) {
75
+ showOfflineToast();
76
+ } else {
77
+ showOnlineToast();
89
78
  }
90
- };
91
- }, [connectionInfo]);
92
-
93
- return (
94
- <View style={styles.container}>
95
- <NotificationView
96
- hidden={hidden}
97
- online={online}
98
- previousOnline={previousOnline}
99
- dismiss={dismiss}
100
- >
101
- {children}
102
- </NotificationView>
103
- </View>
104
- );
79
+ }
80
+ }, [online, prevOnline, showOfflineToast, showOnlineToast]);
81
+
82
+ return children;
105
83
  };
@@ -1,9 +1,8 @@
1
1
  import * as R from "ramda";
2
-
3
2
  import { NetInfoState } from "@react-native-community/netinfo";
4
3
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
5
4
  import { isOnline as isOnlineUtils } from "@applicaster/quick-brick-core/App/NetworkStatusProvider/utils";
6
- import { useSafeAreaInsets } from "react-native-safe-area-context";
5
+
7
6
  import { Platform } from "react-native";
8
7
 
9
8
  type ConnectionInfo = NetInfoState & { deviceStatus: NetStatus };
@@ -51,14 +50,3 @@ export const parseConnectionInfo: typeof parseConnectionInfoForDefault =
51
50
  samsung_tv: parseConnectionInfoForSamsung,
52
51
  default: parseConnectionInfoForDefault,
53
52
  });
54
-
55
- export const useNotificationHeight = () => {
56
- const insets = useSafeAreaInsets();
57
-
58
- const navBarHeight = platformSelect({ ios: 44, android: 56 });
59
-
60
- const statusHeight = insets.top;
61
- const notificationHeight = statusHeight + navBarHeight;
62
-
63
- return { statusHeight, notificationHeight };
64
- };
@@ -2,7 +2,7 @@ import React from "react";
2
2
 
3
3
  type PreloaderWrapperProps = {
4
4
  showPreloader?: boolean;
5
- children?: React.ReactNode;
5
+ children: React.ReactElement | null;
6
6
  };
7
7
 
8
8
  export const PreloaderWrapper: React.FC<PreloaderWrapperProps> = ({
@@ -8,9 +8,11 @@ import { componentsLogger } from "../../Helpers/logger";
8
8
  const logger = componentsLogger.addSubsystem("ScreenFeedLoader");
9
9
 
10
10
  /** Loads and provides `feedData` and store to */
11
- export const ScreenFeedLoader: React.FC<
12
- React.PropsWithChildren<{ id: string; feedData: any }>
13
- > = ({ id, feedData, children }) => {
11
+ export const ScreenFeedLoader: React.FC<{
12
+ id: string;
13
+ feedData: any;
14
+ children: React.ReactElement | null;
15
+ }> = ({ id, feedData, children }) => {
14
16
  const { source: feedUrl, mapping } = feedData;
15
17
 
16
18
  const { data, loading, error } = useFeedLoader({
@@ -8,7 +8,7 @@ export const ScreenResolverFeedProvider = ({
8
8
  useFeedData,
9
9
  }: {
10
10
  id: string;
11
- children: React.ReactNode;
11
+ children: React.ReactElement | null;
12
12
  useFeedData: (id: string) => Option<ZappDataSource>;
13
13
  }) => {
14
14
  const feedData = useFeedData(id);
@@ -7,7 +7,7 @@ import { useMarginTop } from "./hooks";
7
7
 
8
8
  interface IProps {
9
9
  targetScreenId?: string;
10
- children?: React.ReactNode;
10
+ children: React.ReactElement | null;
11
11
  applyTopCutoff?: boolean;
12
12
  }
13
13
 
@@ -21,7 +21,7 @@ export const TopCutoffOverlay: React.FC<IProps> = ({
21
21
  targetScreenId,
22
22
  children,
23
23
  applyTopCutoff = true,
24
- }: IProps) => {
24
+ }) => {
25
25
  const cutoffHeight = useMarginTop(targetScreenId);
26
26
 
27
27
  const { backgroundColor: screenBackgroundColor } =
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { View } from "react-native";
3
- import { append, compose, identity, isNil, tail, take, update } from "ramda";
3
+ import { append, compose, identity, tail, take, update } from "ramda";
4
4
 
5
5
  import { AnimationManager } from "./AnimationManager";
6
6
  import { Scene } from "./Scene";
@@ -10,6 +10,7 @@ import {
10
10
  shouldSkipAnimationForPreviousWebViewScene,
11
11
  } from "./utils";
12
12
  import { v4 as uuid_v4 } from "uuid";
13
+ import { isScreenActiveForRoute } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useIsScreenActive";
13
14
 
14
15
  export const NAV_ACTION_PUSH = "PUSH";
15
16
 
@@ -50,16 +51,16 @@ function scenesForBackTransition(props: SceneProps, { scenes }) {
50
51
  : [prepareScene(props.children), scenes[0]];
51
52
  }
52
53
 
53
- const isModalClosed = (navigator) => {
54
- return !!isNil(navigator?.modalData);
55
- };
56
-
57
54
  type Props = {
58
55
  transitionConfig: any;
59
56
  children: React.ReactNode;
60
57
  navigator: {
61
58
  previousAction: string;
62
59
  currentRoute: string;
60
+ videoModalState?: {
61
+ visible?: boolean;
62
+ mode?: string;
63
+ };
63
64
  screenData: {
64
65
  [key: string]: any;
65
66
  };
@@ -283,8 +284,10 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
283
284
  // so only a single scene should be rendered,
284
285
  // instead of dangerous nulls or duplicates.
285
286
  renderSingleScene({ scenes, to }) {
286
- const { contentStyle } = this.props;
287
- const screenData = this.props.children.props.screenData;
287
+ const { contentStyle, navigator, children } = this.props;
288
+
289
+ const { currentRoute, videoModalState } = navigator;
290
+ const screenData = children.props.screenData;
288
291
  const pathname = scenes[to.index].key;
289
292
 
290
293
  return (
@@ -293,7 +296,11 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
293
296
  <Scene
294
297
  {...{ style: to?.style || {} }}
295
298
  pathname={pathname}
296
- isActive={pathname === this.props.navigator.currentRoute}
299
+ isActive={isScreenActiveForRoute(
300
+ pathname,
301
+ currentRoute,
302
+ videoModalState
303
+ )}
297
304
  contentStyle={contentStyle}
298
305
  key={scenes[to.index].key}
299
306
  screenUniqueId={scenes[to.index].screenUniqueId}
@@ -311,16 +318,19 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
311
318
  // Looks redundant, but when written like this
312
319
  // we do not need to pass or generate keys.
313
320
  renderScenes({ scenes, from, to }) {
314
- const { contentStyle } = this.props;
321
+ const { contentStyle, navigator } = this.props;
322
+
323
+ const { currentRoute, videoModalState } = navigator;
315
324
 
316
325
  const fromScene = scenes[from.index] && (
317
326
  <Scene
318
327
  key={scenes[from.index].key}
319
328
  pathname={scenes[from.index].key}
320
- isActive={
321
- scenes[from.index].key === this.props.navigator.currentRoute &&
322
- isModalClosed(this.props.navigator)
323
- }
329
+ isActive={isScreenActiveForRoute(
330
+ scenes[from.index].key,
331
+ currentRoute,
332
+ videoModalState
333
+ )}
324
334
  style={from.style}
325
335
  pointerEvents="none"
326
336
  overlayStyle={from.overlayStyle}
@@ -336,10 +346,11 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
336
346
  const toScene = scenes[to.index] && (
337
347
  <Scene
338
348
  pathname={scenes[to.index].key}
339
- isActive={
340
- scenes[to.index].key === this.props.navigator.currentRoute &&
341
- isModalClosed(this.props.navigator)
342
- }
349
+ isActive={isScreenActiveForRoute(
350
+ scenes[to.index].key,
351
+ currentRoute,
352
+ videoModalState
353
+ )}
343
354
  key={scenes[to.index].key}
344
355
  style={to.style}
345
356
  overlayStyle={to.overlayStyle}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-ui-components",
3
- "version": "16.0.0-alpha.7501599877",
3
+ "version": "16.0.0-alpha.7845362739",
4
4
  "description": "Applicaster Zapp React Native ui components for the Quick Brick App",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -28,10 +28,10 @@
28
28
  },
29
29
  "homepage": "https://github.com/applicaster/quickbrick#readme",
30
30
  "dependencies": {
31
- "@applicaster/applicaster-types": "16.0.0-alpha.7501599877",
32
- "@applicaster/zapp-react-native-bridge": "16.0.0-alpha.7501599877",
33
- "@applicaster/zapp-react-native-redux": "16.0.0-alpha.7501599877",
34
- "@applicaster/zapp-react-native-utils": "16.0.0-alpha.7501599877",
31
+ "@applicaster/applicaster-types": "16.0.0-alpha.7845362739",
32
+ "@applicaster/zapp-react-native-bridge": "16.0.0-alpha.7845362739",
33
+ "@applicaster/zapp-react-native-redux": "16.0.0-alpha.7845362739",
34
+ "@applicaster/zapp-react-native-utils": "16.0.0-alpha.7845362739",
35
35
  "fast-json-stable-stringify": "^2.1.0",
36
36
  "promise": "^8.3.0",
37
37
  "url": "^0.11.0",
@@ -1,112 +0,0 @@
1
- import * as React from "react";
2
- import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
3
- import { useNetworkStatusLocalizations } from "./utils";
4
-
5
- type Props = {
6
- children?: React.ReactNode;
7
- hidden?: boolean;
8
- online?: boolean;
9
- previousOnline?: boolean;
10
- dismiss: () => void;
11
- };
12
-
13
- const NOTIF_DURATION = 4500;
14
-
15
- const styles: Record<any, React.CSSProperties> = {
16
- body: {
17
- position: "absolute",
18
- bottom: 0,
19
- width: 1920,
20
- height: 200,
21
- background:
22
- "linear-gradient(180deg, rgba(17,17,17,0.9) 0%, rgba(17,17,17,1) 49%, rgba(0,0,0,0.85) 100%)",
23
- display: "flex",
24
- alignItems: "center",
25
- justifyContent: "center",
26
- flexDirection: "column",
27
- color: "#fff",
28
- paddingBottom: 15,
29
- },
30
- title: {
31
- fontSize: 28,
32
- margin: 0,
33
- padding: 0,
34
- },
35
- subtitle: {
36
- fontSize: 20,
37
- margin: 0,
38
- padding: 0,
39
- },
40
- };
41
-
42
- export const NotificationView = (props: Props) => {
43
- const { children, hidden, dismiss, previousOnline, online } = props;
44
-
45
- const theme = useTheme<BaseThemePropertiesTV>();
46
- const storedLocalizations = useNetworkStatusLocalizations();
47
-
48
- const [open, setOpen] = React.useState<boolean | null>(null);
49
-
50
- const timeout = React.useRef<NodeJS.Timeout>();
51
- const wentOnline = !previousOnline && props.online;
52
-
53
- const onClose = () => {
54
- setOpen(false);
55
- dismiss();
56
- };
57
-
58
- const closeNotification = () => {
59
- clearTimeout(timeout.current as NodeJS.Timeout);
60
-
61
- timeout.current = setTimeout(() => {
62
- setOpen(false);
63
- }, NOTIF_DURATION);
64
- };
65
-
66
- const openNotification = () => {
67
- if (!open && !hidden) {
68
- setOpen(true);
69
- }
70
- };
71
-
72
- const handleNotificationChange = () => {
73
- if (open !== null) {
74
- openNotification();
75
- }
76
-
77
- closeNotification();
78
- };
79
-
80
- React.useEffect(() => {
81
- handleNotificationChange();
82
- }, [hidden, online]);
83
-
84
- const showOnlineMsg = wentOnline || online;
85
-
86
- const MSG = showOnlineMsg
87
- ? (theme?.online_notification_title ??
88
- storedLocalizations?.online_notification_title)
89
- : (theme?.offline_notification_title ??
90
- storedLocalizations?.offline_notification_title);
91
-
92
- const EXTRA_MSG = showOnlineMsg
93
- ? (theme?.online_notification_subtitle ??
94
- storedLocalizations?.online_notification_subtitle)
95
- : (theme?.offline_notification_subtitle ??
96
- storedLocalizations?.offline_notification_subtitle);
97
-
98
- return (
99
- <div onClick={onClose}>
100
- {children}
101
- {open ? (
102
- <div style={styles.body}>
103
- <div style={styles.title}>
104
- <h2>{MSG}</h2>
105
- </div>
106
-
107
- <h4 style={styles.subtitle}>{EXTRA_MSG}</h4>
108
- </div>
109
- ) : null}
110
- </div>
111
- );
112
- };
@@ -1,107 +0,0 @@
1
- import * as React from "react";
2
- import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
3
- import { useNetworkStatusLocalizations } from "./utils";
4
-
5
- type Props = {
6
- children?: React.ReactNode;
7
- online?: boolean;
8
- previousOnline?: boolean;
9
- dismiss: () => void;
10
- };
11
-
12
- const DURATION_TO_HIDE_AFTER_BACK_TO_ONLINE = 4500; // ms
13
-
14
- const styles: Record<any, React.CSSProperties> = {
15
- body: {
16
- position: "absolute",
17
- top: 0,
18
- width: 1920,
19
- height: 200,
20
- background:
21
- "linear-gradient(180deg, rgba(17,17,17,0.9) 0%, rgba(17,17,17,1) 49%, rgba(0,0,0,0.85) 100%)",
22
- display: "flex",
23
- alignItems: "center",
24
- justifyContent: "center",
25
- flexDirection: "column",
26
- color: "#fff",
27
- paddingTop: 15,
28
- },
29
- title: {
30
- fontSize: 28,
31
- margin: 0,
32
- padding: 0,
33
- },
34
- subtitle: {
35
- fontSize: 20,
36
- margin: 0,
37
- padding: 0,
38
- },
39
- };
40
-
41
- let timer: NodeJS.Timeout;
42
-
43
- export const NotificationView = (props: Props) => {
44
- const { children, dismiss, previousOnline = true, online } = props;
45
-
46
- const theme = useTheme<BaseThemePropertiesTV>();
47
- const storedLocalizations = useNetworkStatusLocalizations();
48
-
49
- const [shown, setShown] = React.useState<boolean>(false);
50
-
51
- const onClose = () => {
52
- setShown(false);
53
- dismiss();
54
- };
55
-
56
- React.useEffect(() => {
57
- if (previousOnline && online) {
58
- return;
59
- }
60
-
61
- if (!previousOnline && !online) {
62
- return;
63
- }
64
-
65
- if (previousOnline && !online) {
66
- // went to offline
67
- clearTimeout(timer);
68
- setShown(true);
69
- }
70
-
71
- if (!previousOnline && online) {
72
- // back to online
73
- setShown(true);
74
-
75
- timer = setTimeout(() => {
76
- setShown(false);
77
- }, DURATION_TO_HIDE_AFTER_BACK_TO_ONLINE);
78
- }
79
- }, [online, previousOnline]);
80
-
81
- const title = online
82
- ? (theme?.online_notification_title ??
83
- storedLocalizations?.online_notification_title)
84
- : (theme?.offline_notification_title ??
85
- storedLocalizations?.offline_notification_title);
86
-
87
- const subtitle = online
88
- ? (theme?.online_notification_subtitle ??
89
- storedLocalizations?.online_notification_subtitle)
90
- : (theme?.offline_notification_subtitle ??
91
- storedLocalizations?.offline_notification_subtitle);
92
-
93
- return (
94
- <div onClick={onClose}>
95
- {children}
96
- {shown ? (
97
- <div style={styles.body}>
98
- <div style={styles.title}>
99
- <h2>{title}</h2>
100
- </div>
101
-
102
- <h4 style={styles.subtitle}>{subtitle}</h4>
103
- </div>
104
- ) : null}
105
- </div>
106
- );
107
- };