@applicaster/zapp-react-native-utils 15.0.0-alpha.3514407021 → 15.0.0-alpha.3564377339
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/actionsExecutor/ActionExecutorContext.tsx +3 -6
- package/actionsExecutor/feedDecorator.ts +6 -6
- package/adsUtils/index.ts +2 -2
- package/analyticsUtils/README.md +1 -1
- package/appUtils/HooksManager/index.ts +10 -10
- package/appUtils/accessibilityManager/__tests__/utils.test.ts +360 -0
- package/appUtils/accessibilityManager/const.ts +4 -0
- package/appUtils/accessibilityManager/hooks.ts +20 -13
- package/appUtils/accessibilityManager/index.ts +28 -1
- package/appUtils/accessibilityManager/utils.ts +59 -8
- package/appUtils/focusManager/index.ios.ts +8 -2
- package/appUtils/focusManagerAux/utils/index.ts +1 -1
- package/appUtils/focusManagerAux/utils/utils.ios.ts +60 -3
- package/appUtils/keyCodes/keys/keys.web.ts +1 -4
- package/appUtils/orientationHelper.ts +2 -4
- package/appUtils/platform/platformUtils.ts +117 -18
- package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +94 -4
- package/appUtils/playerManager/OverlayObserver/utils.ts +32 -20
- package/appUtils/playerManager/player.ts +4 -0
- package/appUtils/playerManager/playerNative.ts +29 -16
- package/appUtils/playerManager/usePlayerState.tsx +14 -2
- package/cellUtils/index.ts +32 -0
- package/configurationUtils/__tests__/manifestKeyParser.test.ts +26 -26
- package/focusManager/aux/index.ts +1 -1
- package/manifestUtils/defaultManifestConfigurations/player.js +75 -1
- package/manifestUtils/keys.js +21 -0
- package/manifestUtils/sharedConfiguration/screenPicker/utils.js +1 -0
- package/manifestUtils/tvAction/container/index.js +1 -1
- package/package.json +2 -2
- package/playerUtils/usePlayerTTS.ts +8 -3
- package/pluginUtils/index.ts +4 -0
- package/reactHooks/advertising/index.ts +2 -2
- package/reactHooks/debugging/__tests__/index.test.js +4 -4
- package/reactHooks/device/useMemoizedIsTablet.ts +3 -3
- package/reactHooks/feed/__tests__/useEntryScreenId.test.tsx +3 -0
- package/reactHooks/feed/__tests__/{useInflatedUrl.test.ts → useInflatedUrl.test.tsx} +62 -7
- package/reactHooks/feed/useEntryScreenId.ts +2 -2
- package/reactHooks/feed/useInflatedUrl.ts +43 -17
- package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +13 -16
- package/reactHooks/layout/index.ts +1 -1
- package/reactHooks/layout/useDimensions/__tests__/{useDimensions.test.ts → useDimensions.test.tsx} +105 -25
- package/reactHooks/layout/useDimensions/useDimensions.ts +2 -2
- package/reactHooks/navigation/index.ts +7 -6
- package/reactHooks/navigation/useRoute.ts +8 -6
- package/reactHooks/player/TVSeekControlller/TVSeekController.ts +27 -10
- package/reactHooks/resolvers/useCellResolver.ts +6 -2
- package/reactHooks/resolvers/useComponentResolver.ts +8 -2
- package/reactHooks/screen/__tests__/useTargetScreenData.test.tsx +10 -2
- package/reactHooks/screen/useTargetScreenData.ts +4 -2
- package/reactHooks/state/useRivers.ts +1 -1
- package/reactHooks/usePluginConfiguration.ts +2 -2
- package/testUtils/index.tsx +29 -20
- package/utils/__tests__/mapAccum.test.ts +73 -0
- package/utils/__tests__/selectors.test.ts +124 -0
- package/utils/index.ts +14 -0
- package/utils/mapAccum.ts +23 -0
- package/utils/path.ts +6 -3
- package/utils/pathOr.ts +5 -1
- package/utils/selectors.ts +46 -0
- package/zappFrameworkUtils/HookCallback/callbackNavigationAction.ts +34 -11
- package/zappFrameworkUtils/HookCallback/hookCallbackManifestExtensions.config.js +1 -1
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
|
|
4
4
|
import { findComponentByType } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
usePlugins,
|
|
7
|
+
useAppSelector,
|
|
8
|
+
selectComponents,
|
|
9
|
+
} from "@applicaster/zapp-react-native-redux";
|
|
6
10
|
|
|
7
11
|
type Decorator = (component: React.Component<any>) => React.Component<any>;
|
|
8
12
|
type Watcher = Array<any>;
|
|
@@ -15,7 +19,9 @@ export function useComponentResolver(
|
|
|
15
19
|
{ componentType, decorators }: Props,
|
|
16
20
|
watchers?: Watcher
|
|
17
21
|
): React.ComponentType<any> {
|
|
18
|
-
const
|
|
22
|
+
const plugins = usePlugins();
|
|
23
|
+
|
|
24
|
+
const components = useAppSelector(selectComponents);
|
|
19
25
|
|
|
20
26
|
return React.useMemo(
|
|
21
27
|
() =>
|
|
@@ -9,8 +9,16 @@ const mockStore = configureStore([thunk]);
|
|
|
9
9
|
import { useTargetScreenData } from "../useTargetScreenData";
|
|
10
10
|
|
|
11
11
|
describe("useTargetScreenData", function () {
|
|
12
|
-
const river_id_2 = {
|
|
13
|
-
|
|
12
|
+
const river_id_2 = {
|
|
13
|
+
id: "river_id_2",
|
|
14
|
+
type: "any",
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const river_id_1 = {
|
|
18
|
+
id: "river_id_1",
|
|
19
|
+
type: "any",
|
|
20
|
+
};
|
|
21
|
+
|
|
14
22
|
const screenId = "river_id_2";
|
|
15
23
|
const entry = { id: "test", type: { value: "video" } };
|
|
16
24
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { useContentTypes } from "@applicaster/zapp-react-native-redux/hooks";
|
|
3
3
|
import * as R from "ramda";
|
|
4
4
|
import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
|
|
5
|
+
import { useRivers } from "../state";
|
|
5
6
|
|
|
6
7
|
export function getTargetScreenData(
|
|
7
8
|
entry: ZappEntry,
|
|
@@ -43,7 +44,8 @@ export function getTargetScreenDataFromEntry(entry: ZappEntry): ZappRiver {
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
export const useTargetScreenData = (entry: ZappEntry) => {
|
|
46
|
-
const
|
|
47
|
+
const rivers = useRivers();
|
|
48
|
+
const contentTypes = useContentTypes();
|
|
47
49
|
|
|
48
50
|
return React.useMemo(
|
|
49
51
|
() => getTargetScreenData(entry, rivers, contentTypes),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as R from "ramda";
|
|
2
2
|
import { useMemo } from "react";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { usePlugins } from "@applicaster/zapp-react-native-redux/hooks";
|
|
5
5
|
|
|
6
6
|
// importing this way prevents typescript packages importing from this
|
|
7
7
|
// file to go crazy reporting errors on JS
|
|
@@ -25,7 +25,7 @@ export function parsePluginConfiguration(plugin, manifest) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export function usePluginConfiguration<T, S>(identifier, manifest) {
|
|
28
|
-
const
|
|
28
|
+
const plugins = usePlugins();
|
|
29
29
|
|
|
30
30
|
const plugin = useMemo(
|
|
31
31
|
() => R.find(R.propEq("identifier", identifier), plugins),
|
package/testUtils/index.tsx
CHANGED
|
@@ -56,9 +56,29 @@ const initialState = {
|
|
|
56
56
|
contentTypes: null,
|
|
57
57
|
};
|
|
58
58
|
|
|
59
|
+
const themeObjDefault = {
|
|
60
|
+
component_margin_top: 0,
|
|
61
|
+
component_margin_bottom: 0,
|
|
62
|
+
component_margin_left: 0,
|
|
63
|
+
component_margin_right: 0,
|
|
64
|
+
component_padding_top: 0,
|
|
65
|
+
component_padding_bottom: 0,
|
|
66
|
+
component_padding_left: 0,
|
|
67
|
+
component_padding_right: 0,
|
|
68
|
+
component_gutter_vertical: 0,
|
|
69
|
+
component_gutter_horizontal: 0,
|
|
70
|
+
component_corner_radius: 0,
|
|
71
|
+
app_background_color: "rgba(0,0,0,0)",
|
|
72
|
+
screen_margin_top: 0,
|
|
73
|
+
screen_margin_bottom: 0,
|
|
74
|
+
component_anchor_point_y: 0,
|
|
75
|
+
assets: "",
|
|
76
|
+
};
|
|
77
|
+
|
|
59
78
|
export const WrappedWithProviders = ({
|
|
60
79
|
children,
|
|
61
80
|
store: storeObj = {},
|
|
81
|
+
theme: themeObj = themeObjDefault,
|
|
62
82
|
}: any) => {
|
|
63
83
|
const _store = configureStore([thunk])(
|
|
64
84
|
R.mergeDeepRight(initialState, { ...storeObj })
|
|
@@ -70,24 +90,7 @@ export const WrappedWithProviders = ({
|
|
|
70
90
|
<ThemeContext.Provider
|
|
71
91
|
value={{
|
|
72
92
|
themes: {
|
|
73
|
-
light:
|
|
74
|
-
component_margin_top: 0,
|
|
75
|
-
component_margin_bottom: 0,
|
|
76
|
-
component_margin_left: 0,
|
|
77
|
-
component_margin_right: 0,
|
|
78
|
-
component_padding_top: 0,
|
|
79
|
-
component_padding_bottom: 0,
|
|
80
|
-
component_padding_left: 0,
|
|
81
|
-
component_padding_right: 0,
|
|
82
|
-
component_gutter_vertical: 0,
|
|
83
|
-
component_gutter_horizontal: 0,
|
|
84
|
-
component_corner_radius: 0,
|
|
85
|
-
app_background_color: "rgba(0,0,0,0)",
|
|
86
|
-
screen_margin_top: 0,
|
|
87
|
-
screen_margin_bottom: 0,
|
|
88
|
-
component_anchor_point_y: 0,
|
|
89
|
-
assets: "",
|
|
90
|
-
},
|
|
93
|
+
light: themeObj,
|
|
91
94
|
},
|
|
92
95
|
selectedThemeId: "light",
|
|
93
96
|
setSelectedThemeId: () => {},
|
|
@@ -113,11 +116,17 @@ export const WrappedWithProviders = ({
|
|
|
113
116
|
* @param store optional store to pass to the provider
|
|
114
117
|
* @returns
|
|
115
118
|
*/
|
|
116
|
-
export const renderWithProviders = (
|
|
119
|
+
export const renderWithProviders = (
|
|
120
|
+
component,
|
|
121
|
+
storeObj?: unknown,
|
|
122
|
+
themeObj?: unknown
|
|
123
|
+
) => {
|
|
117
124
|
return render(component, {
|
|
118
125
|
wrapper: function TestWrapper({ children }: PropsWithChildren<any>) {
|
|
119
126
|
return (
|
|
120
|
-
<WrappedWithProviders store={storeObj}
|
|
127
|
+
<WrappedWithProviders store={storeObj} theme={themeObj}>
|
|
128
|
+
{children}
|
|
129
|
+
</WrappedWithProviders>
|
|
121
130
|
);
|
|
122
131
|
},
|
|
123
132
|
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { mapAccum } from "../mapAccum";
|
|
2
|
+
|
|
3
|
+
describe("mapAccum", () => {
|
|
4
|
+
it("using standard ramda test", () => {
|
|
5
|
+
const digits = ["1", "2", "3", "4"];
|
|
6
|
+
const appender = (a, b) => [a + b, a + b];
|
|
7
|
+
|
|
8
|
+
const [acc, result] = mapAccum(appender, 0, digits); //= > ['01234', ['01', '012', '0123', '01234']]
|
|
9
|
+
expect(acc).toBe("01234");
|
|
10
|
+
expect(result).toEqual(["01", "012", "0123", "01234"]);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("maps and accumulates over an array", () => {
|
|
14
|
+
const fn = (acc, x) => [acc + x, x * 2];
|
|
15
|
+
const [acc, result] = mapAccum(fn, 0, [1, 2, 3]);
|
|
16
|
+
|
|
17
|
+
expect(acc).toBe(6); // final accumulator (0 + 1 + 2 + 3)
|
|
18
|
+
expect(result).toEqual([2, 4, 6]); // mapped values (acc + x*2 at each step)
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("returns initial accumulator for empty array", () => {
|
|
22
|
+
const fn = (acc, x) => [acc + x, acc * x];
|
|
23
|
+
const [acc, result] = mapAccum(fn, 10, []);
|
|
24
|
+
|
|
25
|
+
expect(acc).toBe(10);
|
|
26
|
+
expect(result).toEqual([]);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("accumulates strings correctly", () => {
|
|
30
|
+
const fn = (acc, x) => [acc + x, acc + x];
|
|
31
|
+
const [acc, result] = mapAccum(fn, "A", ["B", "C", "D"]);
|
|
32
|
+
|
|
33
|
+
expect(acc).toBe("ABCD");
|
|
34
|
+
expect(result).toEqual(["AB", "ABC", "ABCD"]);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("works with objects as accumulator", () => {
|
|
38
|
+
const fn = (acc, x) => {
|
|
39
|
+
const newAcc = { sum: acc.sum + x };
|
|
40
|
+
|
|
41
|
+
return [newAcc, newAcc.sum];
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const [acc, result] = mapAccum(fn, { sum: 0 }, [1, 2, 3]);
|
|
45
|
+
|
|
46
|
+
expect(acc).toEqual({ sum: 6 });
|
|
47
|
+
expect(result).toEqual([1, 3, 6]);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("is curried", () => {
|
|
51
|
+
const fn = (acc, x) => [acc + x, x * 2];
|
|
52
|
+
const mapWithFn = mapAccum(fn);
|
|
53
|
+
const withInit = mapWithFn(2);
|
|
54
|
+
const [acc, result] = withInit([1, 2, 3]);
|
|
55
|
+
|
|
56
|
+
expect(acc).toBe(8);
|
|
57
|
+
expect(result).toEqual([2, 4, 6]);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("does not mutate the original array", () => {
|
|
61
|
+
const arr = [1, 2, 3];
|
|
62
|
+
mapAccum((acc, x) => [acc + x, acc + x], 0, arr);
|
|
63
|
+
expect(arr).toEqual([1, 2, 3]);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("handles mixed types in accumulator and result", () => {
|
|
67
|
+
const fn = (acc, x) => [acc + x.length, acc + "-" + x];
|
|
68
|
+
const [acc, result] = mapAccum(fn, 0, ["a", "bb", "ccc"]);
|
|
69
|
+
|
|
70
|
+
expect(acc).toBe(6);
|
|
71
|
+
expect(result).toEqual(["0-a", "1-bb", "3-ccc"]);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createPluginsByPathSelector,
|
|
3
|
+
createPluginsByModuleSelector,
|
|
4
|
+
combinePluginSelectors,
|
|
5
|
+
} from "../selectors";
|
|
6
|
+
|
|
7
|
+
describe("Plugin Selectors", () => {
|
|
8
|
+
const mockPlugins = [
|
|
9
|
+
{
|
|
10
|
+
identifier: "plugin1",
|
|
11
|
+
module: {
|
|
12
|
+
urlScheme: { host: "test" },
|
|
13
|
+
player: { type: "default" },
|
|
14
|
+
},
|
|
15
|
+
customField: true,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
identifier: "plugin2",
|
|
19
|
+
module: {
|
|
20
|
+
urlScheme: { host: "other" },
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
identifier: "plugin3",
|
|
25
|
+
module: {
|
|
26
|
+
player: { type: "custom" },
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
const mockState = {
|
|
32
|
+
plugins: mockPlugins,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
describe("createPluginsByPathSelector", () => {
|
|
36
|
+
it("filters plugins by string path", () => {
|
|
37
|
+
const selector = createPluginsByPathSelector("customField");
|
|
38
|
+
const result = selector(mockState);
|
|
39
|
+
|
|
40
|
+
expect(result).toHaveLength(1);
|
|
41
|
+
expect(result[0].identifier).toBe("plugin1");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("filters plugins by array path", () => {
|
|
45
|
+
const selector = createPluginsByPathSelector(["module", "urlScheme"]);
|
|
46
|
+
const result = selector(mockState);
|
|
47
|
+
|
|
48
|
+
expect(result).toHaveLength(2);
|
|
49
|
+
expect(result.map((p) => p.identifier)).toEqual(["plugin1", "plugin2"]);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("handles missing plugins array", () => {
|
|
53
|
+
const selector = createPluginsByPathSelector("customField");
|
|
54
|
+
const result = selector({});
|
|
55
|
+
|
|
56
|
+
expect(result).toEqual([]);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("handles non-existent path", () => {
|
|
60
|
+
const selector = createPluginsByPathSelector("nonexistent");
|
|
61
|
+
const result = selector(mockState);
|
|
62
|
+
|
|
63
|
+
expect(result).toEqual([]);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe("createPluginsByModuleSelector", () => {
|
|
68
|
+
it("filters plugins by module path", () => {
|
|
69
|
+
const selector = createPluginsByModuleSelector("player");
|
|
70
|
+
const result = selector(mockState);
|
|
71
|
+
|
|
72
|
+
expect(result).toHaveLength(2);
|
|
73
|
+
expect(result.map((p) => p.identifier)).toEqual(["plugin1", "plugin3"]);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("handles non-existent module", () => {
|
|
77
|
+
const selector = createPluginsByModuleSelector("nonexistent");
|
|
78
|
+
const result = selector(mockState);
|
|
79
|
+
|
|
80
|
+
expect(result).toEqual([]);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe("combinePluginSelectors", () => {
|
|
85
|
+
it("combines multiple selectors with AND logic", () => {
|
|
86
|
+
const urlSchemeSelector = createPluginsByModuleSelector("urlScheme");
|
|
87
|
+
const playerSelector = createPluginsByModuleSelector("player");
|
|
88
|
+
|
|
89
|
+
const combinedSelector = combinePluginSelectors(
|
|
90
|
+
urlSchemeSelector,
|
|
91
|
+
playerSelector
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const result = combinedSelector(mockState);
|
|
95
|
+
|
|
96
|
+
expect(result).toHaveLength(1);
|
|
97
|
+
expect(result[0].identifier).toBe("plugin1");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("returns empty array when no plugins match all conditions", () => {
|
|
101
|
+
const urlSchemeSelector = createPluginsByModuleSelector("urlScheme");
|
|
102
|
+
const customSelector = createPluginsByPathSelector("nonexistent");
|
|
103
|
+
|
|
104
|
+
const combinedSelector = combinePluginSelectors(
|
|
105
|
+
urlSchemeSelector,
|
|
106
|
+
customSelector
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const result = combinedSelector(mockState);
|
|
110
|
+
|
|
111
|
+
expect(result).toEqual([]);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("handles empty state", () => {
|
|
115
|
+
const selector = combinePluginSelectors(
|
|
116
|
+
createPluginsByModuleSelector("urlScheme")
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const result = selector({});
|
|
120
|
+
|
|
121
|
+
expect(result).toEqual([]);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
});
|
package/utils/index.ts
CHANGED
|
@@ -16,6 +16,8 @@ export { endsWith } from "./endsWith";
|
|
|
16
16
|
|
|
17
17
|
export { take } from "./take";
|
|
18
18
|
|
|
19
|
+
export { mapAccum } from "./mapAccum";
|
|
20
|
+
|
|
19
21
|
export {
|
|
20
22
|
cloneDeep as clone,
|
|
21
23
|
flatten,
|
|
@@ -37,4 +39,16 @@ export {
|
|
|
37
39
|
uniq,
|
|
38
40
|
uniqWith,
|
|
39
41
|
flowRight as compose,
|
|
42
|
+
partial,
|
|
43
|
+
clamp,
|
|
44
|
+
reverse,
|
|
45
|
+
takeRight,
|
|
46
|
+
fromPairs,
|
|
47
|
+
sortBy,
|
|
48
|
+
merge,
|
|
49
|
+
values,
|
|
50
|
+
head,
|
|
51
|
+
findIndex,
|
|
52
|
+
set,
|
|
53
|
+
compact,
|
|
40
54
|
} from "lodash";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { curry } from "lodash";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A native reimplementation of Ramda's mapAccum.
|
|
5
|
+
*
|
|
6
|
+
* @template A, B, C
|
|
7
|
+
* @param {(acc: A, value: B) => [A, C]} fn - Function returning [newAcc, mappedValue]
|
|
8
|
+
* @param {A} acc - Initial accumulator
|
|
9
|
+
* @param {B[]} list - List to process
|
|
10
|
+
* @returns {[A, C[]]} - Tuple of [final accumulator, mapped array]
|
|
11
|
+
*/
|
|
12
|
+
export const mapAccum = curry((fn, acc, list) => {
|
|
13
|
+
const result = [];
|
|
14
|
+
let currentAcc = acc;
|
|
15
|
+
|
|
16
|
+
for (let i = 0; i < list.length; i++) {
|
|
17
|
+
const [nextAcc, mapped] = fn(currentAcc, list[i]);
|
|
18
|
+
currentAcc = nextAcc;
|
|
19
|
+
result.push(mapped);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return [currentAcc, result];
|
|
23
|
+
});
|
package/utils/path.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { pathOr } from "./pathOr";
|
|
2
2
|
|
|
3
|
-
export const path =
|
|
4
|
-
|
|
3
|
+
export const path = <T = any>(
|
|
4
|
+
route: (string | number) | (string | number)[],
|
|
5
|
+
record: any
|
|
6
|
+
) => {
|
|
7
|
+
return pathOr<T>(undefined, route, record);
|
|
5
8
|
};
|
package/utils/pathOr.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { get } from "lodash";
|
|
2
2
|
|
|
3
|
-
export const pathOr =
|
|
3
|
+
export const pathOr = <T = any>(
|
|
4
|
+
defaultValue: T,
|
|
5
|
+
path: (number | string) | (number | string)[],
|
|
6
|
+
record: any
|
|
7
|
+
): T => {
|
|
4
8
|
return get(record, path, defaultValue);
|
|
5
9
|
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { get } from "lodash";
|
|
2
|
+
|
|
3
|
+
export type Selector<T> = (state: any) => T;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a selector for filtering plugins by path
|
|
7
|
+
* @param path - Path to check in plugin. Can be a dot notation string or array
|
|
8
|
+
* @returns A selector function that returns matching plugins
|
|
9
|
+
*/
|
|
10
|
+
export const createPluginsByPathSelector = (
|
|
11
|
+
path: string | string[]
|
|
12
|
+
): Selector<any[]> => {
|
|
13
|
+
return (state: any) => {
|
|
14
|
+
const plugins = state.plugins || [];
|
|
15
|
+
|
|
16
|
+
return plugins.filter((plugin: any) => get(plugin, path));
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Creates a selector for filtering plugins by module path
|
|
22
|
+
* @param modulePath - Module path to check in plugin (e.g., "urlScheme", "player")
|
|
23
|
+
* @returns A selector function that returns plugins with specified module
|
|
24
|
+
*/
|
|
25
|
+
export const createPluginsByModuleSelector = (
|
|
26
|
+
modulePath: string
|
|
27
|
+
): Selector<any[]> => {
|
|
28
|
+
return createPluginsByPathSelector(["module", modulePath]);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Creates a selector that combines multiple plugin selectors
|
|
33
|
+
* @param selectors - Array of plugin selectors to combine
|
|
34
|
+
* @returns A selector function that returns plugins matching all conditions
|
|
35
|
+
*/
|
|
36
|
+
export const combinePluginSelectors = (
|
|
37
|
+
...selectors: Selector<any[]>[]
|
|
38
|
+
): Selector<any[]> => {
|
|
39
|
+
return (state: any) => {
|
|
40
|
+
return selectors.reduce((filtered, selector) => {
|
|
41
|
+
const selected = selector(state);
|
|
42
|
+
|
|
43
|
+
return filtered.filter((plugin) => selected.includes(plugin));
|
|
44
|
+
}, state.plugins || []);
|
|
45
|
+
};
|
|
46
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useNavigation, useRivers, useScreenContext } from "../../reactHooks";
|
|
2
2
|
import { createLogger } from "../../logger";
|
|
3
|
-
import { useCallback, useMemo } from "react";
|
|
3
|
+
import { useCallback, useMemo, useRef, useEffect } from "react";
|
|
4
4
|
|
|
5
5
|
export enum NavigationCallbackOptions {
|
|
6
6
|
DEFAULT = "default",
|
|
@@ -17,6 +17,7 @@ export enum ResultType {
|
|
|
17
17
|
export type CallbackResult = hookCallbackArgs & {
|
|
18
18
|
options?: {
|
|
19
19
|
resultType?: ResultType;
|
|
20
|
+
navigator?: QuickBrickAppNavigator;
|
|
20
21
|
};
|
|
21
22
|
};
|
|
22
23
|
|
|
@@ -45,7 +46,7 @@ const legacyMappingKeys = {
|
|
|
45
46
|
actionType: "login_completion_action",
|
|
46
47
|
targetScreen: "navigate_to_login_screen",
|
|
47
48
|
},
|
|
48
|
-
"quick-brick-user-account-ui-component": {
|
|
49
|
+
"quick-brick-user-account-ui-component.login": {
|
|
49
50
|
actionType: "callbackAction",
|
|
50
51
|
},
|
|
51
52
|
"quick-brick-login-multi-login-providers.login": {
|
|
@@ -83,7 +84,8 @@ export const getNavigationKeys = (
|
|
|
83
84
|
): NavKeys => {
|
|
84
85
|
const general = (item?.general ?? {}) as General;
|
|
85
86
|
|
|
86
|
-
const pluginIdentifier =
|
|
87
|
+
const pluginIdentifier =
|
|
88
|
+
(item as any).identifier ?? item?.type ?? item?.component_type ?? "";
|
|
87
89
|
|
|
88
90
|
const legacy =
|
|
89
91
|
legacyMappingKeys[`${pluginIdentifier}.${resultType}`] ??
|
|
@@ -135,6 +137,12 @@ export const useCallbackNavigationAction = (
|
|
|
135
137
|
const rivers = useRivers();
|
|
136
138
|
const screenContext = useScreenContext();
|
|
137
139
|
|
|
140
|
+
const navigationRef = useRef(navigation);
|
|
141
|
+
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
navigationRef.current = navigation;
|
|
144
|
+
}, [navigation]);
|
|
145
|
+
|
|
138
146
|
const overrideCallbackFromComponent = useMemo(() => {
|
|
139
147
|
log_verbose(`${LogPrefix}: overridden callbackAction by component`);
|
|
140
148
|
|
|
@@ -168,20 +176,35 @@ export const useCallbackNavigationAction = (
|
|
|
168
176
|
return;
|
|
169
177
|
}
|
|
170
178
|
|
|
171
|
-
|
|
179
|
+
let data = getNavigationKeys(item, args.options?.resultType ?? null);
|
|
172
180
|
|
|
173
181
|
if (!data) {
|
|
174
|
-
hookCallback
|
|
182
|
+
const isScreen = !hookCallback;
|
|
175
183
|
|
|
176
|
-
|
|
184
|
+
if (isScreen && args.options?.resultType === ResultType.login) {
|
|
185
|
+
log_debug(
|
|
186
|
+
`${LogPrefix} no navigation data found, applying GO BACK for login screen`
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
data = {
|
|
190
|
+
action: NavigationCallbackOptions.GO_BACK,
|
|
191
|
+
targetScreenId: null,
|
|
192
|
+
};
|
|
193
|
+
} else {
|
|
194
|
+
hookCallback?.(args);
|
|
195
|
+
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
177
198
|
}
|
|
178
199
|
|
|
179
200
|
hookCallback?.({ ...args, success: false, cancelled: true });
|
|
201
|
+
const currentNavigation = navigationRef.current;
|
|
180
202
|
|
|
181
203
|
switch (data.action) {
|
|
182
204
|
case NavigationCallbackOptions.GO_BACK: {
|
|
183
|
-
if (
|
|
184
|
-
|
|
205
|
+
if (currentNavigation.canGoBack()) {
|
|
206
|
+
currentNavigation.goBack();
|
|
207
|
+
|
|
185
208
|
log_info(`${LogPrefix} performing 'GO BACK' action`);
|
|
186
209
|
} else {
|
|
187
210
|
log_info(`${LogPrefix} cannot perform 'GO BACK' action — ignoring`);
|
|
@@ -191,7 +214,7 @@ export const useCallbackNavigationAction = (
|
|
|
191
214
|
}
|
|
192
215
|
|
|
193
216
|
case NavigationCallbackOptions.GO_HOME: {
|
|
194
|
-
|
|
217
|
+
currentNavigation.goHome();
|
|
195
218
|
log_info(`${LogPrefix} performing 'GO HOME' action`);
|
|
196
219
|
break;
|
|
197
220
|
}
|
|
@@ -207,7 +230,7 @@ export const useCallbackNavigationAction = (
|
|
|
207
230
|
const screen = rivers[screenId];
|
|
208
231
|
|
|
209
232
|
if (screen) {
|
|
210
|
-
|
|
233
|
+
currentNavigation.replace(screen);
|
|
211
234
|
|
|
212
235
|
log_info(
|
|
213
236
|
`${LogPrefix} performing 'GO TO SCREEN' action to screen: ${screenId}`
|
|
@@ -224,7 +247,7 @@ export const useCallbackNavigationAction = (
|
|
|
224
247
|
}
|
|
225
248
|
}
|
|
226
249
|
},
|
|
227
|
-
[item,
|
|
250
|
+
[item, rivers]
|
|
228
251
|
);
|
|
229
252
|
|
|
230
253
|
return overrideCallbackFromComponent || callbackAction;
|