@applicaster/zapp-react-native-utils 14.0.0-rc.39 → 14.0.0-rc.40

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,130 @@
1
+ import { mapContentTypesToRivers } from "../index";
2
+
3
+ describe("mapContentTypesToRivers", () => {
4
+ it("should return the correct content types mapped to rivers", () => {
5
+ const state = {
6
+ rivers: {
7
+ "river-1": {
8
+ plugin_type: "river",
9
+ },
10
+ },
11
+ contentTypes: {
12
+ "content-type-1": {
13
+ screen_id: "river-1",
14
+ },
15
+ },
16
+ };
17
+
18
+ const result = mapContentTypesToRivers(state);
19
+
20
+ expect(result).toEqual({
21
+ "content-type-1": {
22
+ screenType: "river",
23
+ screen_id: "river-1",
24
+ },
25
+ });
26
+ });
27
+
28
+ it("should return null if contentTypes is undefined", () => {
29
+ const state = {
30
+ rivers: {
31
+ "river-1": {
32
+ plugin_type: "river",
33
+ },
34
+ },
35
+ // contentTypes is missing
36
+ };
37
+
38
+ const result = mapContentTypesToRivers(state);
39
+
40
+ expect(result).toBeNull();
41
+ });
42
+
43
+ it("should skip content types whose screen does not exist in rivers", () => {
44
+ const state = {
45
+ rivers: {
46
+ "river-1": {
47
+ plugin_type: "river",
48
+ },
49
+ },
50
+ contentTypes: {
51
+ "content-type-1": {
52
+ screen_id: "river-1",
53
+ },
54
+ "content-type-2": {
55
+ screen_id: "river-2", // river-2 does not exist
56
+ },
57
+ },
58
+ };
59
+
60
+ const result = mapContentTypesToRivers(state);
61
+
62
+ expect(result).toEqual({
63
+ "content-type-1": {
64
+ screenType: "river",
65
+ screen_id: "river-1",
66
+ },
67
+ });
68
+
69
+ // result is not null, but may be undefined for missing keys
70
+ expect(result && result["content-type-2"]).toBeUndefined();
71
+ });
72
+
73
+ it("should use 'type' if 'plugin_type' is not present in river", () => {
74
+ const state = {
75
+ rivers: {
76
+ "river-1": {
77
+ type: "custom-type",
78
+ },
79
+ },
80
+ contentTypes: {
81
+ "content-type-1": {
82
+ screen_id: "river-1",
83
+ },
84
+ },
85
+ };
86
+
87
+ const result = mapContentTypesToRivers(state);
88
+
89
+ expect(result).toEqual({
90
+ "content-type-1": {
91
+ screenType: "custom-type",
92
+ screen_id: "river-1",
93
+ },
94
+ });
95
+ });
96
+
97
+ it("should skip content types if neither plugin_type nor type is present in river", () => {
98
+ const state = {
99
+ rivers: {
100
+ "river-1": {
101
+ // no plugin_type or type
102
+ },
103
+ },
104
+ contentTypes: {
105
+ "content-type-1": {
106
+ screen_id: "river-1",
107
+ },
108
+ },
109
+ };
110
+
111
+ const result = mapContentTypesToRivers(state);
112
+
113
+ expect(result).toEqual({});
114
+ });
115
+
116
+ it("should handle empty contentTypes object", () => {
117
+ const state = {
118
+ rivers: {
119
+ "river-1": {
120
+ plugin_type: "river",
121
+ },
122
+ },
123
+ contentTypes: {},
124
+ };
125
+
126
+ const result = mapContentTypesToRivers(state);
127
+
128
+ expect(result).toEqual({});
129
+ });
130
+ });
@@ -13,6 +13,7 @@ import {
13
13
  isPlayable,
14
14
  isV2River,
15
15
  } from "./itemTypeMatchers";
16
+ import { RootState } from "@applicaster/zapp-react-native-redux/store";
16
17
 
