@applicaster/zapp-react-native-ui-components 15.0.0-rc.12 → 15.0.0-rc.121

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 (159) hide show
  1. package/Components/AnimatedInOut/index.tsx +69 -26
  2. package/Components/BaseFocusable/index.ios.ts +12 -2
  3. package/Components/Cell/Cell.tsx +14 -3
  4. package/Components/Cell/CellWithFocusable.tsx +9 -0
  5. package/Components/Cell/FocusableWrapper.tsx +47 -0
  6. package/Components/Cell/TvOSCellComponent.tsx +106 -19
  7. package/Components/Focusable/Focusable.tsx +4 -2
  8. package/Components/Focusable/FocusableTvOS.tsx +18 -1
  9. package/Components/Focusable/__tests__/__snapshots__/FocusableTvOS.test.tsx.snap +1 -0
  10. package/Components/FocusableGroup/FocusableTvOS.tsx +32 -1
  11. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +39 -28
  12. package/Components/GeneralContentScreen/__tests__/GeneralContentScreen.test.tsx +104 -0
  13. package/Components/GeneralContentScreen/utils/__tests__/getScreenDataSource.test.ts +19 -0
  14. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +1 -1
  15. package/Components/GeneralContentScreen/utils/getScreenDataSource.ts +9 -0
  16. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +22 -6
  17. package/Components/HandlePlayable/HandlePlayable.tsx +33 -94
  18. package/Components/HandlePlayable/const.ts +3 -0
  19. package/Components/HandlePlayable/utils.ts +105 -0
  20. package/Components/HookRenderer/HookRenderer.tsx +40 -10
  21. package/Components/HookRenderer/__tests__/HookRenderer.test.tsx +60 -0
  22. package/Components/Layout/TV/LayoutBackground.tsx +5 -2
  23. package/Components/Layout/TV/NavBarContainer.tsx +1 -10
  24. package/Components/Layout/TV/ScreenContainer.tsx +2 -6
  25. package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +7 -12
  26. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +7 -12
  27. package/Components/Layout/TV/index.tsx +3 -4
  28. package/Components/Layout/TV/index.web.tsx +3 -4
  29. package/Components/LinkHandler/LinkHandler.tsx +2 -2
  30. package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx +16 -1
  31. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +30 -2
  32. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +5 -1
  33. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +11 -3
  34. package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +9 -1
  35. package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +15 -14
  36. package/Components/MasterCell/DefaultComponents/LiveImage/__tests__/prepareEntry.test.ts +352 -0
  37. package/Components/MasterCell/DefaultComponents/LiveImage/executePreloadHooks.ts +136 -0
  38. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +43 -22
  39. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +40 -39
  40. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/Image.test.tsx +95 -0
  41. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +86 -0
  42. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/index.test.ts +141 -0
  43. package/Components/MasterCell/DefaultComponents/SecondaryImage/hooks/__tests__/useGetImageDimensions.test.ts +7 -6
  44. package/Components/MasterCell/DefaultComponents/SecondaryImage/index.ts +1 -1
  45. package/Components/MasterCell/DefaultComponents/Text/index.tsx +8 -8
  46. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +6 -2
  47. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/getPluginIdentifier.test.ts +233 -11
  48. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +19 -15
  49. package/Components/MasterCell/hoc/__tests__/withAsyncRender.test.tsx +219 -0
  50. package/Components/MasterCell/hoc/withAsyncRender.tsx +9 -7
  51. package/Components/MasterCell/index.tsx +2 -0
  52. package/Components/MasterCell/utils/__tests__/resolveColor.test.js +82 -3
  53. package/Components/MasterCell/utils/index.ts +61 -31
  54. package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +102 -87
  55. package/Components/MeasurmentsPortal/__tests__/MeasurementsPortal.test.tsx +355 -0
  56. package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +17 -9
  57. package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +16 -8
  58. package/Components/OfflineHandler/NotificationView/NotificationView.tsx +2 -2
  59. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +17 -18
  60. package/Components/OfflineHandler/NotificationView/utils.ts +34 -0
  61. package/Components/OfflineHandler/__tests__/index.test.tsx +27 -18
  62. package/Components/PlayerContainer/PlayerContainer.tsx +43 -64
  63. package/Components/PlayerImageBackground/index.tsx +3 -22
  64. package/Components/PreloaderWrapper/__tests__/index.test.tsx +26 -0
  65. package/Components/PreloaderWrapper/index.tsx +15 -0
  66. package/Components/River/ComponentsMap/ComponentsMap.tsx +16 -0
  67. package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +1 -1
  68. package/Components/River/RefreshControl.tsx +9 -3
  69. package/Components/River/RiverItem.tsx +26 -20
  70. package/Components/River/TV/River.tsx +31 -14
  71. package/Components/River/TV/index.tsx +8 -4
  72. package/Components/River/TV/utils/__tests__/toStringOrEmpty.test.ts +30 -0
  73. package/Components/River/TV/utils/index.ts +4 -0
  74. package/Components/River/TV/withFocusableGroupForContent.tsx +71 -0
  75. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +2 -0
  76. package/Components/River/__tests__/componentsMap.test.js +38 -0
  77. package/Components/Screen/TV/index.web.tsx +4 -2
  78. package/Components/Screen/__tests__/Screen.test.tsx +66 -42
  79. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +68 -44
  80. package/Components/Screen/hooks.ts +75 -6
  81. package/Components/Screen/index.tsx +9 -4
  82. package/Components/Screen/navigationHandler.ts +49 -24
  83. package/Components/Screen/orientationHandler.ts +10 -13
  84. package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +46 -0
  85. package/Components/ScreenFeedLoader/__tests__/ScreenFeedLoader.test.tsx +94 -0
  86. package/Components/ScreenFeedLoader/index.ts +1 -0
  87. package/Components/ScreenResolver/__tests__/screenResolver.test.js +24 -0
  88. package/Components/ScreenResolver/hooks/index.ts +3 -0
  89. package/Components/ScreenResolver/hooks/useGetComponent.ts +15 -0
  90. package/Components/ScreenResolver/hooks/useScreenComponentResolver.tsx +90 -0
  91. package/Components/ScreenResolver/index.tsx +15 -111
  92. package/Components/ScreenResolver/utils/__tests__/getScreenTypeProps.test.ts +45 -0
  93. package/Components/ScreenResolver/utils/getScreenTypeProps.ts +43 -0
  94. package/Components/ScreenResolver/utils/index.ts +1 -0
  95. package/Components/ScreenResolver/withDefaultScreenContext.tsx +16 -0
  96. package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +25 -0
  97. package/Components/ScreenResolverFeedProvider/__tests__/ScreenResolverFeedProvider.test.tsx +44 -0
  98. package/Components/ScreenResolverFeedProvider/index.ts +1 -0
  99. package/Components/ScreenRevealManager/ScreenRevealManager.ts +40 -8
  100. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +86 -69
  101. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +44 -26
  102. package/Components/Tabs/TV/Tabs.tsx +20 -3
  103. package/Components/Tabs/TabContent.tsx +7 -4
  104. package/Components/Transitioner/Scene.tsx +10 -3
  105. package/Components/Transitioner/index.js +3 -3
  106. package/Components/VideoLive/LiveImageManager.ts +199 -54
  107. package/Components/VideoLive/PlayerLiveImageComponent.tsx +31 -33
  108. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +2 -17
  109. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +1 -0
  110. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +118 -171
  111. package/Components/VideoModal/ModalAnimation/index.ts +2 -13
  112. package/Components/VideoModal/ModalAnimation/utils.ts +1 -327
  113. package/Components/VideoModal/PlayerWrapper.tsx +14 -88
  114. package/Components/VideoModal/VideoModal.tsx +1 -5
  115. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -0
  116. package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +15 -7
  117. package/Components/VideoModal/hooks/useModalSize.ts +10 -5
  118. package/Components/VideoModal/playerWrapperStyle.ts +70 -0
  119. package/Components/VideoModal/playerWrapperUtils.ts +91 -0
  120. package/Components/VideoModal/utils.ts +19 -9
  121. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +0 -2
  122. package/Components/Viewport/ViewportAware/index.tsx +16 -7
  123. package/Components/Viewport/ViewportEvents/__tests__/viewportEvents.test.js +1 -1
  124. package/Components/ZappUIComponent/index.tsx +12 -6
  125. package/Components/index.js +1 -1
  126. package/Contexts/ScreenContext/__tests__/index.test.tsx +57 -0
  127. package/Contexts/ScreenContext/index.tsx +71 -19
  128. package/Contexts/ScreenTrackedViewPositionsContext/__tests__/index.test.tsx +1 -1
  129. package/Contexts/ZappHookModalContext/index.tsx +37 -61
  130. package/Contexts/ZappPipesContext/ZappPipesContextFactory.tsx +18 -7
  131. package/Contexts/index.ts +0 -2
  132. package/Decorators/Analytics/index.tsx +6 -5
  133. package/Decorators/ConfigurationWrapper/__tests__/__snapshots__/withConfigurationProvider.test.tsx.snap +1 -0
  134. package/Decorators/ConfigurationWrapper/const.ts +1 -0
  135. package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -7
  136. package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +212 -5
  137. package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +39 -21
  138. package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +1 -1
  139. package/Decorators/ZappPipesDataConnector/index.tsx +2 -2
  140. package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +1 -1
  141. package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +18 -7
  142. package/Helpers/DataSourceHelper/__tests__/itemLimitForData.test.ts +80 -0
  143. package/Helpers/DataSourceHelper/index.ts +19 -0
  144. package/events/index.ts +3 -0
  145. package/events/scrollEndReached.ts +15 -0
  146. package/index.d.ts +7 -0
  147. package/package.json +6 -5
  148. package/Components/PlayerContainer/ErrorDisplay/ErrorDisplay.tsx +0 -57
  149. package/Components/PlayerContainer/ErrorDisplay/index.ts +0 -9
  150. package/Components/River/TV/withTVEventHandler.tsx +0 -27
  151. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +0 -60
  152. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +0 -417
  153. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.web.tsx +0 -294
  154. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +0 -176
  155. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.web.tsx +0 -93
  156. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +0 -500
  157. package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +0 -108
  158. package/Helpers/DataSourceHelper/index.js +0 -19
  159. /package/Components/HookRenderer/{index.tsx → index.ts} +0 -0
