@glomopay/react-native-sdk 1.3.4 → 2.0.1
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/README.md +9 -4
- package/lib/config/base.d.ts +14 -5
- package/lib/config/base.d.ts.map +1 -1
- package/lib/config/base.js +22 -6
- package/lib/glomo-lrs-checkout.d.ts.map +1 -1
- package/lib/glomo-lrs-checkout.js +156 -9
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/injections/index.d.ts +1 -0
- package/lib/injections/index.d.ts.map +1 -1
- package/lib/injections/index.js +2 -0
- package/lib/injections/webview-education-carousel.injection.d.ts +3 -0
- package/lib/injections/webview-education-carousel.injection.d.ts.map +1 -0
- package/lib/injections/webview-education-carousel.injection.js +157 -0
- package/lib/injections/webview-flow.injection.d.ts.map +1 -1
- package/lib/injections/webview-flow.injection.js +3 -5
- package/lib/injections/webview-main.injection.d.ts.map +1 -1
- package/lib/injections/webview-main.injection.js +3 -5
- package/lib/use-lrs-checkout.d.ts +14 -1
- package/lib/use-lrs-checkout.d.ts.map +1 -1
- package/lib/use-lrs-checkout.js +124 -8
- package/lib/utils/analytics.d.ts +11 -0
- package/lib/utils/analytics.d.ts.map +1 -1
- package/lib/utils/analytics.js +22 -0
- package/package.json +1 -1
- package/src/config/base.ts +35 -5
- package/src/glomo-lrs-checkout.tsx +206 -10
- package/src/index.ts +1 -0
- package/src/injections/index.ts +2 -0
- package/src/injections/webview-education-carousel.injection.ts +154 -0
- package/src/injections/webview-flow.injection.ts +3 -5
- package/src/injections/webview-main.injection.ts +3 -5
- package/src/use-lrs-checkout.tsx +161 -8
- package/src/utils/analytics.ts +29 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/** The GlomoPay LRS Checkout Component */
|
|
2
2
|
|
|
3
3
|
import React, { useMemo, useImperativeHandle, forwardRef } from "react";
|
|
4
|
-
import { StyleSheet, View, Modal, Platform } from "react-native";
|
|
5
|
-
import { WebView, type WebViewMessageEvent } from "react-native-webview";
|
|
4
|
+
import { StyleSheet, View, Modal, Platform, SafeAreaView, TouchableOpacity, Text } from "react-native";
|
|
5
|
+
import { WebView, type WebViewMessageEvent, type WebViewProps } from "react-native-webview";
|
|
6
6
|
|
|
7
7
|
import { useLrsCheckout, type UseLrsCheckoutOptions, type LrsCheckoutStatus } from "./use-lrs-checkout";
|
|
8
8
|
import { type SdkError } from "./utils/analytics";
|
|
@@ -21,7 +21,7 @@ export interface GlomoLrsCheckoutRef {
|
|
|
21
21
|
/**
|
|
22
22
|
* The Main GlomoPay LRS Checkout Component
|
|
23
23
|
*
|
|
24
|
-
* @param server - Optional. The
|
|
24
|
+
* @param server - Optional. The SDK server environment. For development builds ONLY.
|
|
25
25
|
* @param publicKey - The public key for the merchant. If it starts with "test_", mock mode will be enabled automatically. Otherwise, live mode is used.
|
|
26
26
|
* @param orderId - The order ID. Always starts with "order_"
|
|
27
27
|
*
|
|
@@ -54,10 +54,13 @@ function GlomoLrsCheckoutComponent(
|
|
|
54
54
|
) {
|
|
55
55
|
// Computing mockMode based on the publicKey prefix
|
|
56
56
|
const mockMode = useMemo(() => {
|
|
57
|
+
const resolvedMockMode = publicKey?.toLowerCase().startsWith("test_") ?? false;
|
|
57
58
|
if (devMode) {
|
|
58
|
-
console.log(
|
|
59
|
+
console.log(
|
|
60
|
+
`[GlomoPay RN SDK] ${resolvedMockMode ? "Using" : "Not using"} Mock mode for publicKey: ${publicKey}`
|
|
61
|
+
);
|
|
59
62
|
}
|
|
60
|
-
return
|
|
63
|
+
return resolvedMockMode;
|
|
61
64
|
}, [publicKey, devMode]);
|
|
62
65
|
|
|
63
66
|
const {
|
|
@@ -66,17 +69,23 @@ function GlomoLrsCheckoutComponent(
|
|
|
66
69
|
showCheckout,
|
|
67
70
|
flowWebViewUrl,
|
|
68
71
|
showFlowWebView,
|
|
72
|
+
educationCarouselUrl: resolvedEducationCarouselUrl,
|
|
73
|
+
educationCarouselState,
|
|
69
74
|
checkoutUrl,
|
|
70
75
|
mainWebViewRef,
|
|
71
76
|
flowWebViewRef,
|
|
77
|
+
educationCarouselWebViewRef,
|
|
72
78
|
handleMainWebViewMessage,
|
|
73
79
|
handleFlowWebViewMessage,
|
|
80
|
+
handleEducationCarouselWebViewMessage,
|
|
74
81
|
handleError,
|
|
75
82
|
handleHttpError,
|
|
76
83
|
handleNavigationStateChange,
|
|
77
84
|
handleModalBackButton,
|
|
85
|
+
handleFlowBack,
|
|
78
86
|
injectedMain,
|
|
79
87
|
injectedFlow,
|
|
88
|
+
injectedEducationCarousel,
|
|
80
89
|
} = useLrsCheckout(
|
|
81
90
|
{
|
|
82
91
|
server,
|
|
@@ -98,14 +107,73 @@ function GlomoLrsCheckoutComponent(
|
|
|
98
107
|
getStatus: () => status,
|
|
99
108
|
}));
|
|
100
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Injecting a viewport meta tag and CSS text-size-adjust guard into the carousel WebView on load.
|
|
112
|
+
* This prevents the OS from auto-scaling text (especially on Android), which can break the carousel layout.
|
|
113
|
+
*/
|
|
114
|
+
const carouselViewportGuardScript = useMemo(
|
|
115
|
+
() => `
|
|
116
|
+
(function() {
|
|
117
|
+
try {
|
|
118
|
+
var viewportContent = "width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover";
|
|
119
|
+
var viewportTag = document.querySelector("meta[name='viewport']");
|
|
120
|
+
|
|
121
|
+
if (!viewportTag) {
|
|
122
|
+
viewportTag = document.createElement("meta");
|
|
123
|
+
viewportTag.setAttribute("name", "viewport");
|
|
124
|
+
var headOrRoot = document.head || document.documentElement;
|
|
125
|
+
if (headOrRoot) {
|
|
126
|
+
headOrRoot.appendChild(viewportTag);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (viewportTag) {
|
|
131
|
+
viewportTag.setAttribute("content", viewportContent);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
var styleTagId = "__glomo_rn_webview_scale_guard__";
|
|
135
|
+
var existingStyleTag = document.getElementById(styleTagId);
|
|
136
|
+
if (!existingStyleTag) {
|
|
137
|
+
var styleTag = document.createElement("style");
|
|
138
|
+
styleTag.id = styleTagId;
|
|
139
|
+
styleTag.textContent = "html, body, * { -webkit-text-size-adjust: 100% !important; text-size-adjust: 100% !important; }";
|
|
140
|
+
var styleHost = document.head || document.documentElement;
|
|
141
|
+
if (styleHost) {
|
|
142
|
+
styleHost.appendChild(styleTag);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
} catch (error) {}
|
|
146
|
+
true;
|
|
147
|
+
})();
|
|
148
|
+
`,
|
|
149
|
+
[]
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Locking down zoom and scaling behaviour for the carousel WebView.
|
|
154
|
+
* setSupportZoom/scalesPageToFit prevent user-initiated and system-initiated zoom;
|
|
155
|
+
* textZoom=100 on Android normalises the system font-size setting so the carousel isn't affected.
|
|
156
|
+
*/
|
|
157
|
+
const carouselWebViewProps = useMemo<Partial<WebViewProps>>(
|
|
158
|
+
() => ({
|
|
159
|
+
setSupportZoom: false,
|
|
160
|
+
scalesPageToFit: false,
|
|
161
|
+
overScrollMode: "never",
|
|
162
|
+
textZoom: Platform.OS === "android" ? 100 : undefined,
|
|
163
|
+
}),
|
|
164
|
+
[]
|
|
165
|
+
);
|
|
166
|
+
|
|
101
167
|
// Making the WebView component
|
|
102
168
|
const makeWebView = React.useCallback(
|
|
103
169
|
(
|
|
104
170
|
ref: React.RefObject<WebView>,
|
|
105
171
|
url: string,
|
|
106
172
|
messageHandler: (event: WebViewMessageEvent) => void,
|
|
107
|
-
identifier: "main" | "flow",
|
|
108
|
-
injectedJavaScript?: string
|
|
173
|
+
identifier: "main" | "flow" | "educationCarousel",
|
|
174
|
+
injectedJavaScript?: string,
|
|
175
|
+
injectedJavaScriptBeforeContentLoaded?: string,
|
|
176
|
+
additionalProps?: Partial<WebViewProps>
|
|
109
177
|
) => {
|
|
110
178
|
// Preventing a render if no injection script is provided
|
|
111
179
|
if (!injectedJavaScript) {
|
|
@@ -145,6 +213,26 @@ function GlomoLrsCheckoutComponent(
|
|
|
145
213
|
onError={handleError}
|
|
146
214
|
onHttpError={handleHttpError}
|
|
147
215
|
onNavigationStateChange={handleNavigationStateChange}
|
|
216
|
+
onLoadStart={() => {
|
|
217
|
+
if (devMode) {
|
|
218
|
+
console.log(`[GlomoPay RN SDK] [${identifier}] WebView load started for ${url}`);
|
|
219
|
+
}
|
|
220
|
+
}}
|
|
221
|
+
onLoadEnd={() => {
|
|
222
|
+
if (identifier === "educationCarousel" && ref.current && carouselViewportGuardScript) {
|
|
223
|
+
ref.current.injectJavaScript(carouselViewportGuardScript);
|
|
224
|
+
}
|
|
225
|
+
if (devMode) {
|
|
226
|
+
console.log(`[GlomoPay RN SDK] [${identifier}] WebView load ended for ${url}`);
|
|
227
|
+
}
|
|
228
|
+
}}
|
|
229
|
+
onLoadProgress={({ nativeEvent }) => {
|
|
230
|
+
if (devMode && identifier === "educationCarousel") {
|
|
231
|
+
console.log(
|
|
232
|
+
`[GlomoPay RN SDK] [educationCarousel] load progress=${nativeEvent.progress} url=${nativeEvent.url}`
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
}}
|
|
148
236
|
source={{ uri: url }}
|
|
149
237
|
javaScriptCanOpenWindowsAutomatically={true}
|
|
150
238
|
setSupportMultipleWindows={true}
|
|
@@ -155,6 +243,7 @@ function GlomoLrsCheckoutComponent(
|
|
|
155
243
|
limitsNavigationsToAppBoundDomains={false}
|
|
156
244
|
menuItems={[]}
|
|
157
245
|
injectedJavaScript={injectedJavaScript}
|
|
246
|
+
injectedJavaScriptBeforeContentLoaded={injectedJavaScriptBeforeContentLoaded}
|
|
158
247
|
style={styles.webview}
|
|
159
248
|
showsHorizontalScrollIndicator={false}
|
|
160
249
|
showsVerticalScrollIndicator={false}
|
|
@@ -163,10 +252,11 @@ function GlomoLrsCheckoutComponent(
|
|
|
163
252
|
sharedCookiesEnabled={true}
|
|
164
253
|
allowsInlineMediaPlayback={true}
|
|
165
254
|
mediaPlaybackRequiresUserAction={false}
|
|
255
|
+
{...additionalProps}
|
|
166
256
|
/>
|
|
167
257
|
);
|
|
168
258
|
},
|
|
169
|
-
[handleError, handleHttpError, handleNavigationStateChange, devMode]
|
|
259
|
+
[handleError, handleHttpError, handleNavigationStateChange, devMode, carouselViewportGuardScript]
|
|
170
260
|
);
|
|
171
261
|
|
|
172
262
|
const MainWebViewComponent = useMemo(
|
|
@@ -182,6 +272,29 @@ function GlomoLrsCheckoutComponent(
|
|
|
182
272
|
[makeWebView, flowWebViewUrl, handleFlowWebViewMessage, injectedFlow, flowWebViewRef]
|
|
183
273
|
);
|
|
184
274
|
|
|
275
|
+
const EducationCarouselWebViewComponent = useMemo(
|
|
276
|
+
() =>
|
|
277
|
+
resolvedEducationCarouselUrl
|
|
278
|
+
? makeWebView(
|
|
279
|
+
educationCarouselWebViewRef,
|
|
280
|
+
resolvedEducationCarouselUrl,
|
|
281
|
+
handleEducationCarouselWebViewMessage,
|
|
282
|
+
"educationCarousel",
|
|
283
|
+
injectedEducationCarousel,
|
|
284
|
+
undefined,
|
|
285
|
+
carouselWebViewProps
|
|
286
|
+
)
|
|
287
|
+
: null,
|
|
288
|
+
[
|
|
289
|
+
makeWebView,
|
|
290
|
+
resolvedEducationCarouselUrl,
|
|
291
|
+
educationCarouselWebViewRef,
|
|
292
|
+
handleEducationCarouselWebViewMessage,
|
|
293
|
+
injectedEducationCarousel,
|
|
294
|
+
carouselWebViewProps,
|
|
295
|
+
]
|
|
296
|
+
);
|
|
297
|
+
|
|
185
298
|
// Using the controlled visible if provided, otherwise using the internal state
|
|
186
299
|
const isVisible = useMemo(() => controlledVisible ?? showCheckout, [controlledVisible, showCheckout]);
|
|
187
300
|
|
|
@@ -200,6 +313,22 @@ function GlomoLrsCheckoutComponent(
|
|
|
200
313
|
// Alias to ensure explicit component reference for React Native
|
|
201
314
|
const ModalComponent = Modal;
|
|
202
315
|
|
|
316
|
+
/**
|
|
317
|
+
* Deriving render gates from state:
|
|
318
|
+
* showCarousel: carousel WebView is visible only after it signals it has content
|
|
319
|
+
* shouldRenderFlowOverlay: flow overlay is mounted only when there is an active flow URL
|
|
320
|
+
* shouldRenderEducationCarousel: carousel is rendered inside the flow overlay (depends on shouldRenderFlowOverlay)
|
|
321
|
+
*/
|
|
322
|
+
const showCarousel = educationCarouselState === "hasContent";
|
|
323
|
+
const shouldRenderFlowOverlay = Boolean(showFlowWebView && flowWebViewUrl && FlowWebViewComponent);
|
|
324
|
+
const shouldRenderEducationCarousel = Boolean(shouldRenderFlowOverlay && EducationCarouselWebViewComponent);
|
|
325
|
+
|
|
326
|
+
if (devMode) {
|
|
327
|
+
console.log(
|
|
328
|
+
`[GlomoPay RN SDK] Render gates: modal=${shouldShowModal}, flowOverlay=${shouldRenderFlowOverlay}, educationCarouselWebView=${shouldRenderEducationCarousel}, educationCarouselVisible=${showCarousel}, flowWebViewUrl=${flowWebViewUrl || "<empty>"}, educationCarouselUrl=${resolvedEducationCarouselUrl || "<empty>"}`
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
|
|
203
332
|
return (
|
|
204
333
|
<ModalComponent
|
|
205
334
|
visible={shouldShowModal}
|
|
@@ -210,9 +339,36 @@ function GlomoLrsCheckoutComponent(
|
|
|
210
339
|
<View style={styles.modalContainer}>
|
|
211
340
|
<View style={styles.mainWebViewContainer}>{MainWebViewComponent}</View>
|
|
212
341
|
|
|
213
|
-
{
|
|
342
|
+
{shouldRenderFlowOverlay && (
|
|
214
343
|
<View style={styles.flowWebViewContainer}>
|
|
215
|
-
<
|
|
344
|
+
<SafeAreaView style={styles.flowHeader}>
|
|
345
|
+
<TouchableOpacity onPress={handleFlowBack} style={styles.flowBackButton}>
|
|
346
|
+
<Text style={styles.flowBackChevron}>‹</Text>
|
|
347
|
+
</TouchableOpacity>
|
|
348
|
+
</SafeAreaView>
|
|
349
|
+
<View style={styles.overlayContentContainer}>
|
|
350
|
+
{shouldRenderEducationCarousel && (
|
|
351
|
+
<View
|
|
352
|
+
pointerEvents={showCarousel ? "auto" : "none"}
|
|
353
|
+
style={[
|
|
354
|
+
styles.educationCarouselContainer,
|
|
355
|
+
showCarousel
|
|
356
|
+
? styles.educationCarouselContainerVisible
|
|
357
|
+
: styles.educationCarouselContainerHidden,
|
|
358
|
+
]}
|
|
359
|
+
>
|
|
360
|
+
{EducationCarouselWebViewComponent}
|
|
361
|
+
</View>
|
|
362
|
+
)}
|
|
363
|
+
<View
|
|
364
|
+
style={[
|
|
365
|
+
styles.flowWebViewContent,
|
|
366
|
+
showCarousel ? styles.flowWebViewContentWithCarousel : null,
|
|
367
|
+
]}
|
|
368
|
+
>
|
|
369
|
+
{FlowWebViewComponent}
|
|
370
|
+
</View>
|
|
371
|
+
</View>
|
|
216
372
|
</View>
|
|
217
373
|
)}
|
|
218
374
|
</View>
|
|
@@ -242,13 +398,53 @@ const styles = StyleSheet.create({
|
|
|
242
398
|
left: 0,
|
|
243
399
|
right: 0,
|
|
244
400
|
bottom: 0,
|
|
401
|
+
flexDirection: "column",
|
|
245
402
|
backgroundColor: "#fff",
|
|
246
403
|
zIndex: 99999,
|
|
247
404
|
elevation: 99999,
|
|
248
405
|
},
|
|
406
|
+
flowHeader: {
|
|
407
|
+
backgroundColor: "#fff",
|
|
408
|
+
borderBottomWidth: 1,
|
|
409
|
+
borderBottomColor: "#e0e0e0",
|
|
410
|
+
},
|
|
411
|
+
flowBackButton: {
|
|
412
|
+
paddingVertical: 0,
|
|
413
|
+
paddingLeft: 20,
|
|
414
|
+
},
|
|
415
|
+
flowBackChevron: {
|
|
416
|
+
fontSize: 42,
|
|
417
|
+
color: "#333",
|
|
418
|
+
lineHeight: 42,
|
|
419
|
+
},
|
|
249
420
|
flowWebViewContent: {
|
|
250
421
|
flex: 1,
|
|
251
422
|
},
|
|
423
|
+
flowWebViewContentWithCarousel: {
|
|
424
|
+
flex: 8.5,
|
|
425
|
+
},
|
|
426
|
+
overlayContentContainer: {
|
|
427
|
+
flex: 1,
|
|
428
|
+
},
|
|
429
|
+
educationCarouselContainer: {
|
|
430
|
+
flex: 1.5,
|
|
431
|
+
},
|
|
432
|
+
educationCarouselContainerVisible: {
|
|
433
|
+
opacity: 1,
|
|
434
|
+
zIndex: 2,
|
|
435
|
+
elevation: 2,
|
|
436
|
+
},
|
|
437
|
+
educationCarouselContainerHidden: {
|
|
438
|
+
position: "absolute",
|
|
439
|
+
top: 0,
|
|
440
|
+
left: 0,
|
|
441
|
+
width: 1,
|
|
442
|
+
height: 1,
|
|
443
|
+
opacity: 0,
|
|
444
|
+
zIndex: -1,
|
|
445
|
+
elevation: 0,
|
|
446
|
+
overflow: "hidden",
|
|
447
|
+
},
|
|
252
448
|
errorContainer: {
|
|
253
449
|
flex: 1,
|
|
254
450
|
justifyContent: "center",
|
package/src/index.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// Payload, status, and error types from the LRS Checkout flow
|
|
4
4
|
export { type GlomoLrsCheckoutPayload, type LrsCheckoutStatus } from "./use-lrs-checkout";
|
|
5
5
|
export { type SdkError } from "./utils/analytics";
|
|
6
|
+
export { type GlomoLrsServer } from "./config/base";
|
|
6
7
|
|
|
7
8
|
// Main UI Component for the LRS Checkout flow
|
|
8
9
|
export { GlomoLrsCheckout, type GlomoLrsCheckoutProps, type GlomoLrsCheckoutRef } from "./glomo-lrs-checkout";
|
package/src/injections/index.ts
CHANGED
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { injectedScript as mainScript } from "./webview-main.injection";
|
|
5
5
|
import { injectedScript as flowScript } from "./webview-flow.injection";
|
|
6
|
+
import { injectedScript as educationCarouselScript } from "./webview-education-carousel.injection";
|
|
6
7
|
|
|
7
8
|
export const InjectionScripts = {
|
|
8
9
|
main: mainScript,
|
|
9
10
|
flow: flowScript,
|
|
11
|
+
educationCarousel: educationCarouselScript,
|
|
10
12
|
};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/** Injection JavaScript for the Education Carousel WebView */
|
|
2
|
+
export const injectedScript: string = `
|
|
3
|
+
(function() {
|
|
4
|
+
// Handling the carousel
|
|
5
|
+
const LOG_PREFIX = 'EDUCATION_CAROUSEL_WEBVIEW: ';
|
|
6
|
+
|
|
7
|
+
function formatMessage(args) {
|
|
8
|
+
return args.map(function(arg) {
|
|
9
|
+
if (typeof arg === 'object') {
|
|
10
|
+
try {
|
|
11
|
+
return LOG_PREFIX + JSON.stringify(arg, null, 2);
|
|
12
|
+
} catch (error) {
|
|
13
|
+
return LOG_PREFIX + '[unserializable object]';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return LOG_PREFIX + String(arg);
|
|
18
|
+
}).join(' ');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function parseMessageData(rawData) {
|
|
22
|
+
if (typeof rawData === 'string') {
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(rawData);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
return rawData;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return rawData;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function forwardEducationStepsMessage(data, source) {
|
|
34
|
+
const parsedData = parseMessageData(data);
|
|
35
|
+
|
|
36
|
+
if (!parsedData || typeof parsedData !== 'object') {
|
|
37
|
+
safePostMessage({
|
|
38
|
+
type: 'console',
|
|
39
|
+
level: 'debug',
|
|
40
|
+
message: formatMessage(['Ignored non-object carousel message from ' + source, parsedData])
|
|
41
|
+
});
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (parsedData.type !== 'lrs.has_education_steps') {
|
|
46
|
+
safePostMessage({
|
|
47
|
+
type: 'console',
|
|
48
|
+
level: 'debug',
|
|
49
|
+
message: formatMessage(['Ignored unrelated carousel message from ' + source, parsedData])
|
|
50
|
+
});
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
safePostMessage({
|
|
55
|
+
type: 'lrs.has_education_steps',
|
|
56
|
+
value: Boolean(parsedData.value),
|
|
57
|
+
source: source,
|
|
58
|
+
payload: parsedData
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
safePostMessage({
|
|
62
|
+
type: 'console',
|
|
63
|
+
level: 'info',
|
|
64
|
+
message: formatMessage(['Forwarded lrs.has_education_steps from ' + source, parsedData])
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function safePostMessage(payload) {
|
|
69
|
+
try {
|
|
70
|
+
if (window.ReactNativeWebView && typeof window.ReactNativeWebView.postMessage === 'function') {
|
|
71
|
+
window.ReactNativeWebView.postMessage(JSON.stringify(payload));
|
|
72
|
+
}
|
|
73
|
+
} catch (error) {
|
|
74
|
+
originalError && originalError.call(console, LOG_PREFIX + 'Failed to post message to ReactNativeWebView', error);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Overriding console methods
|
|
79
|
+
const originalLog = console.log;
|
|
80
|
+
const originalWarn = console.warn;
|
|
81
|
+
const originalError = console.error;
|
|
82
|
+
const originalInfo = console.info;
|
|
83
|
+
|
|
84
|
+
console.log = function(...args) {
|
|
85
|
+
originalLog.apply(console, args);
|
|
86
|
+
safePostMessage({
|
|
87
|
+
type: 'console',
|
|
88
|
+
level: 'log',
|
|
89
|
+
message: formatMessage(args)
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
console.warn = function(...args) {
|
|
94
|
+
originalWarn.apply(console, args);
|
|
95
|
+
safePostMessage({
|
|
96
|
+
type: 'console',
|
|
97
|
+
level: 'warn',
|
|
98
|
+
message: formatMessage(args)
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
console.error = function(...args) {
|
|
103
|
+
originalError.apply(console, args);
|
|
104
|
+
safePostMessage({
|
|
105
|
+
type: 'console',
|
|
106
|
+
level: 'error',
|
|
107
|
+
message: formatMessage(args)
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
console.info = function(...args) {
|
|
112
|
+
originalInfo.apply(console, args);
|
|
113
|
+
safePostMessage({
|
|
114
|
+
type: 'console',
|
|
115
|
+
level: 'info',
|
|
116
|
+
message: formatMessage(args)
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// Listening for unhandled errors
|
|
121
|
+
window.addEventListener('error', function(event) {
|
|
122
|
+
safePostMessage({
|
|
123
|
+
type: 'console',
|
|
124
|
+
level: 'error',
|
|
125
|
+
message: LOG_PREFIX + 'Unhandled Error: ' + event.message + ' at ' + event.filename + ':' + event.lineno
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Listening for unhandled promise rejections
|
|
130
|
+
window.addEventListener('unhandledrejection', function(event) {
|
|
131
|
+
safePostMessage({
|
|
132
|
+
type: 'console',
|
|
133
|
+
level: 'error',
|
|
134
|
+
message: LOG_PREFIX + 'Unhandled Promise Rejection: ' + (event.reason?.toString() || 'Unknown')
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Listening for messages from the WebView
|
|
139
|
+
window.addEventListener('message', function(event) {
|
|
140
|
+
console.log(LOG_PREFIX + 'Message received from window: ' + event.data);
|
|
141
|
+
forwardEducationStepsMessage(event.data, 'window.message');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
document.addEventListener('message', function(event) {
|
|
145
|
+
console.log(LOG_PREFIX + 'Message received from document: ' + event.data);
|
|
146
|
+
forwardEducationStepsMessage(event.data, 'document.message');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Logging that injection is complete
|
|
150
|
+
console.log(LOG_PREFIX + 'GlomoPay WebView JavaScript injection complete and waiting for lrs.has_education_steps');
|
|
151
|
+
|
|
152
|
+
true; // Required for injected JavaScript
|
|
153
|
+
})();
|
|
154
|
+
`;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Injection JavaScript for the Secondary WebView */
|
|
2
2
|
export const injectedScript: string = `
|
|
3
3
|
(function() {
|
|
4
|
-
//
|
|
4
|
+
// Overriding console methods
|
|
5
5
|
const originalLog = console.log;
|
|
6
6
|
const originalWarn = console.warn;
|
|
7
7
|
const originalError = console.error;
|
|
@@ -58,8 +58,7 @@ export const injectedScript: string = `
|
|
|
58
58
|
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
59
59
|
type: 'console',
|
|
60
60
|
level: 'network',
|
|
61
|
-
message: "FLOW_WEBVIEW: " + 'FETCH RESPONSE: ' + url + ' - Status: ' + response.status
|
|
62
|
-
extraData: { data: response.responseText }
|
|
61
|
+
message: "FLOW_WEBVIEW: " + 'FETCH RESPONSE: ' + url + ' - Status: ' + response.status
|
|
63
62
|
}));
|
|
64
63
|
return response;
|
|
65
64
|
})
|
|
@@ -94,8 +93,7 @@ export const injectedScript: string = `
|
|
|
94
93
|
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
95
94
|
type: 'console',
|
|
96
95
|
level: 'network',
|
|
97
|
-
message: "FLOW_WEBVIEW: " + 'XHR RESPONSE: ' + this._url + ' - Status: ' + this.status
|
|
98
|
-
extraData: { data: this.responseText }
|
|
96
|
+
message: "FLOW_WEBVIEW: " + 'XHR RESPONSE: ' + this._url + ' - Status: ' + this.status
|
|
99
97
|
}));
|
|
100
98
|
});
|
|
101
99
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Injection JavaScript for the Primary WebView */
|
|
2
2
|
export const injectedScript: string = `
|
|
3
3
|
(function() {
|
|
4
|
-
//
|
|
4
|
+
// Overriding console methods
|
|
5
5
|
const originalLog = console.log;
|
|
6
6
|
const originalWarn = console.warn;
|
|
7
7
|
const originalError = console.error;
|
|
@@ -94,15 +94,13 @@ export const injectedScript: string = `
|
|
|
94
94
|
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
95
95
|
type: 'console',
|
|
96
96
|
level: 'network',
|
|
97
|
-
message: 'XHR RESPONSE LOAD: ' + this._url + ' - Status: ' + this.status
|
|
98
|
-
extraData: { data: this.responseText }
|
|
97
|
+
message: 'XHR RESPONSE LOAD: ' + this._url + ' - Status: ' + this.status
|
|
99
98
|
}));
|
|
100
99
|
} catch (e) {
|
|
101
100
|
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
102
101
|
type: 'console',
|
|
103
102
|
level: 'network',
|
|
104
|
-
message: 'XHR RESPONSE ERROR: ' + this._url + ' - Status: ' + this.status
|
|
105
|
-
extraData: { data: this.responseText }
|
|
103
|
+
message: 'XHR RESPONSE ERROR: ' + this._url + ' - Status: ' + this.status
|
|
106
104
|
}));
|
|
107
105
|
}
|
|
108
106
|
});
|