@applicaster/quick-brick-core 15.0.0-rc.48 → 15.0.0-rc.49
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/App/DeepLinking/URLSchemeHandler/SchemeHandlerHooks/__tests__/useOpenSchemeHandler.test.tsx +12 -27
- package/App/DeepLinking/URLSchemeHandler/SchemeHandlerHooks/__tests__/useUrlSchemeHandler.test.tsx +196 -103
- package/App/DeepLinking/URLSchemeHandler/SchemeHandlerHooks/useOpenSchemeHandler/index.ts +4 -7
- package/App/DeepLinking/URLSchemeHandler/SchemeHandlerHooks/useUrlSchemeHandler.ts +42 -30
- package/App/DeepLinking/URLSchemeHandler/URLSchemeHandler.tsx +4 -1
- package/App/DeepLinking/URLSchemeHandler/__tests__/URLSchemeHandler.test.tsx +20 -13
- package/App/DeepLinking/URLSchemeListener/index.tsx +3 -4
- package/App/NavigationProvider/Loader.tsx +3 -4
- package/App/NavigationProvider/NavigationProvider.tsx +21 -35
- package/App/NavigationProvider/ScreenHooks/usePluginScreenHooks.ts +2 -2
- package/App/NavigationProvider/__tests__/navigationProvider.test.tsx +141 -152
- package/App/NavigationProvider/navigator/selectors.ts +20 -5
- package/App/NetworkStatusProvider/NetworkStatusProvider.tsx +2 -2
- package/package.json +8 -8
- package/App/DeepLinking/URLSchemeHandler/__tests__/__snapshots__/URLSchemeHandler.test.tsx.snap +0 -24
package/App/DeepLinking/URLSchemeHandler/SchemeHandlerHooks/__tests__/useOpenSchemeHandler.test.tsx
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
/* eslint-disable max-len */
|
|
2
|
-
import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
|
|
3
2
|
import * as feedLoader from "@applicaster/zapp-react-native-utils/reactHooks/feed/useFeedLoader";
|
|
4
3
|
import * as useNavigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
|
|
5
4
|
import { waitFor, cleanup, renderHook } from "@testing-library/react-native";
|
|
6
5
|
import nock from "nock";
|
|
7
|
-
import * as R from "ramda";
|
|
8
6
|
import React from "react";
|
|
9
|
-
import {
|
|
10
|
-
import configureStore from "redux-mock-store";
|
|
7
|
+
import { mergeDeepRight } from "ramda";
|
|
11
8
|
import * as helpers from "../../../helpers";
|
|
9
|
+
import { WrappedWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
|
|
10
|
+
|
|
12
11
|
import {
|
|
13
12
|
noTargetScreenError,
|
|
14
13
|
resolveError,
|
|
@@ -24,6 +23,7 @@ const rivers: Record<string, Partial<ZappRiver>> = {
|
|
|
24
23
|
home: true,
|
|
25
24
|
},
|
|
26
25
|
B0987: {
|
|
26
|
+
type: "any",
|
|
27
27
|
id: "B0987",
|
|
28
28
|
},
|
|
29
29
|
C5678: {
|
|
@@ -42,7 +42,7 @@ const contentTypes: ZappContentTypes = {
|
|
|
42
42
|
const endpoint = "http://feed.com";
|
|
43
43
|
|
|
44
44
|
const pipesEndpoints: ZappPipesEndpoints = {
|
|
45
|
-
[
|
|
45
|
+
[endpoint]: {
|
|
46
46
|
context_keys: [],
|
|
47
47
|
context_obj: [],
|
|
48
48
|
},
|
|
@@ -55,7 +55,6 @@ const navigator = {
|
|
|
55
55
|
goHome: jest.fn(),
|
|
56
56
|
} as any;
|
|
57
57
|
|
|
58
|
-
const mockStore = configureStore();
|
|
59
58
|
jest.spyOn(useNavigationHooks, "useNavigation").mockReturnValue(navigator);
|
|
60
59
|
|
|
61
60
|
const helperSpy = jest.spyOn(helpers, "handlePresentNavigation");
|
|
@@ -80,31 +79,17 @@ jest.mock("../../../logger", () => ({
|
|
|
80
79
|
// to use import instead of require it's required to use jest.mock above
|
|
81
80
|
const { useOpenSchemeHandler } = require("../useOpenSchemeHandler");
|
|
82
81
|
|
|
83
|
-
const
|
|
84
|
-
const store = mockStore(
|
|
85
|
-
R.mergeDeepRight(
|
|
86
|
-
{ rivers, contentTypes, pipesEndpoints, appData },
|
|
87
|
-
storeProps
|
|
88
|
-
)
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
appStore.set(store);
|
|
92
|
-
|
|
93
|
-
const Wrapper = ({ children }: { children: React.ReactChild }) => (
|
|
94
|
-
/* @ts-ignore */
|
|
95
|
-
<Provider store={store}>{children}</Provider>
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
return Wrapper;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const testHook = async ({ url, query, storeProps = {}, tests }) => {
|
|
102
|
-
const wrapper = getWrapper(storeProps);
|
|
82
|
+
const mockStoreObj = { rivers, contentTypes, pipesEndpoints, appData };
|
|
103
83
|
|
|
84
|
+
const testHook = async ({ url, query, storeProps = {}, tests }: any) => {
|
|
104
85
|
const callback = jest.fn((fn) => fn(tests));
|
|
105
86
|
|
|
106
87
|
renderHook(() => useOpenSchemeHandler({ url, query, onFinish: callback }), {
|
|
107
|
-
wrapper
|
|
88
|
+
wrapper: ({ children }) => (
|
|
89
|
+
<WrappedWithProviders store={mergeDeepRight(mockStoreObj, storeProps)}>
|
|
90
|
+
{children}
|
|
91
|
+
</WrappedWithProviders>
|
|
92
|
+
),
|
|
108
93
|
});
|
|
109
94
|
|
|
110
95
|
await waitFor(() => expect(callback).toHaveBeenCalled());
|
package/App/DeepLinking/URLSchemeHandler/SchemeHandlerHooks/__tests__/useUrlSchemeHandler.test.tsx
CHANGED
|
@@ -6,6 +6,30 @@ import { Provider } from "react-redux";
|
|
|
6
6
|
import configureStore from "redux-mock-store";
|
|
7
7
|
|
|
8
8
|
import { log_warning } from "../../../logger";
|
|
9
|
+
import { handleActionSchemeUrl } from "../useUrlSchemeHandler";
|
|
10
|
+
import { appStore } from "../../../../../../zapp-react-native-redux/AppStore";
|
|
11
|
+
|
|
12
|
+
type UrlSchemeHandlerArgs = {
|
|
13
|
+
query: Record<string, unknown>;
|
|
14
|
+
url: string;
|
|
15
|
+
onFinish?: (callback: () => void) => void;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type PluginType = "general" | "player";
|
|
19
|
+
|
|
20
|
+
interface ZappPlugin {
|
|
21
|
+
urlScheme?: {
|
|
22
|
+
host: string;
|
|
23
|
+
handler: (args: UrlSchemeHandlerArgs) => void;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface QuickBrickPlugin {
|
|
28
|
+
module: ZappPlugin;
|
|
29
|
+
name: string;
|
|
30
|
+
identifier: string;
|
|
31
|
+
type: PluginType;
|
|
32
|
+
}
|
|
9
33
|
|
|
10
34
|
const mockStore = configureStore();
|
|
11
35
|
|
|
@@ -14,153 +38,222 @@ jest.mock("../../../logger", () => ({
|
|
|
14
38
|
log_warning: jest.fn(),
|
|
15
39
|
}));
|
|
16
40
|
|
|
17
|
-
const
|
|
18
|
-
|
|
41
|
+
const mockHandler = jest.fn(({ onFinish }) => {
|
|
42
|
+
onFinish?.(() => {});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const mockComplexHandler = jest.fn(({ onFinish }) => {
|
|
46
|
+
onFinish?.(() => {});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const lambdaPlugin: QuickBrickPlugin = {
|
|
50
|
+
module: {} as ZappPlugin,
|
|
19
51
|
name: "Lambda plugin",
|
|
20
52
|
identifier: "someplugin",
|
|
21
|
-
type: "general"
|
|
53
|
+
type: "general",
|
|
22
54
|
};
|
|
23
55
|
|
|
24
|
-
const pluginWithHandler = {
|
|
56
|
+
const pluginWithHandler: QuickBrickPlugin = {
|
|
25
57
|
name: "Plugin handling scheme",
|
|
26
58
|
identifier: "plugin-with-handler",
|
|
27
|
-
type: "general"
|
|
59
|
+
type: "general",
|
|
28
60
|
module: {
|
|
29
61
|
urlScheme: {
|
|
30
62
|
host: "foo",
|
|
31
|
-
handler:
|
|
32
|
-
|
|
33
|
-
|
|
63
|
+
handler: mockHandler,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const pluginWithComplexHandler: QuickBrickPlugin = {
|
|
69
|
+
name: "Plugin with nested handler",
|
|
70
|
+
identifier: "plugin-with-nested-handler",
|
|
71
|
+
type: "general",
|
|
72
|
+
module: {
|
|
73
|
+
urlScheme: {
|
|
74
|
+
host: "complex",
|
|
75
|
+
handler: mockComplexHandler,
|
|
34
76
|
},
|
|
35
|
-
}
|
|
77
|
+
},
|
|
36
78
|
};
|
|
37
79
|
|
|
38
|
-
const plugins
|
|
80
|
+
const plugins = [lambdaPlugin, pluginWithHandler, pluginWithComplexHandler];
|
|
39
81
|
|
|
40
82
|
const { useUrlSchemeHandler } = require("../useUrlSchemeHandler");
|
|
41
83
|
|
|
42
84
|
describe("useUrlSchemeHandler", () => {
|
|
43
|
-
|
|
44
|
-
// log_warning.mockClear();
|
|
45
|
-
// });
|
|
85
|
+
const store = mockStore({ plugins });
|
|
46
86
|
|
|
47
|
-
|
|
87
|
+
appStore.set(store);
|
|
48
88
|
|
|
49
|
-
const wrapper: React.FC
|
|
89
|
+
const wrapper: React.FC = ({ children }) => (
|
|
50
90
|
<Provider store={store}>{children}</Provider>
|
|
51
91
|
);
|
|
52
92
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const onFinish = jest.fn();
|
|
56
|
-
const url = "test://present?foo=bar";
|
|
93
|
+
beforeEach(() => {
|
|
94
|
+
jest.clearAllMocks();
|
|
57
95
|
|
|
58
|
-
URLHandlersMap.schemeHandlerHooks.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
() =>
|
|
62
|
-
useUrlSchemeHandler({
|
|
63
|
-
url,
|
|
64
|
-
onFinish,
|
|
65
|
-
}),
|
|
66
|
-
{ wrapper }
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
expect(presentSpy).toBeCalledWith({ query: { foo: "bar" }, url, onFinish });
|
|
96
|
+
Object.keys(URLHandlersMap.schemeHandlerHooks).forEach((key) => {
|
|
97
|
+
delete (URLHandlersMap.schemeHandlerHooks as any)[key];
|
|
98
|
+
});
|
|
70
99
|
});
|
|
71
100
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
101
|
+
describe("Basic URL scheme handling", () => {
|
|
102
|
+
it("handles query params correctly", () => {
|
|
103
|
+
const testHandler = jest.fn();
|
|
104
|
+
(URLHandlersMap.schemeHandlerHooks as any).test = testHandler;
|
|
105
|
+
const testUrl = "test://test?foo=bar";
|
|
106
|
+
|
|
107
|
+
renderHook(
|
|
108
|
+
() =>
|
|
109
|
+
useUrlSchemeHandler({
|
|
110
|
+
url: testUrl,
|
|
111
|
+
onFinish: jest.fn(),
|
|
112
|
+
}),
|
|
113
|
+
{ wrapper }
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
expect(testHandler).toBeCalledWith({
|
|
117
|
+
query: { foo: "bar" },
|
|
118
|
+
url: testUrl,
|
|
119
|
+
onFinish: expect.any(Function),
|
|
120
|
+
});
|
|
77
121
|
});
|
|
78
122
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
url,
|
|
83
|
-
onFinish,
|
|
84
|
-
}),
|
|
85
|
-
{ wrapper }
|
|
86
|
-
);
|
|
123
|
+
it("handles missing scheme handlers gracefully", () => {
|
|
124
|
+
const testUrl = "test://unknown?foo=bar";
|
|
125
|
+
const finishCallback = jest.fn();
|
|
87
126
|
|
|
88
|
-
|
|
127
|
+
const onFinish = jest.fn((cb) => {
|
|
128
|
+
cb();
|
|
129
|
+
finishCallback();
|
|
130
|
+
});
|
|
89
131
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
132
|
+
renderHook(
|
|
133
|
+
() =>
|
|
134
|
+
useUrlSchemeHandler({
|
|
135
|
+
url: testUrl,
|
|
136
|
+
onFinish,
|
|
137
|
+
}),
|
|
138
|
+
{ wrapper }
|
|
139
|
+
);
|
|
94
140
|
|
|
95
|
-
|
|
96
|
-
const url = "test://present?foo=bar";
|
|
97
|
-
const onFinish = jest.fn();
|
|
141
|
+
expect(finishCallback).toBeCalled();
|
|
98
142
|
|
|
99
|
-
|
|
100
|
-
onFinish();
|
|
143
|
+
expect(log_warning).toBeCalledWith(expect.stringContaining(testUrl));
|
|
101
144
|
});
|
|
102
|
-
|
|
103
|
-
URLHandlersMap.schemeHandlerHooks.present = presentSpy;
|
|
104
|
-
|
|
105
|
-
renderHook(
|
|
106
|
-
() =>
|
|
107
|
-
useUrlSchemeHandler({
|
|
108
|
-
url,
|
|
109
|
-
onFinish,
|
|
110
|
-
}),
|
|
111
|
-
{ wrapper }
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
expect(onFinish).toBeCalled();
|
|
115
145
|
});
|
|
116
146
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
147
|
+
describe("Plugin-based scheme handling", () => {
|
|
148
|
+
it("resolves and calls plugin handlers", () => {
|
|
149
|
+
const testUrl = "test://foo?param=test";
|
|
150
|
+
const onFinish = jest.fn();
|
|
151
|
+
|
|
152
|
+
renderHook(
|
|
153
|
+
() =>
|
|
154
|
+
useUrlSchemeHandler({
|
|
155
|
+
url: testUrl,
|
|
156
|
+
onFinish,
|
|
157
|
+
}),
|
|
158
|
+
{ wrapper }
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
expect(mockHandler).toBeCalledWith({
|
|
162
|
+
query: { param: "test" },
|
|
163
|
+
url: testUrl,
|
|
164
|
+
onFinish,
|
|
165
|
+
});
|
|
122
166
|
});
|
|
123
167
|
|
|
124
|
-
|
|
125
|
-
|
|
168
|
+
it("handles complex plugin configurations", () => {
|
|
169
|
+
const testUrl = "test://complex?param=nested";
|
|
170
|
+
const onFinish = jest.fn();
|
|
171
|
+
|
|
172
|
+
renderHook(
|
|
173
|
+
() =>
|
|
174
|
+
useUrlSchemeHandler({
|
|
175
|
+
url: testUrl,
|
|
176
|
+
onFinish,
|
|
177
|
+
}),
|
|
178
|
+
{ wrapper }
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
expect(mockComplexHandler).toBeCalledWith({
|
|
182
|
+
query: { param: "nested" },
|
|
183
|
+
url: testUrl,
|
|
184
|
+
onFinish,
|
|
185
|
+
});
|
|
126
186
|
});
|
|
127
187
|
|
|
128
|
-
|
|
188
|
+
it("ignores plugins without urlScheme", () => {
|
|
189
|
+
const testUrl = "test://nonexistent?param=value";
|
|
190
|
+
const finishCallback = jest.fn();
|
|
191
|
+
|
|
192
|
+
const onFinish = jest.fn((cb) => {
|
|
193
|
+
cb();
|
|
194
|
+
finishCallback();
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
renderHook(
|
|
198
|
+
() =>
|
|
199
|
+
useUrlSchemeHandler({
|
|
200
|
+
url: testUrl,
|
|
201
|
+
onFinish,
|
|
202
|
+
}),
|
|
203
|
+
{ wrapper }
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
expect(lambdaPlugin.module).not.toHaveProperty("urlScheme");
|
|
207
|
+
expect(finishCallback).toBeCalled();
|
|
208
|
+
});
|
|
209
|
+
});
|
|
129
210
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
url,
|
|
134
|
-
onFinish,
|
|
135
|
-
}),
|
|
136
|
-
{ wrapper }
|
|
137
|
-
);
|
|
211
|
+
describe("Action scheme handling", () => {
|
|
212
|
+
it("handles action schemes using plugins", () => {
|
|
213
|
+
const testUrl = "test://foo?action=test";
|
|
138
214
|
|
|
139
|
-
|
|
215
|
+
handleActionSchemeUrl({
|
|
216
|
+
url: testUrl,
|
|
217
|
+
plugins,
|
|
218
|
+
} as any);
|
|
140
219
|
|
|
141
|
-
|
|
142
|
-
|
|
220
|
+
expect(mockHandler).toBeCalledWith({
|
|
221
|
+
query: { action: "test" },
|
|
222
|
+
url: testUrl,
|
|
223
|
+
});
|
|
224
|
+
});
|
|
143
225
|
|
|
144
|
-
|
|
145
|
-
|
|
226
|
+
it("throws for unknown action schemes", () => {
|
|
227
|
+
const testUrl = "test://unknown?action=test";
|
|
146
228
|
|
|
147
|
-
|
|
148
|
-
|
|
229
|
+
expect(() => {
|
|
230
|
+
handleActionSchemeUrl({
|
|
231
|
+
url: testUrl,
|
|
232
|
+
plugins,
|
|
233
|
+
} as any);
|
|
234
|
+
}).toThrow(/Non of the installed plugins/);
|
|
149
235
|
});
|
|
150
236
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
237
|
+
it("handles malformed URLs gracefully", () => {
|
|
238
|
+
const testUrl = "invalid-url";
|
|
239
|
+
const finishCallback = jest.fn();
|
|
240
|
+
|
|
241
|
+
const onFinish = jest.fn((cb) => {
|
|
242
|
+
cb();
|
|
243
|
+
finishCallback();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
renderHook(
|
|
247
|
+
() =>
|
|
248
|
+
useUrlSchemeHandler({
|
|
249
|
+
url: testUrl,
|
|
250
|
+
onFinish,
|
|
251
|
+
}),
|
|
252
|
+
{ wrapper }
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
expect(log_warning).toBeCalled();
|
|
256
|
+
expect(finishCallback).toBeCalled();
|
|
162
257
|
});
|
|
163
|
-
|
|
164
|
-
expect(onFinish).toBeCalled();
|
|
165
258
|
});
|
|
166
259
|
});
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
useAppSelector,
|
|
3
|
-
selectContentTypes,
|
|
4
|
-
selectRivers,
|
|
5
|
-
} from "@applicaster/zapp-react-native-redux";
|
|
1
|
+
import { useContentTypes } from "@applicaster/zapp-react-native-redux";
|
|
6
2
|
import { ZappPipesEntryContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
|
|
7
3
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
8
4
|
import { useEffect } from "react";
|
|
@@ -24,6 +20,7 @@ import {
|
|
|
24
20
|
withInitialPlayerState,
|
|
25
21
|
} from "./utils";
|
|
26
22
|
import { log_warning } from "../../../logger";
|
|
23
|
+
import { useRivers } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
27
24
|
|
|
28
25
|
async function handleQuery({
|
|
29
26
|
query,
|
|
@@ -101,8 +98,8 @@ async function handleQuery({
|
|
|
101
98
|
}
|
|
102
99
|
|
|
103
100
|
export function useOpenSchemeHandler({ query, url, onFinish }) {
|
|
104
|
-
const rivers =
|
|
105
|
-
const contentTypes =
|
|
101
|
+
const rivers = useRivers();
|
|
102
|
+
const contentTypes = useContentTypes();
|
|
106
103
|
const navigator = useNavigation();
|
|
107
104
|
const homeId = getHomeScreenId(rivers);
|
|
108
105
|
const homeRoute = `/river/${homeId}`;
|
|
@@ -1,55 +1,59 @@
|
|
|
1
|
-
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
2
1
|
import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
|
|
3
|
-
import
|
|
2
|
+
import {
|
|
3
|
+
selectUrlSchemePlugins,
|
|
4
|
+
useAppSelector,
|
|
5
|
+
} from "@applicaster/zapp-react-native-redux";
|
|
4
6
|
|
|
5
7
|
import { schemeHandlerHooks } from ".";
|
|
6
8
|
import { parseUrl } from "../../helpers";
|
|
7
|
-
|
|
8
9
|
import { log_warning } from "../../logger";
|
|
10
|
+
import { getPluginModuleUrlScheme } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
9
11
|
|
|
10
12
|
type useUrlSchemeHandlerArgs = {
|
|
11
13
|
url: string;
|
|
12
14
|
onFinish: (callback: (done: () => void) => void) => void;
|
|
13
15
|
};
|
|
14
16
|
|
|
15
|
-
function resolveSchemeHandler(
|
|
17
|
+
function resolveSchemeHandler(
|
|
18
|
+
host: string,
|
|
19
|
+
eligiblePlugins: QuickBrickPlugin[]
|
|
20
|
+
) {
|
|
21
|
+
// First check built-in scheme handlers
|
|
16
22
|
if (schemeHandlerHooks?.[host]) return schemeHandlerHooks?.[host];
|
|
17
23
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (elligiblePlugins?.length > 0) {
|
|
24
|
-
const match = R.compose(
|
|
25
|
-
R.prop("handler"),
|
|
26
|
-
R.head,
|
|
27
|
-
R.filter(R.propEq("host", host)),
|
|
28
|
-
R.map(R.path(["module", "urlScheme"]))
|
|
29
|
-
)(elligiblePlugins);
|
|
24
|
+
if (eligiblePlugins?.length > 0) {
|
|
25
|
+
// Find the first plugin with matching host
|
|
26
|
+
const matchingPlugin = eligiblePlugins.find(
|
|
27
|
+
(plugin) => getPluginModuleUrlScheme(plugin)?.host === host
|
|
28
|
+
);
|
|
30
29
|
|
|
31
|
-
return
|
|
30
|
+
return getPluginModuleUrlScheme(matchingPlugin)?.handler || null;
|
|
32
31
|
}
|
|
33
|
-
}
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
`Non of the installed plugins knows how to handle this urlScheme ${url}`
|
|
38
|
-
);
|
|
39
|
-
};
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
40
35
|
|
|
41
36
|
export function useUrlSchemeHandler({
|
|
42
37
|
url,
|
|
43
38
|
onFinish,
|
|
44
39
|
}: useUrlSchemeHandlerArgs) {
|
|
45
40
|
const { host, query } = parseUrl(url);
|
|
46
|
-
const
|
|
41
|
+
const pluginsWithUrlScheme = useAppSelector(selectUrlSchemePlugins) || [];
|
|
47
42
|
|
|
48
|
-
const
|
|
49
|
-
resolveSchemeHandler(host, plugins) || skipSchemeHandle;
|
|
43
|
+
const schemeHandler = resolveSchemeHandler(host, pluginsWithUrlScheme);
|
|
50
44
|
|
|
51
45
|
try {
|
|
52
|
-
|
|
46
|
+
if (schemeHandler) {
|
|
47
|
+
schemeHandler({ query, url, onFinish });
|
|
48
|
+
} else {
|
|
49
|
+
onFinish((done) => {
|
|
50
|
+
log_warning(
|
|
51
|
+
`unable to resolve ${url}: No handler found for scheme ${host}`
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
done?.();
|
|
55
|
+
});
|
|
56
|
+
}
|
|
53
57
|
} catch (e) {
|
|
54
58
|
onFinish((done) => {
|
|
55
59
|
log_warning(`unable to resolve ${url}: ${e.message}`);
|
|
@@ -58,11 +62,19 @@ export function useUrlSchemeHandler({
|
|
|
58
62
|
}
|
|
59
63
|
}
|
|
60
64
|
|
|
61
|
-
export function handleActionSchemeUrl({
|
|
65
|
+
export function handleActionSchemeUrl({
|
|
66
|
+
url,
|
|
67
|
+
availablePlugins = appStore.get("plugins"),
|
|
68
|
+
}) {
|
|
62
69
|
const { host, query } = parseUrl(url);
|
|
63
|
-
const plugins = appStore.get("plugins");
|
|
64
70
|
|
|
65
|
-
const actionScheme = resolveSchemeHandler(host,
|
|
71
|
+
const actionScheme = resolveSchemeHandler(host, availablePlugins);
|
|
72
|
+
|
|
73
|
+
if (!actionScheme) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`Non of the installed plugins knows how to handle this urlScheme ${url}`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
66
78
|
|
|
67
79
|
actionScheme({ query, url });
|
|
68
80
|
}
|
|
@@ -30,7 +30,10 @@ export function URLSchemeHandler({ url, onFinish }: Props) {
|
|
|
30
30
|
useUrlSchemeHandler({ url, onFinish });
|
|
31
31
|
|
|
32
32
|
return (
|
|
33
|
-
<View
|
|
33
|
+
<View
|
|
34
|
+
testID="URLSchemeHandler"
|
|
35
|
+
style={[viewStyles.container, { width, height, backgroundColor }]}
|
|
36
|
+
>
|
|
34
37
|
<Spinner size="large" />
|
|
35
38
|
</View>
|
|
36
39
|
);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { StyleSheet } from "react-native";
|
|
3
|
+
import { cleanup } from "@testing-library/react-native";
|
|
4
|
+
import { renderWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
|
|
3
5
|
|
|
4
6
|
const theme = {
|
|
5
7
|
screen_margin_top: 0,
|
|
@@ -10,14 +12,6 @@ jest.mock(
|
|
|
10
12
|
"@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation"
|
|
11
13
|
);
|
|
12
14
|
|
|
13
|
-
jest.mock("@applicaster/zapp-react-native-utils/theme", () => ({
|
|
14
|
-
useTheme: jest.fn(() => theme),
|
|
15
|
-
}));
|
|
16
|
-
|
|
17
|
-
jest.mock("@applicaster/zapp-react-native-redux/hooks", () => ({
|
|
18
|
-
usePickFromState: jest.fn(() => ({})),
|
|
19
|
-
}));
|
|
20
|
-
|
|
21
15
|
const { URLSchemeHandler } = require("../URLSchemeHandler");
|
|
22
16
|
const schemeHooks = require("../SchemeHandlerHooks/useUrlSchemeHandler");
|
|
23
17
|
|
|
@@ -36,12 +30,25 @@ describe("URLSchemeHandler", () => {
|
|
|
36
30
|
|
|
37
31
|
afterEach(cleanup);
|
|
38
32
|
|
|
39
|
-
it("renders correctly and invokes the hook",
|
|
40
|
-
const wrapper =
|
|
41
|
-
|
|
33
|
+
it("renders correctly and invokes the hook", () => {
|
|
34
|
+
const wrapper = renderWithProviders(
|
|
35
|
+
<URLSchemeHandler url={url} onFinish={onFinish} />,
|
|
36
|
+
{},
|
|
37
|
+
theme
|
|
42
38
|
);
|
|
43
39
|
|
|
44
|
-
expect(wrapper.
|
|
40
|
+
expect(wrapper.getByTestId("URLSchemeHandler")).toBeTruthy();
|
|
41
|
+
|
|
42
|
+
expect(
|
|
43
|
+
StyleSheet.flatten(wrapper.getByTestId("URLSchemeHandler").props.style)
|
|
44
|
+
).toMatchObject({
|
|
45
|
+
alignItems: "center",
|
|
46
|
+
backgroundColor: "white",
|
|
47
|
+
flex: 1,
|
|
48
|
+
height: 1334,
|
|
49
|
+
justifyContent: "center",
|
|
50
|
+
width: 750,
|
|
51
|
+
});
|
|
45
52
|
|
|
46
53
|
expect(hookSpy).toHaveBeenCalledWith(
|
|
47
54
|
expect.objectContaining({ url, onFinish })
|
|
@@ -3,16 +3,15 @@ import React, { useCallback, useContext } from "react";
|
|
|
3
3
|
import { URLSchemeHandler } from "../URLSchemeHandler";
|
|
4
4
|
import { URLSchemeContext } from "./URLSchemeContextProvider";
|
|
5
5
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
6
|
-
import {
|
|
6
|
+
import { useAppSelector } from "@applicaster/zapp-react-native-redux/hooks";
|
|
7
|
+
import { selectAppReady } from "@applicaster/zapp-react-native-redux";
|
|
7
8
|
|
|
8
9
|
export function URLSchemeListener({ children }: { children: React.ReactNode }) {
|
|
9
10
|
const { url, done } = useContext(URLSchemeContext);
|
|
10
11
|
|
|
11
12
|
const navigator = useNavigation();
|
|
12
13
|
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
const appReady = appState?.appReady;
|
|
14
|
+
const appReady = useAppSelector(selectAppReady);
|
|
16
15
|
|
|
17
16
|
const onFinish = useCallback(
|
|
18
17
|
(callback) => {
|
|
@@ -2,8 +2,9 @@ import React from "react";
|
|
|
2
2
|
import { View, StyleSheet } from "react-native";
|
|
3
3
|
|
|
4
4
|
import { Spinner } from "@applicaster/zapp-react-native-ui-components/Components/Spinner";
|
|
5
|
-
import {
|
|
5
|
+
import { useAppSelector } from "@applicaster/zapp-react-native-redux/hooks";
|
|
6
6
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
7
|
+
import { selectAppLaunched } from "@applicaster/zapp-react-native-redux";
|
|
7
8
|
|
|
8
9
|
type Props = {
|
|
9
10
|
children: React.ReactChild;
|
|
@@ -21,9 +22,7 @@ const styles = StyleSheet.create({
|
|
|
21
22
|
});
|
|
22
23
|
|
|
23
24
|
export function Loader({ children }: Props) {
|
|
24
|
-
const
|
|
25
|
-
appState: { appLaunched },
|
|
26
|
-
} = usePickFromState(["appState"]);
|
|
25
|
+
const appLaunched = useAppSelector(selectAppLaunched);
|
|
27
26
|
|
|
28
27
|
const { currentRoute } = useNavigation();
|
|
29
28
|
|