@applicaster/zapp-react-native-utils 12.0.0-alpha.4300857220 → 12.0.0-alpha.4355141911
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.
- package/analyticsUtils/AnalyticsEvents/index.ts +6 -0
- package/analyticsUtils/AnalyticsEvents/searchEvents.ts +21 -0
- package/analyticsUtils/events.ts +6 -0
- package/analyticsUtils/index.tsx +6 -0
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +3 -3
- package/appUtils/focusManager/__tests__/focusManager.test.js +4 -24
- package/appUtils/focusManager/__tests__/index.test.ts +3 -3
- package/appUtils/focusManager/index.ts +141 -56
- package/appUtils/focusManager/treeDataStructure/Utils/index.js +74 -43
- package/appUtils/focusManager/utils/index.ts +100 -0
- package/appUtils/playerManager/usePlayerControllerSetup.tsx +6 -1
- package/arrayUtils/__tests__/isFilledArray.test.ts +63 -0
- package/arrayUtils/index.ts +5 -0
- package/cellUtils/__tests__/cellUtils.test.ts +9 -20
- package/cellUtils/index.ts +6 -12
- package/dateUtils/index.ts +11 -0
- package/inflatedUrlUtils/index.ts +4 -4
- package/localizationUtils/__tests__/localizationUtils.test.ts +72 -53
- package/localizationUtils/index.ts +13 -22
- package/numberUtils/__tests__/isLikeNumber.test.ts +18 -0
- package/numberUtils/index.ts +9 -18
- package/package.json +2 -2
- package/reactHooks/cell-click/__tests__/index.test.js +10 -1
- package/reactHooks/cell-click/index.ts +12 -12
- package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +30 -70
- package/reactHooks/feed/__tests__/useInflatedUrl.test.ts +18 -3
- package/reactHooks/feed/useBuildPipesUrl.ts +7 -10
- package/reactHooks/feed/useInflatedUrl.ts +44 -15
- package/reactHooks/navigation/__tests__/index.test.tsx +11 -8
- package/reactHooks/navigation/index.ts +49 -66
- package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +21 -23
- package/reactHooks/screen/index.ts +2 -0
- package/reactHooks/screen/useScreenBackgroundColor.ts +23 -0
- package/reactHooks/screen/useScreenContext.ts +2 -2
- package/types.ts +4 -0
|
@@ -11,9 +11,9 @@ import {
|
|
|
11
11
|
} from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
12
12
|
import { ZappPipesEntryContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
|
|
13
13
|
import { toBooleanWithDefaultTrue } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
import {
|
|
14
|
+
import { ActionExecutorContext } from "@applicaster/zapp-react-native-utils/actionsExecutor/ActionExecutorContext";
|
|
15
|
+
|
|
16
|
+
import { isFunction, noop } from "../../functionUtils";
|
|
17
17
|
import { useSendAnalyticsOnPress } from "../analytics";
|
|
18
18
|
import { logOnPress, warnEmptyContentType } from "./helpers";
|
|
19
19
|
|
|
@@ -30,12 +30,12 @@ type Props = {
|
|
|
30
30
|
zappPipesData?: ZappPipesData;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
export const useCellClick = (
|
|
34
|
-
const { component, zappPipesData } = props;
|
|
33
|
+
export const useCellClick = ({ component, zappPipesData, item }: Props) => {
|
|
35
34
|
const { push, currentRoute } = useNavigation();
|
|
36
35
|
const { pathname } = useRoute();
|
|
37
|
-
|
|
38
|
-
const
|
|
36
|
+
|
|
37
|
+
const onCellTap: Option<Function> = React.useContext(CellTapContext);
|
|
38
|
+
const actionExecutor = React.useContext(ActionExecutorContext);
|
|
39
39
|
|
|
40
40
|
const cellSelectable = toBooleanWithDefaultTrue(
|
|
41
41
|
component?.rules?.component_cells_selectable
|
|
@@ -47,7 +47,7 @@ export const useCellClick = (props: Props) => {
|
|
|
47
47
|
const logTimestamp = useProfilerLogging();
|
|
48
48
|
|
|
49
49
|
const sendAnalyticsOnPress = useSendAnalyticsOnPress(
|
|
50
|
-
|
|
50
|
+
item,
|
|
51
51
|
component,
|
|
52
52
|
zappPipesData
|
|
53
53
|
);
|
|
@@ -56,7 +56,7 @@ export const useCellClick = (props: Props) => {
|
|
|
56
56
|
async (_item?: ZappEntry | any, _index?: number) => {
|
|
57
57
|
// Making sure we are not getting GestureResponderEvent in here.
|
|
58
58
|
const isZappEntry = _item?.id && _item?.type;
|
|
59
|
-
const selectedItem = isZappEntry ? _item :
|
|
59
|
+
const selectedItem = isZappEntry ? _item : item;
|
|
60
60
|
setEntryContext?.(selectedItem);
|
|
61
61
|
|
|
62
62
|
if (!selectedItem?.type?.value) {
|
|
@@ -80,10 +80,10 @@ export const useCellClick = (props: Props) => {
|
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
} else {
|
|
83
|
-
if (
|
|
84
|
-
onCellTap(selectedItem, _index);
|
|
83
|
+
if (isFunction(onCellTap)) {
|
|
84
|
+
onCellTap?.(selectedItem, _index);
|
|
85
85
|
} else {
|
|
86
|
-
if (currentRoute === pathname || pathname
|
|
86
|
+
if (currentRoute === pathname || pathname.includes("video-modal")) {
|
|
87
87
|
const targetScreen = component?.data?.target;
|
|
88
88
|
|
|
89
89
|
push(
|
|
@@ -1,77 +1,26 @@
|
|
|
1
|
-
import React from "react";
|
|
2
1
|
import { renderHook } from "@testing-library/react-hooks";
|
|
3
|
-
import configureStore from "redux-mock-store";
|
|
4
|
-
import thunk from "redux-thunk";
|
|
5
|
-
import { Provider } from "react-redux";
|
|
6
|
-
|
|
7
2
|
import { encodeParams } from "@applicaster/zapp-pipes-v2-client/src/utils";
|
|
8
3
|
|
|
9
|
-
const mockStore = configureStore([thunk]);
|
|
10
|
-
|
|
11
|
-
jest.useFakeTimers();
|
|
12
|
-
|
|
13
4
|
const appData = {
|
|
14
5
|
platform: "foo",
|
|
15
6
|
version_name: "1.2.0",
|
|
16
7
|
sdk_version: "2.0.0",
|
|
17
8
|
};
|
|
18
9
|
|
|
19
|
-
|
|
20
|
-
"http://foo.com/show": {
|
|
21
|
-
context_obj: [
|
|
22
|
-
{ type: "ctx", key: "platform" },
|
|
23
|
-
{ type: "query", mapper: "version", key: "appVersion" },
|
|
24
|
-
{ type: "header", mapper: "SDK", key: "sdkVersion" },
|
|
25
|
-
],
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const store_mock = { appData, pipesEndpoints };
|
|
30
|
-
|
|
31
|
-
const defaultStore = mockStore({
|
|
32
|
-
pipesEndpoints,
|
|
33
|
-
appData,
|
|
34
|
-
});
|
|
10
|
+
let INFLATED_URL;
|
|
35
11
|
|
|
36
|
-
|
|
37
|
-
|
|
12
|
+
jest.mock(
|
|
13
|
+
"@applicaster/zapp-react-native-utils/reactHooks/feed/useInflatedUrl",
|
|
14
|
+
() => ({
|
|
15
|
+
useInflatedUrl: () => INFLATED_URL,
|
|
16
|
+
})
|
|
38
17
|
);
|
|
39
18
|
|
|
40
|
-
const navigator = {
|
|
41
|
-
currentRoute: "/river/A1234",
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
jest.mock("../../navigation", () => ({
|
|
45
|
-
useNavigation: jest.fn(() => navigator),
|
|
46
|
-
useRoute: jest.fn(() => ({})),
|
|
47
|
-
}));
|
|
48
|
-
|
|
49
|
-
const contexts = {
|
|
50
|
-
entry: { id: "show-1" },
|
|
51
|
-
search: {},
|
|
52
|
-
screen: {},
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const contextMock = (type) => ({
|
|
56
|
-
useZappPipesContext: () => [contexts[type] || {}],
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
jest.mock("@applicaster/zapp-react-native-ui-components/Contexts", () => ({
|
|
60
|
-
ZappPipesEntryContext: contextMock("entry"),
|
|
61
|
-
ZappPipesSearchContext: contextMock("search"),
|
|
62
|
-
ZappPipesScreenContext: contextMock("screen"),
|
|
63
|
-
}));
|
|
64
|
-
|
|
65
|
-
jest.mock("@applicaster/zapp-react-native-redux/AppStore", () => ({
|
|
66
|
-
appStore: {
|
|
67
|
-
get: jest.fn((prop) => store_mock[prop]),
|
|
68
|
-
},
|
|
69
|
-
}));
|
|
70
|
-
|
|
71
19
|
const { useBuildPipesUrl } = require("../useBuildPipesUrl");
|
|
72
20
|
|
|
73
21
|
describe("useBuildPipesUrl", () => {
|
|
74
22
|
it("returns the proper url", async () => {
|
|
23
|
+
INFLATED_URL = "http://foo.com/show/show-1";
|
|
75
24
|
const url = "http://foo.com/show/{{showId}}";
|
|
76
25
|
|
|
77
26
|
const mapping = {
|
|
@@ -81,12 +30,20 @@ describe("useBuildPipesUrl", () => {
|
|
|
81
30
|
},
|
|
82
31
|
};
|
|
83
32
|
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
33
|
+
const buildResult = {
|
|
34
|
+
params: {
|
|
35
|
+
ctx: encodeParams({ platform: appData.platform }),
|
|
36
|
+
version: appData.version_name,
|
|
37
|
+
},
|
|
38
|
+
headers: { SDK: appData.sdk_version },
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const mockedRequestBuilder = {
|
|
42
|
+
build: jest.fn(() => Promise.resolve(buildResult)),
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const { result, waitForNextUpdate } = renderHook(() =>
|
|
46
|
+
useBuildPipesUrl({ url, mapping, requestBuilder: mockedRequestBuilder })
|
|
90
47
|
);
|
|
91
48
|
|
|
92
49
|
expect(result.current.url).toBe("http://foo.com/show/show-1");
|
|
@@ -108,6 +65,7 @@ describe("useBuildPipesUrl", () => {
|
|
|
108
65
|
});
|
|
109
66
|
|
|
110
67
|
it("returns empty object if url is not in endpoints", async () => {
|
|
68
|
+
INFLATED_URL = "http://foobar.com/show-1";
|
|
111
69
|
const url = "http://foobar.com/{{showId}}";
|
|
112
70
|
|
|
113
71
|
const mapping = {
|
|
@@ -117,12 +75,14 @@ describe("useBuildPipesUrl", () => {
|
|
|
117
75
|
},
|
|
118
76
|
};
|
|
119
77
|
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
78
|
+
const buildResult = {};
|
|
79
|
+
|
|
80
|
+
const mockedRequestBuilder = {
|
|
81
|
+
build: jest.fn(() => Promise.resolve(buildResult)),
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const { result, waitForNextUpdate } = renderHook(() =>
|
|
85
|
+
useBuildPipesUrl({ url, mapping, requestBuilder: mockedRequestBuilder })
|
|
126
86
|
);
|
|
127
87
|
|
|
128
88
|
expect(result.current.url).toBe("http://foobar.com/show-1");
|
|
@@ -12,9 +12,21 @@ const {
|
|
|
12
12
|
|
|
13
13
|
const { reactHooksLogger } = require("../../logger");
|
|
14
14
|
|
|
15
|
+
let mockStore;
|
|
16
|
+
|
|
15
17
|
describe("getInflatedDataSourceUrl", () => {
|
|
16
18
|
beforeEach(() => {
|
|
17
19
|
reactHooksLogger.warning.mockClear();
|
|
20
|
+
|
|
21
|
+
const {
|
|
22
|
+
appStore,
|
|
23
|
+
} = require("@applicaster/zapp-react-native-redux/AppStore");
|
|
24
|
+
|
|
25
|
+
mockStore = {
|
|
26
|
+
getState: jest.fn().mockReturnValue({ pipesEndpoints: {} }),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
appStore.set(mockStore);
|
|
18
30
|
});
|
|
19
31
|
|
|
20
32
|
it("returns the url inflated with the right params", () => {
|
|
@@ -72,7 +84,8 @@ describe("getInflatedDataSourceUrl", () => {
|
|
|
72
84
|
expect(reactHooksLogger.warning).toHaveBeenCalledTimes(1);
|
|
73
85
|
|
|
74
86
|
expect(reactHooksLogger.warning).toHaveBeenCalledWith({
|
|
75
|
-
message:
|
|
87
|
+
message:
|
|
88
|
+
"Not enough data to fully inflate url: {{entry.id}} source: http://foo.com/show/seriesId={{seriesId}}",
|
|
76
89
|
data: { source, contexts, mapping },
|
|
77
90
|
});
|
|
78
91
|
});
|
|
@@ -107,7 +120,8 @@ describe("getInflatedDataSourceUrl", () => {
|
|
|
107
120
|
expect(reactHooksLogger.warning).toHaveBeenCalledTimes(1);
|
|
108
121
|
|
|
109
122
|
expect(reactHooksLogger.warning).toHaveBeenCalledWith({
|
|
110
|
-
message:
|
|
123
|
+
message:
|
|
124
|
+
"Not enough data to fully inflate url: {{entry.extensions.groupName}} source: https://zapp-1689-emmys.web.app/emmys/group-categories/{{groupName}}",
|
|
111
125
|
data: { source, contexts, mapping },
|
|
112
126
|
});
|
|
113
127
|
});
|
|
@@ -148,7 +162,8 @@ describe("getInflatedDataSourceUrl", () => {
|
|
|
148
162
|
expect(reactHooksLogger.warning).toHaveBeenCalledTimes(1);
|
|
149
163
|
|
|
150
164
|
expect(reactHooksLogger.warning).toHaveBeenCalledWith({
|
|
151
|
-
message:
|
|
165
|
+
message:
|
|
166
|
+
"Not enough data to fully inflate url: {{entry.extensions.groupName2}} source: https://zapp-1689-emmys.web.app/emmys/group-categories/{{groupName1}}?test={{groupName2}}",
|
|
152
167
|
data: { source, contexts, mapping },
|
|
153
168
|
});
|
|
154
169
|
});
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
// @ts-ignore
|
|
2
1
|
import { RequestBuilder } from "@applicaster/zapp-pipes-v2-client";
|
|
3
|
-
import
|
|
4
|
-
import { useInflatedUrl } from "
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { useInflatedUrl } from "@applicaster/zapp-react-native-utils/reactHooks/feed/useInflatedUrl";
|
|
5
4
|
import { reactHooksLogger } from "../logger";
|
|
6
5
|
|
|
7
6
|
export const logger = reactHooksLogger.addSubsystem("build-pipes-url");
|
|
@@ -15,18 +14,16 @@ type PipesBuildRequestObject = {
|
|
|
15
14
|
export function useBuildPipesUrl({
|
|
16
15
|
url,
|
|
17
16
|
mapping = {},
|
|
17
|
+
requestBuilder = new RequestBuilder(),
|
|
18
18
|
}): PipesBuildRequestObject {
|
|
19
|
-
const [requestParams, setRequestParams] = useState<object | null>(null);
|
|
20
|
-
const [error, setError] = useState(null);
|
|
19
|
+
const [requestParams, setRequestParams] = React.useState<object | null>(null);
|
|
21
20
|
|
|
21
|
+
const [error, setError] = React.useState(null);
|
|
22
22
|
const inflatedUrl = useInflatedUrl({ feedUrl: url, mapping });
|
|
23
23
|
|
|
24
|
-
const requestBuilder = new RequestBuilder();
|
|
25
|
-
|
|
26
24
|
const buildRequest = async (_url) => {
|
|
27
25
|
try {
|
|
28
26
|
const result = await requestBuilder.build(_url);
|
|
29
|
-
|
|
30
27
|
setRequestParams(result);
|
|
31
28
|
} catch (e) {
|
|
32
29
|
setError(e);
|
|
@@ -34,7 +31,7 @@ export function useBuildPipesUrl({
|
|
|
34
31
|
}
|
|
35
32
|
};
|
|
36
33
|
|
|
37
|
-
useEffect(() => {
|
|
34
|
+
React.useEffect(() => {
|
|
38
35
|
if (inflatedUrl && !requestParams) {
|
|
39
36
|
buildRequest(inflatedUrl);
|
|
40
37
|
}
|
|
@@ -42,7 +39,7 @@ export function useBuildPipesUrl({
|
|
|
42
39
|
|
|
43
40
|
return {
|
|
44
41
|
url: inflatedUrl || "",
|
|
45
|
-
requestParams
|
|
42
|
+
requestParams, // TODO should it be: || {} ?
|
|
46
43
|
error: error || undefined,
|
|
47
44
|
};
|
|
48
45
|
}
|
|
@@ -9,9 +9,15 @@ import {
|
|
|
9
9
|
|
|
10
10
|
import { inflateString } from "../../stringUtils";
|
|
11
11
|
import { useRoute } from "../navigation";
|
|
12
|
-
import {
|
|
12
|
+
import { getMissingValues } from "../../inflatedUrlUtils";
|
|
13
13
|
import { reactHooksLogger as logger } from "../logger";
|
|
14
14
|
import { isTV } from "../../reactUtils";
|
|
15
|
+
import {
|
|
16
|
+
findEndpointForURL,
|
|
17
|
+
HTTP_METHODS,
|
|
18
|
+
} from "@applicaster/zapp-pipes-v2-client";
|
|
19
|
+
import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
|
|
20
|
+
import { ENDPOINT_TAGS } from "../../types";
|
|
15
21
|
|
|
16
22
|
/**
|
|
17
23
|
* will match any occurrence in a string of one or more word characters
|
|
@@ -105,24 +111,47 @@ export const getInflatedDataSourceUrl: GetInflatedDataSourceUrl = ({
|
|
|
105
111
|
R.keys(mapping)
|
|
106
112
|
);
|
|
107
113
|
|
|
108
|
-
|
|
109
|
-
const message = "Not enough data to fully inflate url";
|
|
114
|
+
const missingValues = getMissingValues(contexts, string);
|
|
110
115
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
if (missingValues && missingValues.length > 0) {
|
|
117
|
+
const pipesEndpoints = appStore.get("pipesEndpoints");
|
|
118
|
+
|
|
119
|
+
const endpointURL = findEndpointForURL(
|
|
120
|
+
source,
|
|
121
|
+
pipesEndpoints,
|
|
122
|
+
HTTP_METHODS.GET
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const tags = pipesEndpoints?.[endpointURL]?.tags;
|
|
126
|
+
const allowMissingKeys = tags?.includes(ENDPOINT_TAGS.allow_missing_keys);
|
|
127
|
+
|
|
128
|
+
if (!allowMissingKeys) {
|
|
129
|
+
const message = `Not enough data to fully inflate url: ${missingValues.join(
|
|
130
|
+
","
|
|
131
|
+
)} source: ${source}`;
|
|
132
|
+
|
|
133
|
+
// todo: add js only payload instead
|
|
134
|
+
if (__DEV__) {
|
|
135
|
+
logger.warning({
|
|
136
|
+
message,
|
|
137
|
+
data: { source, contexts, mapping },
|
|
138
|
+
});
|
|
139
|
+
} else {
|
|
140
|
+
// todo: log values we've failed to resolve
|
|
141
|
+
logger.warning({
|
|
142
|
+
message,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// return null in order to prevent start fetching data with invalid url
|
|
147
|
+
return null;
|
|
117
148
|
} else {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
149
|
+
logger.debug({
|
|
150
|
+
message: `Ignoring missing values in url because ${
|
|
151
|
+
ENDPOINT_TAGS.allow_missing_keys
|
|
152
|
+
} endpoint tag, keys: ${missingValues.join(",")}`,
|
|
121
153
|
});
|
|
122
154
|
}
|
|
123
|
-
|
|
124
|
-
// return null in order to prevent start fetching data with invalid url
|
|
125
|
-
return null;
|
|
126
155
|
}
|
|
127
156
|
|
|
128
157
|
return inflateString({ string, data: contexts });
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
|
|
3
3
|
import { renderHook } from "@testing-library/react-hooks";
|
|
4
|
-
import {
|
|
4
|
+
import { isNavBarVisible, useRoute } from "../";
|
|
5
5
|
import { Provider } from "react-redux";
|
|
6
6
|
import configureMockStore from "redux-mock-store";
|
|
7
7
|
import { NavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NavigationContext";
|
|
8
8
|
import { ZappHookModalContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
|
|
9
9
|
import { ROUTE_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/routeTypes";
|
|
10
|
+
import { ScreenDataContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";
|
|
10
11
|
|
|
11
12
|
const plugins = [];
|
|
12
13
|
|
|
@@ -100,13 +101,15 @@ const mainStackWrapper = ({
|
|
|
100
101
|
pathname = homeStack.route,
|
|
101
102
|
}) => (
|
|
102
103
|
<Provider store={store}>
|
|
103
|
-
<
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
{
|
|
108
|
-
|
|
109
|
-
|
|
104
|
+
<ScreenDataContext.Provider value={homeStack.state}>
|
|
105
|
+
<NavigationContext.Provider
|
|
106
|
+
value={{ ...mainStackNavigator, ...navigator, currentRoute: pathname }}
|
|
107
|
+
>
|
|
108
|
+
<PathnameContext.Provider value={pathname}>
|
|
109
|
+
{children}
|
|
110
|
+
</PathnameContext.Provider>
|
|
111
|
+
</NavigationContext.Provider>
|
|
112
|
+
</ScreenDataContext.Provider>
|
|
110
113
|
</Provider>
|
|
111
114
|
);
|
|
112
115
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-use-before-define */
|
|
2
2
|
/* eslint max-len: off */
|
|
3
3
|
|
|
4
|
-
import React, { useEffect, useMemo } from "react";
|
|
4
|
+
import React, { useContext, useEffect, useMemo } from "react";
|
|
5
5
|
import { BackHandler, InteractionManager, NativeModules } from "react-native";
|
|
6
6
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
7
7
|
|
|
@@ -12,7 +12,11 @@ import {
|
|
|
12
12
|
import { HooksManager } from "@applicaster/zapp-react-native-utils/appUtils/HooksManager";
|
|
13
13
|
|
|
14
14
|
import { legacyScreenData } from "@applicaster/quick-brick-core/App/NavigationProvider/utils";
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
LONG_KEY_PRESS_TIMEOUT,
|
|
17
|
+
QUICK_BRICK_NAVBAR,
|
|
18
|
+
QUICK_BRICK_CONTENT,
|
|
19
|
+
} from "@applicaster/quick-brick-core/const";
|
|
16
20
|
import { useZappHooksModalState } from "@applicaster/zapp-react-dom-ui-components/Components/ZappHooksModal/ZappHooksModal";
|
|
17
21
|
import { ZappHookModalContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
|
|
18
22
|
import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
|
|
@@ -31,6 +35,7 @@ import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
|
31
35
|
import { useNavbarState } from "../screen";
|
|
32
36
|
import { useNavigation } from "./useNavigation";
|
|
33
37
|
import { useModalStore } from "../../modalState";
|
|
38
|
+
import { ScreenDataContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";
|
|
34
39
|
|
|
35
40
|
export { useNavigation } from "./useNavigation";
|
|
36
41
|
|
|
@@ -146,16 +151,8 @@ export const useRoute = (): {
|
|
|
146
151
|
pathname: string;
|
|
147
152
|
} => {
|
|
148
153
|
const pathname = usePathname() || "";
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* compose `useRoute()` output data
|
|
152
|
-
*/
|
|
153
|
-
const composeRouteData = (screenData: VariousScreenData) => ({
|
|
154
|
-
screenData,
|
|
155
|
-
pathname,
|
|
156
|
-
});
|
|
157
|
-
|
|
158
154
|
const navigator = useNavigation();
|
|
155
|
+
const screenDataContext = legacyScreenData(useContext(ScreenDataContext));
|
|
159
156
|
|
|
160
157
|
const { plugins, contentTypes, rivers } = usePickFromState([
|
|
161
158
|
"plugins",
|
|
@@ -163,10 +160,11 @@ export const useRoute = (): {
|
|
|
163
160
|
"contentTypes",
|
|
164
161
|
]);
|
|
165
162
|
|
|
166
|
-
const currentStack = navigator.getStackForPathname(pathname);
|
|
167
163
|
const { modalState } = useModalStore();
|
|
168
164
|
const hookModalState = useZappHooksModalState();
|
|
165
|
+
|
|
169
166
|
const modalScreenData = modalState.screen;
|
|
167
|
+
|
|
170
168
|
const hookModalScreenData = hookModalState.state.screenData?.payload;
|
|
171
169
|
|
|
172
170
|
const videoModalScreenData =
|
|
@@ -183,15 +181,6 @@ export const useRoute = (): {
|
|
|
183
181
|
plugins
|
|
184
182
|
);
|
|
185
183
|
|
|
186
|
-
const currentRouteScreenData = legacyScreenData(
|
|
187
|
-
{
|
|
188
|
-
screen: currentStack?.state?.screen ?? navigator.data?.screen ?? {},
|
|
189
|
-
entry: currentStack?.state?.entry ?? {},
|
|
190
|
-
} as NavigationScreenData,
|
|
191
|
-
|
|
192
|
-
plugins
|
|
193
|
-
);
|
|
194
|
-
|
|
195
184
|
// There are 4 route scenarios
|
|
196
185
|
// For regular screens take date from navigator stack.
|
|
197
186
|
// is path is model grab screenData from modal state
|
|
@@ -200,63 +189,30 @@ export const useRoute = (): {
|
|
|
200
189
|
// if path is hook grab screenData from screenData
|
|
201
190
|
|
|
202
191
|
if (isModalPathname(pathname)) {
|
|
203
|
-
|
|
192
|
+
const screenData = modalScreenData ?? ({} as ZappEntry);
|
|
193
|
+
|
|
194
|
+
return { screenData, pathname };
|
|
204
195
|
}
|
|
205
196
|
|
|
206
197
|
if (isVideoModalPathname(pathname)) {
|
|
207
|
-
|
|
198
|
+
const screenData = videoModalScreenData as LegacyNavigationScreenData;
|
|
199
|
+
|
|
200
|
+
return { screenData, pathname };
|
|
208
201
|
}
|
|
209
202
|
|
|
210
203
|
if (isHookModalPathname(pathname)) {
|
|
211
|
-
|
|
204
|
+
const screenData = hookModalScreenData;
|
|
205
|
+
|
|
206
|
+
return { screenData, pathname };
|
|
212
207
|
}
|
|
213
208
|
|
|
214
209
|
if (isHookPathname(pathname)) {
|
|
215
|
-
|
|
216
|
-
* HACK
|
|
217
|
-
*
|
|
218
|
-
* This condition relies on hacky approach to get the current hook screen data
|
|
219
|
-
* using navigator.screenData for some cases.
|
|
220
|
-
* This is used when hook is in sequence.
|
|
221
|
-
*/
|
|
222
|
-
|
|
223
|
-
// case 1: stack not yet updated in navigator context, but navigator.screenData is updated already.
|
|
224
|
-
if (!currentStack) {
|
|
225
|
-
return composeRouteData(navigator.screenData);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const isValidHookInCurrentRouteScreenData =
|
|
229
|
-
"hookPlugin" in currentRouteScreenData &&
|
|
230
|
-
!!currentRouteScreenData.hookPlugin?.module;
|
|
231
|
-
|
|
232
|
-
let screenData;
|
|
233
|
-
|
|
234
|
-
// case 2: stack has valid hook data
|
|
235
|
-
if (isValidHookInCurrentRouteScreenData) {
|
|
236
|
-
screenData = currentRouteScreenData;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const navigatorScreenData = navigator.screenData as NavigatorEntry;
|
|
240
|
-
|
|
241
|
-
// case 3: current hookPlugin is missing weight, but navigator.screenData has weight, use navigator.screenData
|
|
242
|
-
if (
|
|
243
|
-
screenData.hookPlugin.identifier ===
|
|
244
|
-
navigatorScreenData?.hookPlugin?.identifier &&
|
|
245
|
-
!screenData.hookPlugin?.weight &&
|
|
246
|
-
navigatorScreenData?.hookPlugin?.weight
|
|
247
|
-
) {
|
|
248
|
-
screenData = navigator.screenData;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
return composeRouteData(screenData);
|
|
210
|
+
return { screenData: screenDataContext, pathname };
|
|
252
211
|
}
|
|
253
212
|
|
|
254
|
-
|
|
255
|
-
if (!currentStack) {
|
|
256
|
-
return composeRouteData(navigator.screenData);
|
|
257
|
-
}
|
|
213
|
+
const screenData = screenDataContext;
|
|
258
214
|
|
|
259
|
-
return
|
|
215
|
+
return { screenData, pathname };
|
|
260
216
|
};
|
|
261
217
|
|
|
262
218
|
type Callbacks = Partial<{
|
|
@@ -496,3 +452,30 @@ export const useIsScreenActive = () => {
|
|
|
496
452
|
|
|
497
453
|
return pathname === currentRoute;
|
|
498
454
|
};
|
|
455
|
+
|
|
456
|
+
type Return = (prefix: string) => string;
|
|
457
|
+
|
|
458
|
+
export const useUniqueRouteSuffix = (): Return => {
|
|
459
|
+
const pathname = usePathname();
|
|
460
|
+
const { currentRoute } = useNavigation();
|
|
461
|
+
|
|
462
|
+
const suffix = `currentRoute:${currentRoute}_pathname:${pathname}`;
|
|
463
|
+
|
|
464
|
+
const withUniqueRouteSuffix = React.useCallback((prefix: string) => {
|
|
465
|
+
return `${prefix}___${suffix}`;
|
|
466
|
+
}, []);
|
|
467
|
+
|
|
468
|
+
return withUniqueRouteSuffix;
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
export const useNavbarId = () => {
|
|
472
|
+
const withUniqueRouteSuffix = useUniqueRouteSuffix();
|
|
473
|
+
|
|
474
|
+
return withUniqueRouteSuffix(QUICK_BRICK_NAVBAR);
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
export const useContentId = () => {
|
|
478
|
+
const withUniqueRouteSuffix = useUniqueRouteSuffix();
|
|
479
|
+
|
|
480
|
+
return withUniqueRouteSuffix(QUICK_BRICK_CONTENT);
|
|
481
|
+
};
|
|
@@ -3,23 +3,28 @@ import { Provider } from "react-redux";
|
|
|
3
3
|
import { renderHook } from "@testing-library/react-hooks";
|
|
4
4
|
import configureStore from "redux-mock-store";
|
|
5
5
|
import thunk from "redux-thunk";
|
|
6
|
-
import { NavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NavigationContext";
|
|
7
6
|
|
|
8
7
|
const mockStore = configureStore([thunk]);
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
9
|
+
const river_id_2: ZappRiver = {
|
|
10
|
+
name: "River 2",
|
|
11
|
+
id: "A1234",
|
|
12
|
+
home: false,
|
|
13
|
+
home_offline: false,
|
|
14
|
+
supports_offline: false,
|
|
15
|
+
navigations: [],
|
|
16
|
+
hooks: { preload_plugins: [] },
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
jest.mock("../useScreenContext", () => ({
|
|
20
|
+
useScreenContext: () => ({
|
|
21
|
+
screen: river_id_2,
|
|
22
|
+
}),
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
const { useCurrentScreenData } = require("../useCurrentScreenData");
|
|
26
|
+
|
|
27
|
+
describe("useScreenData", () => {
|
|
23
28
|
const river_id_1 = { id: "B5678" };
|
|
24
29
|
|
|
25
30
|
const store = mockStore({
|
|
@@ -27,17 +32,10 @@ describe("useScreenData", function () {
|
|
|
27
32
|
});
|
|
28
33
|
|
|
29
34
|
const wrapper: React.FC<any> = ({ children }) => (
|
|
30
|
-
<
|
|
31
|
-
value={{
|
|
32
|
-
currentRoute: "/river/river_id_1/river/river_id_2",
|
|
33
|
-
data: { screen: river_id_2 },
|
|
34
|
-
}}
|
|
35
|
-
>
|
|
36
|
-
<Provider store={store}>{children}</Provider>
|
|
37
|
-
</NavigationContext.Provider>
|
|
35
|
+
<Provider store={store}>{children}</Provider>
|
|
38
36
|
);
|
|
39
37
|
|
|
40
|
-
it("should return river data for the current screen/route",
|
|
38
|
+
it("should return river data for the current screen/route", () => {
|
|
41
39
|
const { result } = renderHook(() => useCurrentScreenData(), { wrapper });
|
|
42
40
|
|
|
43
41
|
expect(result.current).toBe(river_id_2);
|