@@ -0,0 +1,46 @@
1
+ import React, { useEffect } from "react";
2
+ import { PreloaderWrapper } from "../PreloaderWrapper";
3
+ import { useScreenContextV2 } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
4
+ import { useFeedLoader } from "@applicaster/zapp-react-native-utils/reactHooks";
5
+
6
+ import { componentsLogger } from "../../Helpers/logger";
7
+
8
+ const logger = componentsLogger.addSubsystem("ScreenFeedLoader");
9
+
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 }) => {
14
+ const { source: feedUrl, mapping } = feedData;
15
+
16
+ const { data, loading, error } = useFeedLoader({
17
+ feedUrl,
18
+ mapping,
19
+ pipesOptions: {},
20
+ });
21
+
22
+ const feedStore = useScreenContextV2()._feedStore;
23
+
24
+ useEffect(() => {
25
+ if (data && !loading) {
26
+ feedStore.setState({ screenFeed: data, screenFeedError: null });
27
+
28
+ logger.log("screenFeed set for active screen", { data, screenId: id });
29
+ }
30
+
31
+ if (error && !loading) {
32
+ feedStore.setState({ screenFeed: data, screenFeedError: error });
33
+
34
+ logger.warning("Feed data error:", {
35
+ data,
36
+ loading,
37
+ error,
38
+ screenId: id,
39
+ });
40
+ }
41
+ }, [data, loading, error, feedStore, id]);
42
+
43
+ return (
44
+ <PreloaderWrapper showPreloader={loading}>{children}</PreloaderWrapper>
45
+ );
46
+ };
@@ -0,0 +1,94 @@
1
+ import React from "react";
2
+ import { Text } from "react-native";
3
+ import { render, waitFor } from "@testing-library/react-native";
4
+ import { ScreenFeedLoader } from "../ScreenFeedLoader";
5
+
6
+ const mockUseFeedLoader = jest.fn();
7
+ const mockUseScreenContextV2 = jest.fn();
8
+ const mockSetState = jest.fn();
9
+
10
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks", () => ({
11
+ useFeedLoader: (...args) => mockUseFeedLoader(...args),
12
+ }));
13
+
14
+ jest.mock(
15
+ "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext",
16
+ () => ({
17
+ useScreenContextV2: (...args) => mockUseScreenContextV2(...args),
18
+ })
19
+ );
20
+
21
+ describe("ScreenFeedLoader", () => {
22
+ beforeEach(() => {
23
+ jest.clearAllMocks();
24
+
25
+ mockUseScreenContextV2.mockReturnValue({
26
+ _feedStore: {
27
+ setState: mockSetState,
28
+ },
29
+ });
30
+ });
31
+
32
+ it("hides children while loading", () => {
33
+ mockUseFeedLoader.mockReturnValue({
34
+ data: null,
35
+ loading: true,
36
+ error: null,
37
+ });
38
+
39
+ const { queryByText } = render(
40
+ <ScreenFeedLoader id="test" feedData={{ source: "url", mapping: {} }}>
41
+ <Text>child</Text>
42
+ </ScreenFeedLoader>
43
+ );
44
+
45
+ expect(queryByText("child")).toBeNull();
46
+ });
47
+
48
+ it("writes loaded feed data to _feedStore", async () => {
49
+ const data = { entry: { id: "1" } };
50
+
51
+ mockUseFeedLoader.mockReturnValue({
52
+ data,
53
+ loading: false,
54
+ error: null,
55
+ });
56
+
57
+ render(
58
+ <ScreenFeedLoader id="test" feedData={{ source: "url", mapping: {} }}>
59
+ <Text>child</Text>
60
+ </ScreenFeedLoader>
61
+ );
62
+
63
+ await waitFor(() => {
64
+ expect(mockSetState).toHaveBeenCalledWith({
65
+ screenFeed: data,
66
+ screenFeedError: null,
67
+ });
68
+ });
69
+ });
70
+
71
+ it("writes feed error to _feedStore", async () => {
72
+ const error = new Error("feed failed");
73
+ const data = { fallback: true };
74
+
75
+ mockUseFeedLoader.mockReturnValue({
76
+ data,
77
+ loading: false,
78
+ error,
79
+ });
80
+
81
+ render(
82
+ <ScreenFeedLoader id="test" feedData={{ source: "url", mapping: {} }}>
83
+ <Text>child</Text>
84
+ </ScreenFeedLoader>
85
+ );
86
+
87
+ await waitFor(() => {
88
+ expect(mockSetState).toHaveBeenCalledWith({
89
+ screenFeed: data,
90
+ screenFeedError: error,
91
+ });
92
+ });
93
+ });
94
+ });
@@ -0,0 +1 @@
1
+ export { ScreenFeedLoader } from "./ScreenFeedLoader";
@@ -53,6 +53,9 @@ const mockComponents = { ScreenType1, ScreenType2, PlayerController };
53
53
 
