@applicaster/quick-brick-core 15.0.0-rc.129 → 15.0.0-rc.131
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__/usePresentSchemeHandler.test.tsx +72 -35
- package/App/DeepLinking/URLSchemeHandler/SchemeHandlerHooks/usePresentSchemeHandler.ts +14 -12
- package/App/DeepLinking/URLSchemeListener/URLSchemeContextProvider.tsx +59 -0
- package/App/DeepLinking/helpers/index.ts +3 -3
- package/package.json +8 -8
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import * as R from "ramda";
|
|
2
1
|
import axios from "axios";
|
|
3
|
-
import { renderHook } from "@testing-library/react-native";
|
|
2
|
+
import { renderHook, waitFor } from "@testing-library/react-native";
|
|
4
3
|
import { sessionStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/SessionStorage";
|
|
5
4
|
import * as helpers from "../../../helpers";
|
|
6
5
|
import * as feedLoader from "@applicaster/zapp-react-native-utils/reactHooks/feed/useFeedLoader";
|
|
7
6
|
import { WrappedWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
|
|
8
7
|
import { usePresentSchemeHandler } from "../usePresentSchemeHandler";
|
|
9
8
|
|
|
10
|
-
import configureStore from "redux-mock-store";
|
|
11
|
-
|
|
12
9
|
const rivers = {
|
|
13
10
|
A1234: {
|
|
14
11
|
id: "A1234",
|
|
@@ -28,8 +25,6 @@ jest.mock(
|
|
|
28
25
|
})
|
|
29
26
|
);
|
|
30
27
|
|
|
31
|
-
const mockStore = configureStore();
|
|
32
|
-
|
|
33
28
|
const helperSpy = jest.spyOn(helpers, "handlePresentNavigation");
|
|
34
29
|
const feedLoaderSpy = jest.spyOn(feedLoader, "useFeedLoader");
|
|
35
30
|
|
|
@@ -179,46 +174,88 @@ describe("usePresentSchemeHandler", () => {
|
|
|
179
174
|
});
|
|
180
175
|
|
|
181
176
|
describe("loading new river", () => {
|
|
182
|
-
|
|
183
|
-
const store = mockStore({ test: "test" });
|
|
184
|
-
|
|
185
|
-
const wrapper = WrappedWithProviders;
|
|
177
|
+
const query = { rivers_configuration_id: "layout-uuid" };
|
|
186
178
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
179
|
+
const baseSessionData = {
|
|
180
|
+
accountsAccountId: "account-123",
|
|
181
|
+
bundleIdentifier: "com.example.app",
|
|
182
|
+
app_family_id: "42",
|
|
183
|
+
version_name: "1.0.0",
|
|
184
|
+
};
|
|
190
185
|
|
|
191
|
-
|
|
192
|
-
|
|
186
|
+
let storageSpy: jest.SpyInstance;
|
|
187
|
+
let axiosGetSpy: jest.SpyInstance;
|
|
193
188
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
store: "store",
|
|
200
|
-
});
|
|
189
|
+
beforeEach(() => {
|
|
190
|
+
storageSpy = jest.spyOn(sessionStorage, "getAllItems");
|
|
191
|
+
axiosGetSpy = jest.spyOn(axios, "get");
|
|
192
|
+
axiosGetSpy.mockResolvedValue({ data: {} });
|
|
193
|
+
});
|
|
201
194
|
|
|
202
|
-
|
|
195
|
+
afterEach(() => {
|
|
196
|
+
storageSpy.mockRestore();
|
|
197
|
+
axiosGetSpy.mockRestore();
|
|
198
|
+
});
|
|
203
199
|
|
|
204
|
-
|
|
205
|
-
|
|
200
|
+
it("fetches the rivers, cell styles and presets mapping URLs", async () => {
|
|
201
|
+
storageSpy.mockResolvedValue({ ...baseSessionData, store: "store" });
|
|
206
202
|
|
|
207
203
|
renderHook(() => usePresentSchemeHandler({ query, url: "", onFinish }), {
|
|
208
|
-
wrapper,
|
|
204
|
+
wrapper: WrappedWithProviders,
|
|
209
205
|
});
|
|
210
206
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
207
|
+
await waitFor(() => {
|
|
208
|
+
expect(axiosGetSpy).toHaveBeenCalledWith(
|
|
209
|
+
expect.stringContaining("/layouts/layout-uuid.json")
|
|
210
|
+
);
|
|
211
|
+
});
|
|
212
|
+
});
|
|
217
213
|
|
|
218
|
-
|
|
214
|
+
describe("WEB_STORE_PLATFORM CDN store key mapping", () => {
|
|
215
|
+
it.each([
|
|
216
|
+
["samsung", "samsung_app_store"],
|
|
217
|
+
["lg", "lg_content_store"],
|
|
218
|
+
["vizio", "vizio_app_store"],
|
|
219
|
+
])(
|
|
220
|
+
'maps store="%s" to "%s" in the rivers URL',
|
|
221
|
+
async (store, expectedCdnKey) => {
|
|
222
|
+
storageSpy.mockResolvedValue({ ...baseSessionData, store });
|
|
223
|
+
|
|
224
|
+
renderHook(
|
|
225
|
+
() => usePresentSchemeHandler({ query, url: "", onFinish }),
|
|
226
|
+
{ wrapper: WrappedWithProviders }
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
await waitFor(() => {
|
|
230
|
+
expect(axiosGetSpy).toHaveBeenCalledWith(
|
|
231
|
+
expect.stringContaining(`/${expectedCdnKey}/`)
|
|
232
|
+
);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// Confirm the raw store name is NOT used in the URL
|
|
236
|
+
expect(axiosGetSpy).not.toHaveBeenCalledWith(
|
|
237
|
+
expect.stringContaining(`/${store}/`)
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
);
|
|
219
241
|
|
|
220
|
-
|
|
221
|
-
|
|
242
|
+
it("passes through an unmapped store value unchanged", async () => {
|
|
243
|
+
storageSpy.mockResolvedValue({
|
|
244
|
+
...baseSessionData,
|
|
245
|
+
store: "apple_tv",
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
renderHook(
|
|
249
|
+
() => usePresentSchemeHandler({ query, url: "", onFinish }),
|
|
250
|
+
{ wrapper: WrappedWithProviders }
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
await waitFor(() => {
|
|
254
|
+
expect(axiosGetSpy).toHaveBeenCalledWith(
|
|
255
|
+
expect.stringContaining("/apple_tv/")
|
|
256
|
+
);
|
|
257
|
+
});
|
|
258
|
+
});
|
|
222
259
|
});
|
|
223
260
|
});
|
|
224
261
|
|
|
@@ -101,26 +101,28 @@ export function usePresentSchemeHandler({
|
|
|
101
101
|
|
|
102
102
|
// @ts-ignore - to be fixed on iOS side
|
|
103
103
|
// key accountsAccountID should be accountsAccountId
|
|
104
|
-
const accountId = getKeyFromStorage
|
|
104
|
+
const accountId = getKeyFromStorage(accountKey, sessionData);
|
|
105
105
|
|
|
106
|
-
const appBundleIdentifier = getKeyFromStorage
|
|
106
|
+
const appBundleIdentifier = getKeyFromStorage(
|
|
107
107
|
"bundleIdentifier",
|
|
108
108
|
sessionData
|
|
109
109
|
);
|
|
110
110
|
|
|
111
|
-
const versionName = getKeyFromStorage
|
|
112
|
-
"version_name",
|
|
113
|
-
sessionData
|
|
114
|
-
);
|
|
111
|
+
const versionName = getKeyFromStorage("version_name", sessionData);
|
|
115
112
|
|
|
116
|
-
const familyId = getKeyFromStorage
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
113
|
+
const familyId = getKeyFromStorage("app_family_id", sessionData);
|
|
114
|
+
|
|
115
|
+
const storeKey = getKeyFromStorage("store", sessionData);
|
|
116
|
+
|
|
117
|
+
const WEB_STORE_PLATFORM: Record<string, string> = {
|
|
118
|
+
samsung: "samsung_app_store",
|
|
119
|
+
lg: "lg_content_store",
|
|
120
|
+
vizio: "vizio_app_store",
|
|
121
|
+
};
|
|
120
122
|
|
|
121
|
-
const
|
|
123
|
+
const cdnStoreKey = WEB_STORE_PLATFORM[storeKey] ?? storeKey;
|
|
122
124
|
|
|
123
|
-
const riversUrl = `https://assets-secure.applicaster.com/zapp/accounts/${accountId}/apps/${appBundleIdentifier}/${
|
|
125
|
+
const riversUrl = `https://assets-secure.applicaster.com/zapp/accounts/${accountId}/apps/${appBundleIdentifier}/${cdnStoreKey}/${versionName}/layouts/${rivers_configuration_id}.json`;
|
|
124
126
|
|
|
125
127
|
const cellStylesUrl = `https://assets-secure.applicaster.com/zapp/accounts/${accountId}/app_families/${familyId}/layouts/${rivers_configuration_id}/cell_styles.json`;
|
|
126
128
|
|
|
@@ -10,6 +10,7 @@ import * as ReactNative from "react-native";
|
|
|
10
10
|
|
|
11
11
|
import { isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
12
12
|
import { log_debug, log_error, log_info } from "../logger";
|
|
13
|
+
import { parseUrl } from "../helpers";
|
|
13
14
|
import { getAppUrlScheme } from "@applicaster/zapp-react-native-utils/appDataUtils";
|
|
14
15
|
import {
|
|
15
16
|
getZappPlatform,
|
|
@@ -47,6 +48,24 @@ const getWebDeepLink = (initialURL: string) => {
|
|
|
47
48
|
return getAppUrlScheme() + "://open" + initialURL.slice(index);
|
|
48
49
|
};
|
|
49
50
|
|
|
51
|
+
const getPresentDeepLink = (
|
|
52
|
+
initialURL: string | null | undefined
|
|
53
|
+
): string | null => {
|
|
54
|
+
if (!initialURL) return null;
|
|
55
|
+
|
|
56
|
+
const index = initialURL.indexOf("?");
|
|
57
|
+
if (index === -1) return null;
|
|
58
|
+
|
|
59
|
+
const { query } = parseUrl(initialURL);
|
|
60
|
+
if (!query?.rivers_configuration_id) return null;
|
|
61
|
+
|
|
62
|
+
return getAppUrlScheme() + "://present" + initialURL.slice(index);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const triggerUrlScheme = (url: string): void => {
|
|
66
|
+
DeviceEventEmitter.emit("handleOpenUrl", { url });
|
|
67
|
+
};
|
|
68
|
+
|
|
50
69
|
function URLSchemeContextProvider(props: Props) {
|
|
51
70
|
const [state, setState] = useState<string | null>(initialState.url);
|
|
52
71
|
|
|
@@ -67,6 +86,16 @@ function URLSchemeContextProvider(props: Props) {
|
|
|
67
86
|
const url = await Linking.getInitialURL();
|
|
68
87
|
|
|
69
88
|
if (isWeb()) {
|
|
89
|
+
const presentDeepLink = getPresentDeepLink(url);
|
|
90
|
+
|
|
91
|
+
if (presentDeepLink) {
|
|
92
|
+
log_info(
|
|
93
|
+
`URLSchemeContextProvider: Retrieved initial deep link: ${presentDeepLink}`
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
return setState(presentDeepLink);
|
|
97
|
+
}
|
|
98
|
+
|
|
70
99
|
if (getZappPlatform() === ZappPlatform.Vizio) {
|
|
71
100
|
const deepLink = getWebDeepLink(url);
|
|
72
101
|
|
|
@@ -127,6 +156,36 @@ function URLSchemeContextProvider(props: Props) {
|
|
|
127
156
|
};
|
|
128
157
|
}
|
|
129
158
|
|
|
159
|
+
if (isWeb()) {
|
|
160
|
+
log_debug(
|
|
161
|
+
`URLSchemeContextProvider: Register DeviceEventEmitter "handleOpenUrl" listener — Platform.OS=${Platform.OS}`
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
const listener = DeviceEventEmitter.addListener(
|
|
165
|
+
"handleOpenUrl",
|
|
166
|
+
({ url: eventUrl }) => {
|
|
167
|
+
if (eventUrl) {
|
|
168
|
+
log_info(
|
|
169
|
+
`URLSchemeContextProvider: DeviceEventEmitter "handleOpenUrl" received — url=${eventUrl}`
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
setState(eventUrl);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
const linkingListener = Linking.addEventListener(
|
|
178
|
+
URL_EVENT_TYPE,
|
|
179
|
+
handleOpenURL
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
return () => {
|
|
183
|
+
log_debug("URLSchemeContextProvider: Remove URL event listeners");
|
|
184
|
+
listener.remove();
|
|
185
|
+
linkingListener.remove();
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
130
189
|
log_debug("URLSchemeContextProvider: Register URL event listener");
|
|
131
190
|
|
|
132
191
|
const listener = Linking.addEventListener(URL_EVENT_TYPE, handleOpenURL);
|
|
@@ -120,13 +120,13 @@ export function isInternalUrl(url = "") {
|
|
|
120
120
|
return query?.isInternalLink;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
export function getKeyFromStorage
|
|
123
|
+
export function getKeyFromStorage(
|
|
124
124
|
key: keyof SessionStorageKeys,
|
|
125
125
|
sessionData: Partial<SessionStorageKeys>
|
|
126
|
-
):
|
|
126
|
+
): string {
|
|
127
127
|
if (!sessionData[key]) {
|
|
128
128
|
throw new Error(`${key} is not available in session storage data`);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
return
|
|
131
|
+
return String(sessionData[key]).replace(/"/g, "");
|
|
132
132
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/quick-brick-core",
|
|
3
|
-
"version": "15.0.0-rc.
|
|
3
|
+
"version": "15.0.0-rc.131",
|
|
4
4
|
"description": "Core package for Applicaster's Quick Brick App",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -28,13 +28,13 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@applicaster/applicaster-types": "15.0.0-rc.
|
|
32
|
-
"@applicaster/quick-brick-core-plugins": "15.0.0-rc.
|
|
33
|
-
"@applicaster/zapp-pipes-v2-client": "15.0.0-rc.
|
|
34
|
-
"@applicaster/zapp-react-native-bridge": "15.0.0-rc.
|
|
35
|
-
"@applicaster/zapp-react-native-redux": "15.0.0-rc.
|
|
36
|
-
"@applicaster/zapp-react-native-ui-components": "15.0.0-rc.
|
|
37
|
-
"@applicaster/zapp-react-native-utils": "15.0.0-rc.
|
|
31
|
+
"@applicaster/applicaster-types": "15.0.0-rc.131",
|
|
32
|
+
"@applicaster/quick-brick-core-plugins": "15.0.0-rc.131",
|
|
33
|
+
"@applicaster/zapp-pipes-v2-client": "15.0.0-rc.131",
|
|
34
|
+
"@applicaster/zapp-react-native-bridge": "15.0.0-rc.131",
|
|
35
|
+
"@applicaster/zapp-react-native-redux": "15.0.0-rc.131",
|
|
36
|
+
"@applicaster/zapp-react-native-ui-components": "15.0.0-rc.131",
|
|
37
|
+
"@applicaster/zapp-react-native-utils": "15.0.0-rc.131",
|
|
38
38
|
"atob": "^2.1.2",
|
|
39
39
|
"axios": "^0.28.0",
|
|
40
40
|
"btoa": "^1.2.1",
|