17
18
  type PathAttribute = {
18
19
  screenType: string;
@@ -377,10 +378,11 @@ export const usesVideoModal = (
377
378
  return targetScreenConfiguration?.styles?.use_video_modal;
378
379
  };
379
380
 
380
- export const mapContentTypesToRivers = ({
381
- rivers,
382
- contentTypes,
383
- }): ZappContentTypesMapped | null => {
381
+ export const mapContentTypesToRivers = (
382
+ state: Partial<RootState>
383
+ ): ZappContentTypesMapped | null => {
384
+ const { rivers, contentTypes } = state;
385
+
384
386
  if (!contentTypes) {
385
387
  return null;
386
388
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "14.0.0-rc.39",
3
+ "version": "14.0.0-rc.40",
4
4
  "description": "Applicaster Zapp React Native utilities package",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "homepage": "https://github.com/applicaster/quickbrick#readme",
29
29
  "dependencies": {
30
- "@applicaster/applicaster-types": "14.0.0-rc.39",
30
+ "@applicaster/applicaster-types": "14.0.0-rc.40",
31
31
  "buffer": "^5.2.1",
32
32
  "camelize": "^1.0.0",
33
33
  "dayjs": "^1.11.10",
@@ -23,7 +23,9 @@ jest.mock(
23
23
 
24
24
  jest.useFakeTimers();
25
25
 
26
- jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation");
26
+ jest.mock(
27
+ "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation"
28
+ );
27
29
 
28
30
  const mockStore = configureStore();
29
31
 
@@ -1,8 +1,10 @@
1
1
  import { complement, compose, isNil, map, min, prop, take, uniq } from "ramda";
2
- import { useDispatch } from "react-redux";
3
2
  import * as React from "react";
4
- import { useZappPipesFeeds } from "@applicaster/zapp-react-native-redux/hooks";
5
- import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
3
+ import {
4
+ ZappPipes,
5
+ useAppDispatch,
6
+ useZappPipesFeed,
7
+ } from "@applicaster/zapp-react-native-redux";
6
8
  import { isNilOrEmpty } from "../../reactUtils/helpers";
7
9
  import { ZappPipesSearchContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
8
10
  import {
@@ -63,7 +65,7 @@ export const useBatchLoading = (
63
65
  componentsToRender: { data?: ZappDataSource; component_type: string }[],
64
66
  options: Options
65
67
  ) => {
66
- const dispatch = useDispatch();
68
+ const dispatch = useAppDispatch();
67
69
  const { screen: screenContext, entry: entryContext } = useScreenContext();
68
70
  const [searchContext] = ZappPipesSearchContext.useZappPipesContext();
69
71
  const [hasEverBeenReady, setHasEverBeenReady] = React.useState(false);
@@ -118,7 +120,7 @@ export const useBatchLoading = (
118
120
  []
119
121
  );
120
122
 
121
- const feeds = useZappPipesFeeds(feedUrls);
123
+ const feeds = useZappPipesFeed(feedUrls);
122
124
 
123
125
  // dispatch loadPipesData for each feed that is not loaded
124
126
  const runBatchLoading = React.useCallback(() => {
@@ -139,7 +141,7 @@ export const useBatchLoading = (
139
141
  if (mappedFeedUrl) {
140
142
  // 4. load data
141
143
  return dispatch(
142
- loadPipesData(mappedFeedUrl, { riverId: options.riverId })
144
+ ZappPipes.loadPipesData(mappedFeedUrl, { riverId: options.riverId })
143
145
  );
144
146
  }
145
147
  }
@@ -1,8 +1,10 @@
1
1
  import React, { useEffect } from "react";
2
- import { useDispatch } from "react-redux";
3
2
 
4
- import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
5
- import { useZappPipesFeed } from "@applicaster/zapp-react-native-redux/hooks";
3
+ import {
4
+ ZappPipes,
5
+ useAppDispatch,
6
+ useZappPipesFeed,
7
+ } from "@applicaster/zapp-react-native-redux";
6
8
 
7
9
  import { reactHooksLogger } from "../logger";
8
10
  import { shouldDispatchData, useIsInitialRender } from "../utils";
@@ -49,7 +51,7 @@ export const useFeedLoader = ({
49
51
  }, []);
50
52
 
51
53
  const isInitialRender = useIsInitialRender();
52
- const dispatch = useDispatch();
54
+ const dispatch = useAppDispatch();
53
55
  const { screenData } = useRoute();
54
56
 
55
57
  const callableFeedUrl = useInflatedUrl({ feedUrl, mapping });
@@ -64,7 +66,7 @@ export const useFeedLoader = ({
64
66
  (silentRefresh = true, callback) => {
65
67
  if (callableFeedUrl) {
66
68
  dispatch(
67
- loadPipesData(callableFeedUrl, {
69
+ ZappPipes.loadPipesData(callableFeedUrl, {
68
70
  clearCache: true,
69
71
  silentRefresh,
70
72
  callback,
@@ -82,7 +84,7 @@ export const useFeedLoader = ({
82
84
 
83
85
  if (nextFeed) {
84
86
  dispatch(
85
- loadPipesData(nextFeed, {
87
+ ZappPipes.loadPipesData(nextFeed, {
86
88
  silentRefresh: true,
87
89
  parentFeed: callableFeedUrl,
88
90
  riverId,
@@ -98,7 +100,7 @@ export const useFeedLoader = ({
98
100
  ) {
99
101
  if (callableFeedUrl && !pipesOptions.skipLoading) {
100
102
  dispatch(
101
- loadPipesData(callableFeedUrl, {
103
+ ZappPipes.loadPipesData(callableFeedUrl, {
102
104
  ...pipesOptions,
103
105
  clearCache: true,
104
106
  riverId,
@@ -131,7 +133,9 @@ export const useFeedLoader = ({
131
133
  // Reload feed when feedUrl changes, unless skipLoading is true
132
134
  useEffect(() => {
133
135
  if (!isInitialRender && callableFeedUrl && !pipesOptions.skipLoading) {
134
- dispatch(loadPipesData(callableFeedUrl, { ...pipesOptions, riverId }));
136
+ dispatch(
137
+ ZappPipes.loadPipesData(callableFeedUrl, { ...pipesOptions, riverId })
138
+ );
135
139
  }
136
140
  }, [callableFeedUrl]);
137
141
 
@@ -1,11 +1,11 @@
1
1
  import React from "react";
2
- import { useDispatch } from "react-redux";
3
2
 
4
3
  import { getDatasourceUrl } from "@applicaster/zapp-react-native-ui-components/Decorators/RiverFeedLoader/utils/getDatasourceUrl";
5
4
  import { usePipesContexts } from "@applicaster/zapp-react-native-ui-components/Decorators/RiverFeedLoader/utils/usePipesContexts";
6
5
  import { clearPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
7
6
 
8
7
  import { useRoute } from "../navigation";
8
+ import { useAppDispatch } from "@applicaster/zapp-react-native-redux";
9
9
 
10
10
  /**
11
11
  * reset river components cache when screen is unmounted
@@ -13,7 +13,7 @@ import { useRoute } from "../navigation";
13
13
  * @param {Array} riverComponents list of UI components
14
14
  */
15
15
  export const usePipesCacheReset = (riverId, riverComponents) => {
16
- const dispatch = useDispatch();
16
+ const dispatch = useAppDispatch();
17
17
  const { screenData, pathname } = useRoute();
18
18
  const pipesContexts = usePipesContexts(riverId, pathname);
19
19
 
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import * as R from "ramda";
3
- import { View } from "react-native";
3
+ import { View, ViewStyle } from "react-native";
4
4
 
5
5
  import { platformSelect } from "../../reactUtils";
6
6
 
@@ -49,13 +49,13 @@ export const useSequentialRenderItem = (data: Data) => {
49
49
  const readyToDisplay =
50
50
  index === 0 ? true : arePreviousComponentsReady(index);
51
51
 
52
- const displayStyle = {
52
+ const displayStyle: ViewStyle = {
53
53
  display: readyToDisplay ? "flex" : "none",
54
54
  };
55
55
 
56
56
  const readyStyle = {
57
57
  visibility: readyToDisplay ? "visible" : "hidden",
58
- };
58
+ } as ViewStyle;
59
59
 
60
60
  const style = platformSelect({
61
61
  tvos: readyStyle,
@@ -42,15 +42,17 @@ jest.mock("react-native-safe-area-context", () => ({
42
42
  }));
43
43
 
44
44
  jest.mock("../../../reactUtils", () => ({
45
+ ...jest.requireActual("../../../reactUtils"),
45
46
  platformSelect: jest.fn((specs) => specs[platform] || specs.default),
46
47
  isTV: jest.fn(() => mock_tv_flag),
47
48
  }));
48
49
 
49
50
  jest.mock("../../navigation", () => ({
50
- useNavigation: () => null,
51
51
  useIsScreenActive: () => true,
52
52
  }));
53
53
 
54
+ jest.mock("../../navigation/useNavigation");
55
+
54
56
  const { Dimensions } = require("react-native");
55
57
  const { useDimensions } = require("..");
56
58
 
@@ -1,46 +1,48 @@
1
1
  import { renderHook } from "@testing-library/react-hooks";
2
2
  import { Dimensions, StatusBar } from "react-native";
3
+ import { useDimensions } from "../useDimensions";
4
+ import { usePickFromState } from "@applicaster/zapp-react-native-redux";
3
5
 
4
- const mockUsePickFromState = jest.fn();
5
- const mockUseIsScreenActive = jest.fn();
6
- const mockGetInitialDimensions = jest.fn();
7
- const mockGetDeviceInfo = jest.fn();
6
+ import { useIsScreenActive } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useIsScreenActive";
8
7
 
9
- jest.mock("@applicaster/zapp-react-native-redux/hooks", () => ({
10
- ...(jest.requireActual("@applicaster/zapp-react-native-redux/hooks") as {}),
11
- usePickFromState: mockUsePickFromState,
12
- }));
13
-
14
- jest.mock("../../../navigation", () => ({
15
- useIsScreenActive: mockUseIsScreenActive,
16
- }));
8
+ jest.mock("@applicaster/zapp-react-native-redux/hooks", () => {
9
+ return {
10
+ ...jest.requireActual("@applicaster/zapp-react-native-redux/hooks"),
11
+ usePickFromState: jest.fn(),
12
+ };
13
+ });
17
14
 
18
- jest.mock("../helpers", () => ({
19
- getInitialDimensions: mockGetInitialDimensions,
15
+ jest.mock(
16
+ "@applicaster/zapp-react-native-utils/reactHooks/navigation/useIsScreenActive",
17
+ () => ({
18
+ useIsScreenActive: jest.fn().mockReturnValue(true),
19
+ })
20
+ );
21
+
22
+ jest.doMock("../helpers", () => ({
23
+ getInitialDimensions: jest
24
+ .fn()
25
+ .mockReturnValue({ width: 100, height: 200, scale: 1, fontScale: 1 }),
20
26
  }));
21
27
 
22
28
  jest.mock("../../getDeviceInfo", () => ({
23
- getDeviceInfo: mockGetDeviceInfo,
29
+ getDeviceInfo: jest.fn().mockReturnValue({ deviceInfo: "testDeviceInfo" }),
24
30
  }));
25
31
 
26
- const { useDimensions } = require("../useDimensions");
32
+ const mockDimensions = { width: 100, height: 200, scale: 1, fontScale: 1 };
33
+
34
+ Dimensions.get = jest.fn().mockReturnValue(mockDimensions);
35
+
36
+ Dimensions.addEventListener = jest.fn().mockReturnValue({
37
+ remove: jest.fn(),
38
+ });
27
39
 
28
40
  describe("useDimensions", () => {
29
- const mockDimensions = { width: 100, height: 200, scale: 1, fontScale: 1 };
30
41
  const mockAppData = { someData: "test" };
31
42
 
32
43
  beforeEach(() => {
33
- jest.clearAllMocks();
34
- Dimensions.get = jest.fn().mockReturnValue(mockDimensions);
35
-
36
- Dimensions.addEventListener = jest.fn().mockReturnValue({
37
- remove: jest.fn(),
38
- });
39
-
40
- mockUsePickFromState.mockReturnValue({ appData: mockAppData });
41
- mockUseIsScreenActive.mockReturnValue(true);
42
- mockGetInitialDimensions.mockReturnValue(mockDimensions);
43
- mockGetDeviceInfo.mockReturnValue({ deviceInfo: "testDeviceInfo" });
44
+ StatusBar.currentHeight = 20;
45
+ (usePickFromState as jest.Mock).mockReturnValue({ appData: mockAppData });
44
46
  });
45
47
 
46
48
  it("returns correct initial dimensions", () => {
@@ -48,12 +50,9 @@ describe("useDimensions", () => {
48
50
  useDimensions("window", { fullDimensions: false })
49
51
  );
50
52
 
51
- expect(result.current).toEqual({
52
- ...mockDimensions,
53
+ expect(result.current).toMatchObject({
53
54
  statusBarHeight: StatusBar.currentHeight,
54
55
  });
55
-
56
- expect(mockGetInitialDimensions).toHaveBeenCalledWith("window");
57
56
  });
58
57
 
59
58
  it("calls handler on mount", () => {
@@ -70,7 +69,7 @@ describe("useDimensions", () => {
70
69
  useDimensions("window", { fullDimensions: false })
71
70
  );
72
71
 
73
- mockUseIsScreenActive.mockReturnValue(false);
72
+ (useIsScreenActive as jest.Mock).mockReturnValue(false);
74
73
  rerender();
75
74
 
76
75
  expect(Dimensions.addEventListener).toHaveBeenCalledWith(
@@ -84,8 +83,7 @@ describe("useDimensions", () => {
84
83
  useDimensions("window", { fullDimensions: true })
85
84
  );
86
85
 
87
- expect(result.current).toEqual({
88
- ...mockDimensions,
86
+ expect(result.current).toMatchObject({
89
87
  scale: 1,
90
88
  fontScale: 1,
91
89
  statusBarHeight: StatusBar.currentHeight,
@@ -98,7 +96,7 @@ describe("useDimensions", () => {
98
96
  );
99
97
 
100
98
  expect(result.current.height).toBe(
101
- mockDimensions.height - StatusBar.currentHeight ?? 0
99
+ mockDimensions.height - (StatusBar?.currentHeight ?? 0)
102
100
  );
103
101
  });
104
102
 
@@ -10,7 +10,7 @@ import { isTV } from "../../../reactUtils";
10
10
  import { Options, UseDimensions } from "../types";
11
11
  import { getDeviceInfo } from "../getDeviceInfo";
12
12
  import { getInitialDimensions } from "./helpers";
13
- import { useIsScreenActive } from "../../navigation";
13
+ import { useIsScreenActive } from "../../navigation/useIsScreenActive";
14
14
 
15
15
  function compensateForScaleIfNeeded(context) {
16
16
  return function () {
@@ -24,8 +24,6 @@ const applyScaleToDimensions = R.unless(R.propEq("scale", 1), (dimensions) => ({
24
24
  scale: 1,
25
25
  }));
26
26
 
27
- const statusBarHeight = StatusBar?.currentHeight;
28
-
29
27
  /**
30
28
  * Returns React-native Dimensions object and updates it on any dimension change
31
29
  * @param {('screen'|'window')} [context=window] - Dimensions context passed to Dimensions.get method
@@ -37,6 +35,7 @@ export const useDimensions: UseDimensions = (
37
35
  context = "window",
38
36
  fullDimensions = { fullDimensions: false, updateForInactiveScreens: true }
39
37
  ) => {
38
+ const statusBarHeight = StatusBar?.currentHeight;
40
39
  const isActive = useIsScreenActive();
41
40
  const { appData } = usePickFromState(["appData"]);
42
41
 
@@ -1,6 +1,8 @@
1
1
  /* eslint-disable no-redeclare */
2
- import { useSelector } from "react-redux";
3
- import * as R from "ramda";
2
+ import {
3
+ useAppSelector,
4
+ selectLayoutVersion,
5
+ } from "@applicaster/zapp-react-native-redux";
4
6
 
5
7
  export function useLayoutVersion(): ZappLayoutVersions;
6
8
 
@@ -23,9 +25,7 @@ export function useLayoutVersion({
23
25
  isV2?: boolean;
24
26
  isV1?: boolean;
25
27
  } = {}): boolean | ZappLayoutVersions {
26
- const layoutVersion = useSelector<any, ZappLayoutVersions>(
27
- R.path(["appData", "layoutVersion"])
28
- );
28
+ const layoutVersion = useAppSelector(selectLayoutVersion);
29
29
 
30
30
  if (isV2) {
31
31
  return layoutVersion === "v2";
@@ -14,6 +14,10 @@ jest.mock("@applicaster/zapp-react-native-utils/localizationUtils", () => ({
14
14
 
15
15
  jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation");
16
16
 
17
+ jest.mock(
18
+ "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation"
19
+ );
20
+
17
21
  const { useCellResolver } = require("../useCellResolver");
18
22
 
19
23
  describe("cellResolver", () => {
@@ -1,9 +1,8 @@
1
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
1
+ import {
2
+ useAppSelector,
3
+ selectRivers,
4
+ } from "@applicaster/zapp-react-native-redux";
2
5
 
3
- const riversSelector = ["rivers"];
4
-
5
- export const useRivers = () => {
6
- const { rivers } = usePickFromState(riversSelector as any);
7
-
8
- return rivers;
9
- };
6
+ export function useRivers(): Record<string, ZappRiver> {
7
+ return useAppSelector(selectRivers);
8
+ }
@@ -11,7 +11,7 @@ class BackgroundTimer {
11
11
  this.uniqueId = 0;
12
12
  this.callbacks = {};
13
13
 
14
- const EventEmitter = platformSelect({
14
+ const EventEmitter: typeof DeviceEventEmitter | undefined = platformSelect({
15
15
  android: DeviceEventEmitter,
16
16
  android_tv: DeviceEventEmitter,
17
17
  amazon: DeviceEventEmitter, // probably does not exist and uses android_tv
package/utils/index.ts CHANGED
@@ -14,6 +14,7 @@ export {
14
14
  flatMap,
15
15
  difference,
16
16
  take,
17
+ pick,
17
18
  map,
18
19
  trim,
19
20
  toString,