54
54
  const mockState = {
55
55
  components: mockComponents,
56
+ remoteConfigurations: {
57
+ assets: {},
58
+ },
56
59
  plugins: [
57
60
  mockScreenType3,
58
61
  mockScreenType4,
@@ -127,6 +130,21 @@ const getWrapper = (screenId, screenType, screenData) => {
127
130
  );
128
131
  };
129
132
 
133
+ const getWrappedWrapper = (screenId, screenType, screenData) => {
134
+ const ScreenResolver = require("../").ScreenResolver;
135
+
136
+ return renderWithProviders(
137
+ <ScreenResolver
138
+ {...{
139
+ screenId,
140
+ screenType,
141
+ screenData,
142
+ }}
143
+ />,
144
+ mockState
145
+ );
146
+ };
147
+
130
148
  describe("<ScreenResolver />", () => {
131
149
  it("renders correctly", () => {
132
150
  const wrapper = getWrapper("1234", "screen_type_1", {});
@@ -134,6 +152,12 @@ describe("<ScreenResolver />", () => {
134
152
  expect(wrapper.getByTestId("screen_type_1")).toBeDefined();
135
153
  });
136
154
 
155
+ it("renders correctly when wrapped with default screen context", () => {
156
+ const wrapper = getWrappedWrapper("1234", "screen_type_1", {});
157
+
158
+ expect(wrapper.getByTestId("screen_type_1")).toBeDefined();
159
+ });
160
+
137
161
  it("picks screen from plugins if it exists", () => {
138
162
  const wrapper = getWrapper("A1234", "screen_type_3", {});
139
163
 
@@ -0,0 +1,3 @@
1
+ export { useGetComponent } from "./useGetComponent";
2
+
3
+ export { useScreenComponentResolver } from "./useScreenComponentResolver";
@@ -0,0 +1,15 @@
1
+ import * as React from "react";
2
+
3
+ import { toPascalCase } from "@applicaster/zapp-react-native-utils/stringUtils";
4
+ import {
5
+ useAppSelector,
6
+ selectComponents,
7
+ } from "@applicaster/zapp-react-native-redux";
8
+
9
+ export const useGetComponent = (screenType) => {
10
+ const components = useAppSelector(selectComponents);
11
+
12
+ return React.useMemo(() => {
13
+ return components[toPascalCase(screenType)];
14
+ }, [components, screenType]);
15
+ };
@@ -0,0 +1,90 @@
1
+ import * as React from "react";
2
+ import { path, prop } from "ramda";
3
+ import {
4
+ findPluginByType,
5
+ findPluginByIdentifier,
6
+ } from "@applicaster/zapp-react-native-utils/pluginUtils";
7
+ import { HandlePlayable } from "../../HandlePlayable";
8
+ import { HookRenderer } from "../../HookRenderer";
9
+ import { LinkHandler } from "../../LinkHandler";
10
+ import { Favorites } from "../../Favorites";
11
+ import { usePlugins } from "@applicaster/zapp-react-native-redux/hooks";
12
+ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
13
+
14
+ import { useCallbackActions } from "@applicaster/zapp-react-native-utils/zappFrameworkUtils/HookCallback/useCallbackActions";
15
+ import { useGetComponent } from "./useGetComponent";
16
+ import { getScreenTypeProps } from "../utils";
17
+
18
+ export enum PresentationType {
19
+ Standalone = "Standalone",
20
+ Hook = "Hook",
21
+ }
22
+
23
+ const screenTypeComponents = {
24
+ favorites: Favorites,
25
+ link: LinkHandler,
26
+ playable: HandlePlayable,
27
+ hooks: HookRenderer,
28
+ };
29
+
30
+ export const useScreenComponentResolver = (screenType, props) => {
31
+ const plugins = usePlugins();
32
+ const { hookPlugin } = props.screenData || {};
33
+ const component = useGetComponent(screenType);
34
+
35
+ const screenAction = useCallbackActions(
36
+ hookPlugin || props.screenData,
37
+ props.screenData.callback
38
+ );
39
+
40
+ const {
41
+ videoModalState: { mode },
42
+ } = useNavigation();
43
+
44
+ const componentProps = {
45
+ ...props,
46
+ mode,
47
+ screenAction,
48
+ };
49
+
50
+ const ScreenTypeComponent = screenTypeComponents?.[screenType];
51
+
52
+ if (ScreenTypeComponent) {
53
+ return (
54
+ <ScreenTypeComponent
55
+ {...getScreenTypeProps(screenType, componentProps)}
56
+ />
57
+ );
58
+ }
59
+
60
+ const ScreenPlugin =
61
+ findPluginByType(screenType, plugins, { skipWarning: true }) ||
62
+ findPluginByIdentifier(screenType, plugins) ||
63
+ findPluginByIdentifier(hookPlugin && hookPlugin.identifier, plugins) ||
64
+ component;
65
+
66
+ const ScreenComponent =
67
+ path(["module", "Component"], ScreenPlugin) ||
68
+ prop("module", ScreenPlugin) ||
69
+ prop("Component", ScreenPlugin) ||
70
+ ScreenPlugin;
71
+
72
+ const configuration =
73
+ prop("configuration", ScreenPlugin) ||
74
+ prop("__plugin_configuration", ScreenComponent);
75
+
76
+ if (!ScreenComponent) {
77
+ return null;
78
+ }
79
+
80
+ return (
81
+ <ScreenComponent
82
+ {...props}
83
+ callback={props.resultCallback || screenAction}
84
+ screenId={props.screenId}
85
+ screenData={props.screenData}
86
+ presentationType={PresentationType.Standalone}
87
+ configuration={configuration}
88
+ />
89
+ );
90
+ };
@@ -1,22 +1,17 @@
1
1
  import * as React from "react";
2
- import { path, prop } from "ramda";
3
- import {
4
- findPluginByType,
5
- findPluginByIdentifier,
6
- } from "@applicaster/zapp-react-native-utils/pluginUtils";
7
- import { HandlePlayable } from "../HandlePlayable";
8
- import { toPascalCase } from "@applicaster/zapp-react-native-utils/stringUtils";
9
- import { HookRenderer } from "../HookRenderer";
10
- import { LinkHandler } from "../LinkHandler";
11
- import { Favorites } from "../Favorites";
12
- import { ZappPipesScreenContext } from "../../Contexts";
2
+
13
3
  import { componentsLogger } from "../../Helpers/logger";
14
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
15
- import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
4
+
16
5
  import { useScreenAnalytics } from "@applicaster/zapp-react-native-utils/analyticsUtils/helpers/hooks";
17
6
 
18
- import { useCallbackActions } from "@applicaster/zapp-react-native-utils/zappFrameworkUtils/HookCallback/useCallbackActions";
19
7
  import { ScreenResultCallback } from "@applicaster/zapp-react-native-utils/zappFrameworkUtils/HookCallback/callbackNavigationAction";
8
+ import { useScreenComponentResolver } from "./hooks/useScreenComponentResolver";
9
+ import { withDefaultScreenContext } from "./withDefaultScreenContext";
10
+
11
+ export enum PresentationType {
12
+ Standalone = "Standalone",
13
+ Hook = "Hook",
14
+ }
20
15
 
21
16
  const logger = componentsLogger.addSubsystem("ScreenResolver");
22
17
 
@@ -37,103 +32,14 @@ type Props = {
37
32
  groupId?: string;
38
33
  };
39
34
 
40
- export enum PresentationType {
41
- Standalone = "Standalone",
42
- Hook = "Hook",
43
- }
44
-
45
35
  export function ScreenResolverComponent(props: Props) {
46
- useScreenAnalytics(props);
47
-
48
- const { screenType, screenId, screenData, groupId } = props;
49
-
50
- const { hookPlugin } = screenData || {};
51
-
52
- const { components, plugins, rivers } = usePickFromState([
53
- "components",
54
- "plugins",
55
- "rivers",
56
- ]);
57
-
58
- const {
59
- videoModalState: { mode },
60
- } = useNavigation();
36
+ const { screenType } = props;
37
+ const component = useScreenComponentResolver(screenType, props);
61
38
 
62
- const [, setScreenContext] = ZappPipesScreenContext.useZappPipesContext();
63
-
64
- React.useEffect(() => {
65
- setScreenContext(rivers[screenId]);
66
- }, [rivers, screenId, setScreenContext]);
67
-
68
- const parentCallback = props.resultCallback;
69
-
70
- const screenAction = useCallbackActions(
71
- hookPlugin || screenData,
72
- screenData.callback
73
- );
74
-
75
- const callbackAction = parentCallback || screenAction;
76
-
77
- const ScreenPlugin =
78
- findPluginByType(screenType, plugins, { skipWarning: true }) ||
79
- findPluginByIdentifier(screenType, plugins) ||
80
- findPluginByIdentifier(hookPlugin && hookPlugin.identifier, plugins) ||
81
- components[toPascalCase(screenType)];
82
-
83
- if (screenType === "favorites") {
84
- return <Favorites screenData={screenData} />;
85
- }
86
-
87
- if (screenType === "link") {
88
- return <LinkHandler screenData={screenData} />;
89
- }
90
-
91
- if (screenType === "playable") {
92
- return (
93
- // @ts-ignore
94
- <HandlePlayable
95
- item={screenData}
96
- mode={mode === "PIP" ? "PIP" : "FULLSCREEN"}
97
- isModal={false}
98
- groupId={groupId}
99
- />
100
- );
101
- }
102
-
103
- if (hookPlugin || screenType === "hooks") {
104
- return (
105
- screenData && (
106
- <HookRenderer
107
- callback={callbackAction}
108
- screenData={screenData}
109
- focused={props.focused}
110
- parentFocus={props.parentFocus as ParentFocus}
111
- />
112
- )
113
- );
114
- }
115
-
116
- const ScreenComponent =
117
- path(["module", "Component"], ScreenPlugin) ||
118
- prop("module", ScreenPlugin) ||
119
- prop("Component", ScreenPlugin) ||
120
- ScreenPlugin;
121
-
122
- const configuration =
123
- prop("configuration", ScreenPlugin) ||
124
- prop("__plugin_configuration", ScreenComponent);
39
+ useScreenAnalytics(props);
125
40
 
126
- if (ScreenComponent) {
127
- return (
128
- <ScreenComponent
129
- {...props}
130
- callback={callbackAction}
131
- screenId={screenId}
132
- screenData={screenData}
133
- configuration={configuration}
134
- presentationType={PresentationType.Standalone}
135
- />
136
- );
41
+ if (component) {
42
+ return component;
137
43
  }
138
44
 
139
45
  logger.warning({
@@ -144,6 +50,4 @@ export function ScreenResolverComponent(props: Props) {
144
50
  return null;
145
51
  }
146
52
 
147
- export const ScreenResolver = ZappPipesScreenContext.withProvider(
148
- ScreenResolverComponent
149
- );
53
+ export const ScreenResolver = withDefaultScreenContext(ScreenResolverComponent);
@@ -0,0 +1,45 @@
1
+ import { getScreenTypeProps } from "../getScreenTypeProps";
2
+
3
+ const baseProps = {
4
+ screenData: { id: "entry-1" },
5
+ mode: "PIP",
6
+ screenId: "screen-1",
7
+ groupId: "group-1",
8
+ focused: true,
9
+ parentFocus: { nextFocusDown: { current: null } },
10
+ screenAction: jest.fn(),
11
+ resultCallback: null,
12
+ };
13
+
14
+ describe("getScreenTypeProps", () => {
15
+ it("returns props for favorites/link", () => {
16
+ expect(getScreenTypeProps("favorites", baseProps)).toEqual({
17
+ screenData: baseProps.screenData,
18
+ });
19
+
20
+ expect(getScreenTypeProps("link", baseProps)).toEqual({
21
+ screenData: baseProps.screenData,
22
+ });
23
+ });
24
+
25
+ it("returns props for playable", () => {
26
+ expect(getScreenTypeProps("playable", baseProps)).toEqual({
27
+ item: baseProps.screenData,
28
+ mode: "PIP",
29
+ isModal: false,
30
+ groupId: "group-1",
31
+ });
32
+ });
33
+
34
+ it("returns props for hooks", () => {
35
+ const result = getScreenTypeProps("hooks", baseProps);
36
+
37
+ expect(result).toMatchObject({
38
+ screenData: baseProps.screenData,
39
+ focused: true,
40
+ parentFocus: baseProps.parentFocus,
41
+ });
42
+
43
+ expect(result.callback).toBe(baseProps.screenAction);
44
+ });
45
+ });
@@ -0,0 +1,43 @@
1
+ export const getScreenTypeProps = (
2
+ screenType: "favorites" | "link" | "playable" | "hooks",
3
+ props
4
+ ) => {
5
+ const {
6
+ screenData,
7
+ mode,
8
+ screenId,
9
+ groupId,
10
+ focused,
11
+ parentFocus,
12
+ screenAction,
13
+ resultCallback,
14
+ } = props;
15
+
16
+ switch (screenType) {
17
+ case "favorites":
18
+ case "link":
19
+ return {
20
+ screenData,
21
+ };
22
+ case "playable":
23
+ return {
24
+ item: screenData,
25
+ mode: mode === "PIP" ? "PIP" : "FULLSCREEN",
26
+ isModal: false,
27
+ groupId: groupId,
28
+ };
29
+ case "hooks":
30
+ return {
31
+ screenData,
32
+ callback: resultCallback || screenAction,
33
+ focused,
34
+ parentFocus: parentFocus as ParentFocus,
35
+ };
36
+ default:
37
+ return {
38
+ callback: resultCallback || screenAction,
39
+ screenId: screenId,
40
+ screenData,
41
+ };
42
+ }
43
+ };
@@ -0,0 +1 @@
1
+ export { getScreenTypeProps } from "./getScreenTypeProps";
@@ -0,0 +1,16 @@
1
+ import * as React from "react";
2
+ import { useRivers } from "@applicaster/zapp-react-native-utils/reactHooks";
3
+ import { ZappPipesScreenContext } from "../../Contexts";
4
+
5
+ export function withDefaultScreenContext(Component: React.ComponentType<any>) {
6
+ return function WithDefaultScreenContext(props: any) {
7
+ const screenId = props.screenId;
8
+ const rivers = useRivers();
9
+
10
+ return (
11
+ <ZappPipesScreenContext.Provider initialContextValue={rivers[screenId]}>
12
+ <Component {...props} />
13
+ </ZappPipesScreenContext.Provider>
14
+ );
15
+ };
16
+ }
@@ -0,0 +1,25 @@
1
+ import React from "react";
2
+ import { ScreenFeedLoader } from "../ScreenFeedLoader/ScreenFeedLoader";
3
+
4
+ /** Resolves screen-feed for a given screen `id` by using the provided `useFeedData` hook */
5
+ export const ScreenResolverFeedProvider = ({
6
+ id,
7
+ children,
8
+ useFeedData,
9
+ }: {
10
+ id: string;
11
+ children: React.ReactNode;
12
+ useFeedData: (id: string) => Option<ZappDataSource>;
13
+ }) => {
14
+ const feedData = useFeedData(id);
15
+
16
+ if (feedData?.source) {
17
+ return (
18
+ <ScreenFeedLoader id={id} feedData={feedData}>
19
+ {children}
20
+ </ScreenFeedLoader>
21
+ );
22
+ } else {
23
+ return <>{children}</>;
24
+ }
25
+ };
@@ -0,0 +1,44 @@
1
+ import React from "react";
2
+ import { Text } from "react-native";
3
+ import { render } from "@testing-library/react-native";
4
+ import { ScreenResolverFeedProvider } from "../ScreenResolverFeedProvider";
5
+
6
+ jest.mock("../../ScreenFeedLoader/ScreenFeedLoader", () => ({
7
+ ScreenFeedLoader: ({ children }) => {
8
+ const React = require("react");
9
+ const { View } = require("react-native");
10
+
11
+ return <View testID="feed-loader">{children}</View>;
12
+ },
13
+ }));
14
+
15
+ describe("ScreenResolverFeedProvider", () => {
16
+ it("renders ScreenFeedLoader when screen feed source exists", () => {
17
+ const useFeedData = jest.fn(() => ({
18
+ source: "https://feed",
19
+ mapping: {},
20
+ }));
21
+
22
+ const { getByTestId, getByText } = render(
23
+ <ScreenResolverFeedProvider id="screen-1" useFeedData={useFeedData}>
24
+ <Text>content</Text>
25
+ </ScreenResolverFeedProvider>
26
+ );
27
+
28
+ expect(getByTestId("feed-loader")).toBeDefined();
29
+ expect(getByText("content")).toBeDefined();
30
+ });
31
+
32
+ it("renders children directly when screen feed source is missing", () => {
33
+ const useFeedData = jest.fn(() => ({}));
34
+
35
+ const { queryByTestId, getByText } = render(
36
+ <ScreenResolverFeedProvider id="screen-1" useFeedData={useFeedData}>
37
+ <Text>content</Text>
38
+ </ScreenResolverFeedProvider>
39
+ );
40
+
41
+ expect(queryByTestId("feed-loader")).toBeNull();
42
+ expect(getByText("content")).toBeDefined();
43
+ });
44
+ });
@@ -0,0 +1 @@
1
+ export { ScreenResolverFeedProvider } from "./ScreenResolverFeedProvider";