@glomopay/react-native-sdk 2.0.1 → 3.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/CHANGELOG.md +64 -0
- package/README.md +261 -314
- package/lib/config/base.d.ts +17 -11
- package/lib/config/base.d.ts.map +1 -1
- package/lib/config/base.js +19 -7
- package/lib/config/segment.js +3 -3
- package/lib/glomo-checkout.d.ts +8 -0
- package/lib/glomo-checkout.d.ts.map +1 -0
- package/lib/glomo-checkout.js +69 -0
- package/lib/glomo-lrs-checkout.d.ts.map +1 -1
- package/lib/glomo-lrs-checkout.js +9 -9
- package/lib/glomo-standard-checkout.d.ts +5 -0
- package/lib/glomo-standard-checkout.d.ts.map +1 -0
- package/lib/glomo-standard-checkout.js +218 -0
- package/lib/index.d.ts +5 -4
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +7 -5
- 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-flow.injection.d.ts.map +1 -1
- package/lib/injections/webview-flow.injection.js +106 -69
- package/lib/injections/webview-main.injection.d.ts.map +1 -1
- package/lib/injections/webview-main.injection.js +112 -77
- package/lib/injections/webview-standard.injection.d.ts +3 -0
- package/lib/injections/webview-standard.injection.d.ts.map +1 -0
- package/lib/injections/webview-standard.injection.js +214 -0
- package/lib/services/order-type-fetcher.d.ts +28 -0
- package/lib/services/order-type-fetcher.d.ts.map +1 -0
- package/lib/services/order-type-fetcher.js +99 -0
- package/lib/types/checkout.d.ts +53 -0
- package/lib/types/checkout.d.ts.map +1 -0
- package/lib/types/checkout.js +3 -0
- package/lib/types/standard-checkout.d.ts +40 -0
- package/lib/types/standard-checkout.d.ts.map +1 -0
- package/lib/types/standard-checkout.js +3 -0
- package/lib/use-glomo-checkout.d.ts +24 -0
- package/lib/use-glomo-checkout.d.ts.map +1 -0
- package/lib/use-glomo-checkout.js +182 -0
- package/lib/use-lrs-checkout.d.ts +9 -4
- package/lib/use-lrs-checkout.d.ts.map +1 -1
- package/lib/use-lrs-checkout.js +91 -93
- package/lib/use-standard-checkout.d.ts +65 -0
- package/lib/use-standard-checkout.d.ts.map +1 -0
- package/lib/use-standard-checkout.js +832 -0
- package/lib/utils/analytics.d.ts +102 -1
- package/lib/utils/analytics.d.ts.map +1 -1
- package/lib/utils/analytics.js +294 -21
- package/lib/utils/device-compliance.js +3 -3
- package/lib/utils/validation.d.ts.map +1 -1
- package/lib/utils/validation.js +7 -6
- package/package.json +3 -2
- package/src/config/base.ts +36 -17
- package/src/config/segment.ts +3 -3
- package/src/glomo-checkout.tsx +73 -0
- package/src/glomo-lrs-checkout.tsx +13 -10
- package/src/glomo-standard-checkout.tsx +324 -0
- package/src/index.ts +13 -7
- package/src/injections/index.ts +2 -0
- package/src/injections/webview-flow.injection.ts +106 -69
- package/src/injections/webview-main.injection.ts +112 -77
- package/src/injections/webview-standard.injection.ts +211 -0
- package/src/services/order-type-fetcher.ts +86 -0
- package/src/types/checkout.ts +65 -0
- package/src/types/standard-checkout.ts +49 -0
- package/src/use-glomo-checkout.tsx +228 -0
- package/src/use-lrs-checkout.tsx +115 -111
- package/src/use-standard-checkout.tsx +1185 -0
- package/src/utils/analytics.ts +431 -22
- package/src/utils/device-compliance.ts +3 -3
- package/src/utils/validation.ts +7 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glomopay/react-native-sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "The React Native SDK for GlomoPay",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
"homepage": "https://github.com/glomopay/glomopay-rn-sdk#readme",
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"axios": "
|
|
52
|
+
"axios": "1.13.2"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"react": ">=17.0.0",
|
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
"lib",
|
|
71
71
|
"src",
|
|
72
72
|
"README.md",
|
|
73
|
+
"CHANGELOG.md",
|
|
73
74
|
"LICENSE"
|
|
74
75
|
],
|
|
75
76
|
"engines": {
|
package/src/config/base.ts
CHANGED
|
@@ -3,37 +3,56 @@
|
|
|
3
3
|
* This file contains the default base configuration variables for the GlomoPay RN SDK.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
/** The publicly documented server environments for the SDK */
|
|
7
|
-
export type
|
|
6
|
+
/** The publicly documented server environments for the SDK (v3 alias) */
|
|
7
|
+
export type GlomoServer = "prod" | "staging";
|
|
8
8
|
|
|
9
|
-
/** Internal extension that adds "local" for development use
|
|
10
|
-
type
|
|
9
|
+
/** Internal extension that adds "local" for development use - not exported */
|
|
10
|
+
type InternalGlomoServer = GlomoServer | "local";
|
|
11
11
|
|
|
12
12
|
/** Base URLs for a given server environment */
|
|
13
|
-
export interface
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
export interface GlomoServerBaseUrls {
|
|
14
|
+
lrsCheckout: string;
|
|
15
|
+
standardCheckout: string;
|
|
16
|
+
lrsEducationCarousel: string;
|
|
17
|
+
api: string;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
/** Server config with nested base URLs */
|
|
21
|
+
export interface GlomoServerConfig {
|
|
22
|
+
baseUrl: GlomoServerBaseUrls;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const DEFAULT_SERVER: InternalGlomoServer = "prod";
|
|
19
26
|
|
|
20
|
-
export const SERVER_CONFIGS: Record<
|
|
27
|
+
export const SERVER_CONFIGS: Record<InternalGlomoServer, GlomoServerConfig> = {
|
|
21
28
|
prod: {
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
baseUrl: {
|
|
30
|
+
lrsCheckout: "https://lrs-checkout.glomopay.com/",
|
|
31
|
+
standardCheckout: "https://checkout.glomopay.com/",
|
|
32
|
+
lrsEducationCarousel: "https://glomopay-utilities.web.app/lrs-education-carousel/",
|
|
33
|
+
api: "https://api.glomopay.com",
|
|
34
|
+
},
|
|
24
35
|
},
|
|
25
36
|
staging: {
|
|
26
|
-
|
|
27
|
-
|
|
37
|
+
baseUrl: {
|
|
38
|
+
lrsCheckout: "https://lrs-checkout-page-staging.web.app/",
|
|
39
|
+
standardCheckout: "https://glomopay-checkout-page-staging.web.app/",
|
|
40
|
+
lrsEducationCarousel: "https://glomopay-utilities-staging.web.app/lrs-education-carousel/",
|
|
41
|
+
api: "https://staging-api.glomopay.com",
|
|
42
|
+
},
|
|
28
43
|
},
|
|
29
44
|
local: {
|
|
30
|
-
|
|
31
|
-
|
|
45
|
+
baseUrl: {
|
|
46
|
+
lrsCheckout: "http://localhost:6870/",
|
|
47
|
+
standardCheckout: "http://localhost:4444/",
|
|
48
|
+
lrsEducationCarousel: "http://localhost:6871/lrs-education-carousel/",
|
|
49
|
+
api: "http://localhost:3000",
|
|
50
|
+
},
|
|
32
51
|
},
|
|
33
52
|
};
|
|
34
53
|
|
|
35
|
-
/** Returns the server config for the given environment, falling back to
|
|
36
|
-
export function resolveServerConfig(server?:
|
|
54
|
+
/** Returns the full server config for the given environment, falling back to prod */
|
|
55
|
+
export function resolveServerConfig(server?: InternalGlomoServer): GlomoServerConfig {
|
|
37
56
|
const resolvedServer = server && server in SERVER_CONFIGS ? server : DEFAULT_SERVER;
|
|
38
57
|
|
|
39
58
|
return SERVER_CONFIGS[resolvedServer];
|
package/src/config/segment.ts
CHANGED
|
@@ -67,7 +67,7 @@ export function initializeSegment(devMode: boolean = false): boolean {
|
|
|
67
67
|
// Preventing multiple initialization attempts
|
|
68
68
|
if (initializationAttempted) {
|
|
69
69
|
if (devMode) {
|
|
70
|
-
console.log("[
|
|
70
|
+
console.log("[Glomo-RN-SDK] Segment initialization already attempted");
|
|
71
71
|
}
|
|
72
72
|
return segmentApiClient !== null;
|
|
73
73
|
}
|
|
@@ -91,14 +91,14 @@ export function initializeSegment(devMode: boolean = false): boolean {
|
|
|
91
91
|
});
|
|
92
92
|
|
|
93
93
|
if (devMode) {
|
|
94
|
-
console.log("[
|
|
94
|
+
console.log("[Glomo-RN-SDK] Segment Analytics initialized successfully");
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
return true;
|
|
98
98
|
} catch (error) {
|
|
99
99
|
if (devMode) {
|
|
100
100
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
101
|
-
console.error("[
|
|
101
|
+
console.error("[Glomo-RN-SDK] Failed to initialize Segment:", errorMessage);
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
// Resetting the flag to allow retrying if needed
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The unified GlomoPay Checkout Component (v3).
|
|
3
|
+
* Detects order type (LRS vs Standard) and delegates rendering to the appropriate inner component.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React, { useImperativeHandle, forwardRef } from "react";
|
|
7
|
+
|
|
8
|
+
import { useGlomoCheckout } from "./use-glomo-checkout";
|
|
9
|
+
import { type GlomoCheckoutRef, type GlomoCheckoutProps } from "./types/checkout";
|
|
10
|
+
import { GlomoLrsCheckout } from "./glomo-lrs-checkout";
|
|
11
|
+
import { GlomoStandardCheckout } from "./glomo-standard-checkout";
|
|
12
|
+
|
|
13
|
+
function GlomoCheckoutComponent(props: GlomoCheckoutProps, ref: React.ForwardedRef<GlomoCheckoutRef>) {
|
|
14
|
+
// useGlomoCheckout handles order type detection and exposes start/getStatus for the ref
|
|
15
|
+
const { orderType, start, getStatus, innerLrsRef, innerStandardRef, props: passedProps } = useGlomoCheckout(props);
|
|
16
|
+
|
|
17
|
+
// Exposing start() and getStatus() via the forwarded ref for the merchant to call
|
|
18
|
+
useImperativeHandle(ref, () => ({
|
|
19
|
+
start,
|
|
20
|
+
getStatus,
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
// Delegating to the LRS checkout component once order type is resolved as LRS
|
|
24
|
+
if (orderType === "lrs") {
|
|
25
|
+
return (
|
|
26
|
+
<GlomoLrsCheckout
|
|
27
|
+
ref={innerLrsRef}
|
|
28
|
+
server={passedProps.server}
|
|
29
|
+
publicKey={passedProps.publicKey}
|
|
30
|
+
orderId={passedProps.orderId}
|
|
31
|
+
onPaymentSuccess={passedProps.onPaymentSuccess}
|
|
32
|
+
onPaymentFailure={passedProps.onPaymentFailure}
|
|
33
|
+
onConnectionError={passedProps.onConnectionError}
|
|
34
|
+
onPaymentTerminate={passedProps.onPaymentTerminate}
|
|
35
|
+
onSdkError={passedProps.onSdkError}
|
|
36
|
+
devMode={passedProps.devMode}
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Delegating to the Standard checkout component once order type is resolved as Standard
|
|
42
|
+
if (orderType === "standard") {
|
|
43
|
+
return (
|
|
44
|
+
<GlomoStandardCheckout
|
|
45
|
+
ref={innerStandardRef}
|
|
46
|
+
server={passedProps.server}
|
|
47
|
+
publicKey={passedProps.publicKey}
|
|
48
|
+
orderId={passedProps.orderId}
|
|
49
|
+
onPaymentSuccess={passedProps.onPaymentSuccess}
|
|
50
|
+
onPaymentFailure={passedProps.onPaymentFailure}
|
|
51
|
+
onConnectionError={passedProps.onConnectionError}
|
|
52
|
+
onPaymentTerminate={passedProps.onPaymentTerminate}
|
|
53
|
+
onSdkError={passedProps.onSdkError}
|
|
54
|
+
onBankTransferSubmitted={passedProps.onBankTransferSubmitted}
|
|
55
|
+
onPayViaBankCompleted={passedProps.onPayViaBankCompleted}
|
|
56
|
+
onPayViaBankBankConnectionSuccessful={passedProps.onPayViaBankBankConnectionSuccessful}
|
|
57
|
+
onUserRefusedCameraPermissions={passedProps.onUserRefusedCameraPermissions}
|
|
58
|
+
devMode={passedProps.devMode}
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* No modal for detecting state - avoids iOS pageSheet conflict where
|
|
65
|
+
* dismissing the detecting modal interferes with the checkout modal presentation.
|
|
66
|
+
* The order type detection is fast enough that a loading indicator is not needed.
|
|
67
|
+
*/
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const GlomoCheckout = forwardRef<GlomoCheckoutRef, GlomoCheckoutProps>(GlomoCheckoutComponent);
|
|
72
|
+
|
|
73
|
+
GlomoCheckout.displayName = "GlomoCheckout";
|
|
@@ -57,7 +57,7 @@ function GlomoLrsCheckoutComponent(
|
|
|
57
57
|
const resolvedMockMode = publicKey?.toLowerCase().startsWith("test_") ?? false;
|
|
58
58
|
if (devMode) {
|
|
59
59
|
console.log(
|
|
60
|
-
`[
|
|
60
|
+
`[Glomo-RN-SDK LRS] ${resolvedMockMode ? "Using" : "Not using"} Mock mode for publicKey: ${publicKey}`
|
|
61
61
|
);
|
|
62
62
|
}
|
|
63
63
|
return resolvedMockMode;
|
|
@@ -179,7 +179,7 @@ function GlomoLrsCheckoutComponent(
|
|
|
179
179
|
if (!injectedJavaScript) {
|
|
180
180
|
if (devMode) {
|
|
181
181
|
console.warn(
|
|
182
|
-
`[
|
|
182
|
+
`[Glomo-RN-SDK LRS] JavaScript Injection missing for ${url}. Skipping ${identifier} Render.`
|
|
183
183
|
);
|
|
184
184
|
}
|
|
185
185
|
return null;
|
|
@@ -191,14 +191,14 @@ function GlomoLrsCheckoutComponent(
|
|
|
191
191
|
if (!isValidUrl(url)) {
|
|
192
192
|
if (devMode) {
|
|
193
193
|
console.error(
|
|
194
|
-
`[
|
|
194
|
+
`[Glomo-RN-SDK LRS] Invalid non-empty URL ${url} provided. Skipping ${identifier} Render.`
|
|
195
195
|
);
|
|
196
196
|
}
|
|
197
197
|
return null;
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
if (devMode) {
|
|
201
|
-
console.error(`[
|
|
201
|
+
console.error(`[Glomo-RN-SDK LRS] Empty or invalid URL provided. Skipping ${identifier} Render.`);
|
|
202
202
|
}
|
|
203
203
|
return null;
|
|
204
204
|
}
|
|
@@ -215,7 +215,7 @@ function GlomoLrsCheckoutComponent(
|
|
|
215
215
|
onNavigationStateChange={handleNavigationStateChange}
|
|
216
216
|
onLoadStart={() => {
|
|
217
217
|
if (devMode) {
|
|
218
|
-
console.log(`[
|
|
218
|
+
console.log(`[Glomo-RN-SDK LRS] [${identifier}] WebView load started for ${url}`);
|
|
219
219
|
}
|
|
220
220
|
}}
|
|
221
221
|
onLoadEnd={() => {
|
|
@@ -223,13 +223,13 @@ function GlomoLrsCheckoutComponent(
|
|
|
223
223
|
ref.current.injectJavaScript(carouselViewportGuardScript);
|
|
224
224
|
}
|
|
225
225
|
if (devMode) {
|
|
226
|
-
console.log(`[
|
|
226
|
+
console.log(`[Glomo-RN-SDK LRS] [${identifier}] WebView load ended for ${url}`);
|
|
227
227
|
}
|
|
228
228
|
}}
|
|
229
229
|
onLoadProgress={({ nativeEvent }) => {
|
|
230
230
|
if (devMode && identifier === "educationCarousel") {
|
|
231
231
|
console.log(
|
|
232
|
-
`[
|
|
232
|
+
`[Glomo-RN-SDK LRS] [educationCarousel] load progress=${nativeEvent.progress} url=${nativeEvent.url}`
|
|
233
233
|
);
|
|
234
234
|
}
|
|
235
235
|
}}
|
|
@@ -304,7 +304,7 @@ function GlomoLrsCheckoutComponent(
|
|
|
304
304
|
|
|
305
305
|
if (devMode) {
|
|
306
306
|
console.log(
|
|
307
|
-
`[
|
|
307
|
+
`[Glomo-RN-SDK LRS] computed visibilityHook: ${value} for internal switch ${isVisible}, and checkout=${checkoutUrl};`
|
|
308
308
|
);
|
|
309
309
|
}
|
|
310
310
|
return value;
|
|
@@ -325,7 +325,7 @@ function GlomoLrsCheckoutComponent(
|
|
|
325
325
|
|
|
326
326
|
if (devMode) {
|
|
327
327
|
console.log(
|
|
328
|
-
`[
|
|
328
|
+
`[Glomo-RN-SDK LRS] Render gates: modal=${shouldShowModal}, flowOverlay=${shouldRenderFlowOverlay}, educationCarouselWebView=${shouldRenderEducationCarousel}, educationCarouselVisible=${showCarousel}, flowWebViewUrl=${flowWebViewUrl || "<empty>"}, educationCarouselUrl=${resolvedEducationCarouselUrl || "<empty>"}`
|
|
329
329
|
);
|
|
330
330
|
}
|
|
331
331
|
|
|
@@ -342,7 +342,10 @@ function GlomoLrsCheckoutComponent(
|
|
|
342
342
|
{shouldRenderFlowOverlay && (
|
|
343
343
|
<View style={styles.flowWebViewContainer}>
|
|
344
344
|
<SafeAreaView style={styles.flowHeader}>
|
|
345
|
-
<TouchableOpacity
|
|
345
|
+
<TouchableOpacity
|
|
346
|
+
onPress={handleFlowBack}
|
|
347
|
+
style={styles.flowBackButton}
|
|
348
|
+
>
|
|
346
349
|
<Text style={styles.flowBackChevron}>‹</Text>
|
|
347
350
|
</TouchableOpacity>
|
|
348
351
|
</SafeAreaView>
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/** The GlomoPay Standard Checkout Component */
|
|
2
|
+
|
|
3
|
+
import React, { useImperativeHandle, useMemo, forwardRef } from "react";
|
|
4
|
+
import { StyleSheet, View, Modal, Platform, SafeAreaView, TouchableOpacity, Text } from "react-native";
|
|
5
|
+
import { WebView, type WebViewMessageEvent, type WebViewProps } from "react-native-webview";
|
|
6
|
+
|
|
7
|
+
import { useStandardCheckout } from "./use-standard-checkout";
|
|
8
|
+
import { type GlomoStandardCheckoutRef, type GlomoStandardCheckoutProps } from "./types/standard-checkout";
|
|
9
|
+
import { isValidUrl } from "./utils/validation";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The Main GlomoPay Standard Checkout Component
|
|
13
|
+
*
|
|
14
|
+
* @param server - Optional. The SDK server environment. For development builds ONLY.
|
|
15
|
+
* @param publicKey - The public key for the merchant. If it starts with "test_", mock mode will be enabled automatically. Otherwise, live mode is used.
|
|
16
|
+
* @param orderId - The order ID. Always starts with "order_"
|
|
17
|
+
*
|
|
18
|
+
* @param onPaymentSuccess - The success callback with payload, for a successful payment
|
|
19
|
+
* @param onPaymentFailure - The failure callback with payload, for a failed payment
|
|
20
|
+
* @param onPaymentTerminate - Optional callback called when the checkout is terminated either from the webpage (back button or close button) or mobile component (user dismissing the modal on iOS or user pressing the back button on Android)
|
|
21
|
+
*
|
|
22
|
+
* @param onConnectionError - Optional callback for connection/network errors
|
|
23
|
+
* @param onSdkError - Optional callback for handling SDK validation errors and configuration issues
|
|
24
|
+
*
|
|
25
|
+
* @param ref - The ref for the component
|
|
26
|
+
* @param devMode - Turn on to see all logs, warnings, and errors in the console. Off by default
|
|
27
|
+
*/
|
|
28
|
+
function GlomoStandardCheckoutComponent(
|
|
29
|
+
{
|
|
30
|
+
server,
|
|
31
|
+
publicKey,
|
|
32
|
+
orderId,
|
|
33
|
+
onPaymentSuccess,
|
|
34
|
+
onPaymentFailure,
|
|
35
|
+
onConnectionError,
|
|
36
|
+
onPaymentTerminate,
|
|
37
|
+
onSdkError,
|
|
38
|
+
onBankTransferSubmitted,
|
|
39
|
+
onPayViaBankCompleted,
|
|
40
|
+
onPayViaBankBankConnectionSuccessful,
|
|
41
|
+
onUserRefusedCameraPermissions,
|
|
42
|
+
devMode = false,
|
|
43
|
+
}: GlomoStandardCheckoutProps,
|
|
44
|
+
ref: React.ForwardedRef<GlomoStandardCheckoutRef>
|
|
45
|
+
) {
|
|
46
|
+
// Computing mockMode based on the publicKey prefix
|
|
47
|
+
const mockMode = useMemo(() => {
|
|
48
|
+
const resolvedMockMode = publicKey?.toLowerCase().startsWith("test_") ?? false;
|
|
49
|
+
if (devMode) {
|
|
50
|
+
console.log(
|
|
51
|
+
`[Glomo-RN-SDK Standard] ${resolvedMockMode ? "Using" : "Not using"} Mock mode for publicKey: ${publicKey}`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
return resolvedMockMode;
|
|
55
|
+
}, [publicKey, devMode]);
|
|
56
|
+
|
|
57
|
+
const {
|
|
58
|
+
start,
|
|
59
|
+
status,
|
|
60
|
+
showCheckout,
|
|
61
|
+
flowWebViewUrl,
|
|
62
|
+
showFlowWebView,
|
|
63
|
+
checkoutUrl,
|
|
64
|
+
mainWebViewRef,
|
|
65
|
+
flowWebViewRef,
|
|
66
|
+
handleMainWebViewMessage,
|
|
67
|
+
handleFlowWebViewMessage,
|
|
68
|
+
handleError,
|
|
69
|
+
handleHttpError,
|
|
70
|
+
handleNavigationStateChange,
|
|
71
|
+
handleModalBackButton,
|
|
72
|
+
handleFlowBack,
|
|
73
|
+
handlePermissionRequest,
|
|
74
|
+
injectedMain,
|
|
75
|
+
injectedFlow,
|
|
76
|
+
} = useStandardCheckout(
|
|
77
|
+
{
|
|
78
|
+
server,
|
|
79
|
+
publicKey,
|
|
80
|
+
orderId,
|
|
81
|
+
onPaymentSuccess,
|
|
82
|
+
onPaymentFailure,
|
|
83
|
+
onConnectionError,
|
|
84
|
+
onPaymentTerminate,
|
|
85
|
+
onSdkError,
|
|
86
|
+
onBankTransferSubmitted,
|
|
87
|
+
onPayViaBankCompleted,
|
|
88
|
+
onPayViaBankBankConnectionSuccessful,
|
|
89
|
+
onUserRefusedCameraPermissions,
|
|
90
|
+
devMode,
|
|
91
|
+
},
|
|
92
|
+
mockMode
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// Exposing the start() and getStatus() methods via the ref
|
|
96
|
+
useImperativeHandle(ref, () => ({
|
|
97
|
+
start,
|
|
98
|
+
getStatus: () => status,
|
|
99
|
+
}));
|
|
100
|
+
|
|
101
|
+
// Making the WebView component
|
|
102
|
+
const makeWebView = React.useCallback(
|
|
103
|
+
(
|
|
104
|
+
ref: React.RefObject<WebView>,
|
|
105
|
+
url: string,
|
|
106
|
+
messageHandler: (event: WebViewMessageEvent) => void,
|
|
107
|
+
identifier: "main" | "flow",
|
|
108
|
+
injectedJavaScript?: string,
|
|
109
|
+
injectedJavaScriptBeforeContentLoaded?: string,
|
|
110
|
+
additionalProps?: Partial<WebViewProps>
|
|
111
|
+
) => {
|
|
112
|
+
// Preventing a render if no injection script is provided
|
|
113
|
+
if (!injectedJavaScript) {
|
|
114
|
+
if (devMode) {
|
|
115
|
+
console.warn(
|
|
116
|
+
`[Glomo-RN-SDK Standard] JavaScript Injection missing for ${url}. Skipping ${identifier} Render.`
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Preventing a render if URL is empty or invalid
|
|
123
|
+
if (!url || url.trim() === "") {
|
|
124
|
+
// Redundantly checking for surprise/extreme edge cases
|
|
125
|
+
if (!isValidUrl(url)) {
|
|
126
|
+
if (devMode) {
|
|
127
|
+
console.error(
|
|
128
|
+
`[Glomo-RN-SDK Standard] Invalid non-empty URL ${url} provided. Skipping ${identifier} Render.`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (devMode) {
|
|
135
|
+
console.error(
|
|
136
|
+
`[Glomo-RN-SDK Standard] Empty or invalid URL provided. Skipping ${identifier} Render.`
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<WebView
|
|
144
|
+
ref={ref}
|
|
145
|
+
webviewDebuggingEnabled={__DEV__ && devMode}
|
|
146
|
+
javaScriptEnabled={true}
|
|
147
|
+
domStorageEnabled={true}
|
|
148
|
+
onMessage={messageHandler}
|
|
149
|
+
onError={handleError}
|
|
150
|
+
onHttpError={handleHttpError}
|
|
151
|
+
onNavigationStateChange={handleNavigationStateChange}
|
|
152
|
+
onLoadStart={() => {
|
|
153
|
+
if (devMode) {
|
|
154
|
+
console.log(`[Glomo-RN-SDK Standard] [${identifier}] WebView load started for ${url}`);
|
|
155
|
+
}
|
|
156
|
+
}}
|
|
157
|
+
onLoadEnd={() => {
|
|
158
|
+
if (devMode) {
|
|
159
|
+
console.log(`[Glomo-RN-SDK Standard] [${identifier}] WebView load ended for ${url}`);
|
|
160
|
+
}
|
|
161
|
+
}}
|
|
162
|
+
source={{ uri: url }}
|
|
163
|
+
javaScriptCanOpenWindowsAutomatically={true}
|
|
164
|
+
setSupportMultipleWindows={true}
|
|
165
|
+
incognito={true}
|
|
166
|
+
cacheEnabled={false}
|
|
167
|
+
cacheMode='LOAD_NO_CACHE'
|
|
168
|
+
pullToRefreshEnabled={false}
|
|
169
|
+
limitsNavigationsToAppBoundDomains={false}
|
|
170
|
+
menuItems={[]}
|
|
171
|
+
injectedJavaScript={injectedJavaScript}
|
|
172
|
+
injectedJavaScriptBeforeContentLoaded={injectedJavaScriptBeforeContentLoaded}
|
|
173
|
+
style={styles.webview}
|
|
174
|
+
showsHorizontalScrollIndicator={false}
|
|
175
|
+
showsVerticalScrollIndicator={false}
|
|
176
|
+
mixedContentMode='always'
|
|
177
|
+
thirdPartyCookiesEnabled={true}
|
|
178
|
+
sharedCookiesEnabled={true}
|
|
179
|
+
allowsInlineMediaPlayback={true}
|
|
180
|
+
mediaPlaybackRequiresUserAction={false}
|
|
181
|
+
mediaCapturePermissionGrantType='prompt'
|
|
182
|
+
allowFileAccess={true}
|
|
183
|
+
allowUniversalAccessFromFileURLs={true}
|
|
184
|
+
allowFileAccessFromFileURLs={true}
|
|
185
|
+
androidLayerType='hardware'
|
|
186
|
+
// @ts-expect-error onPermissionRequest is an Android-only WebView prop not yet in react-native-webview type definitions
|
|
187
|
+
onPermissionRequest={handlePermissionRequest}
|
|
188
|
+
{...additionalProps}
|
|
189
|
+
/>
|
|
190
|
+
);
|
|
191
|
+
},
|
|
192
|
+
[handleError, handleHttpError, handleNavigationStateChange, handlePermissionRequest, devMode]
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
const MainWebViewComponent = useMemo(
|
|
196
|
+
() => makeWebView(mainWebViewRef, checkoutUrl, handleMainWebViewMessage, "main", injectedMain),
|
|
197
|
+
[makeWebView, checkoutUrl, handleMainWebViewMessage, injectedMain, mainWebViewRef]
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
const FlowWebViewComponent = useMemo(
|
|
201
|
+
() =>
|
|
202
|
+
flowWebViewUrl
|
|
203
|
+
? makeWebView(flowWebViewRef, flowWebViewUrl, handleFlowWebViewMessage, "flow", injectedFlow)
|
|
204
|
+
: null,
|
|
205
|
+
[makeWebView, flowWebViewUrl, handleFlowWebViewMessage, injectedFlow, flowWebViewRef]
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
const isVisible = showCheckout;
|
|
209
|
+
|
|
210
|
+
// Prevent extreme edge cases where validations inside start() do not prevent the flow initialization
|
|
211
|
+
const shouldShowModal = useMemo(() => {
|
|
212
|
+
const value = isVisible && (checkoutUrl ?? "").trim().length > 0;
|
|
213
|
+
|
|
214
|
+
if (devMode) {
|
|
215
|
+
console.log(
|
|
216
|
+
`[Glomo-RN-SDK Standard] computed visibilityHook: ${value} for internal switch ${isVisible}, and checkout=${checkoutUrl};`
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
return value;
|
|
220
|
+
}, [isVisible, checkoutUrl, devMode]);
|
|
221
|
+
|
|
222
|
+
// Alias to ensure explicit component reference for React Native
|
|
223
|
+
const ModalComponent = Modal;
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Deriving render gates from state:
|
|
227
|
+
* shouldRenderFlowOverlay: flow overlay is mounted only when there is an active flow URL
|
|
228
|
+
*/
|
|
229
|
+
const shouldRenderFlowOverlay = Boolean(showFlowWebView && flowWebViewUrl && FlowWebViewComponent);
|
|
230
|
+
|
|
231
|
+
if (devMode) {
|
|
232
|
+
console.log(
|
|
233
|
+
`[Glomo-RN-SDK Standard] Render gates: modal=${shouldShowModal}, flowOverlay=${shouldRenderFlowOverlay}, flowWebViewUrl=${flowWebViewUrl || "<empty>"}`
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return (
|
|
238
|
+
<ModalComponent
|
|
239
|
+
visible={shouldShowModal}
|
|
240
|
+
animationType='slide'
|
|
241
|
+
presentationStyle={Platform.OS === "ios" ? "pageSheet" : "fullScreen"}
|
|
242
|
+
onRequestClose={handleModalBackButton}
|
|
243
|
+
>
|
|
244
|
+
<View style={styles.modalContainer}>
|
|
245
|
+
<View style={styles.mainWebViewContainer}>{MainWebViewComponent}</View>
|
|
246
|
+
|
|
247
|
+
{shouldRenderFlowOverlay && (
|
|
248
|
+
<View style={styles.flowWebViewContainer}>
|
|
249
|
+
<SafeAreaView style={styles.flowHeader}>
|
|
250
|
+
<TouchableOpacity
|
|
251
|
+
onPress={handleFlowBack}
|
|
252
|
+
style={styles.flowBackButton}
|
|
253
|
+
>
|
|
254
|
+
<Text style={styles.flowBackChevron}>{"\u2039"}</Text>
|
|
255
|
+
</TouchableOpacity>
|
|
256
|
+
</SafeAreaView>
|
|
257
|
+
<View style={styles.flowWebViewContent}>{FlowWebViewComponent}</View>
|
|
258
|
+
</View>
|
|
259
|
+
)}
|
|
260
|
+
</View>
|
|
261
|
+
</ModalComponent>
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export const GlomoStandardCheckout = forwardRef<GlomoStandardCheckoutRef, GlomoStandardCheckoutProps>(
|
|
266
|
+
GlomoStandardCheckoutComponent
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
GlomoStandardCheckout.displayName = "GlomoStandardCheckout";
|
|
270
|
+
|
|
271
|
+
const styles = StyleSheet.create({
|
|
272
|
+
modalContainer: {
|
|
273
|
+
flex: 1,
|
|
274
|
+
backgroundColor: "#fff",
|
|
275
|
+
},
|
|
276
|
+
mainWebViewContainer: {
|
|
277
|
+
flex: 1,
|
|
278
|
+
position: "relative",
|
|
279
|
+
},
|
|
280
|
+
webview: {
|
|
281
|
+
flex: 1,
|
|
282
|
+
},
|
|
283
|
+
flowWebViewContainer: {
|
|
284
|
+
position: "absolute",
|
|
285
|
+
top: 0,
|
|
286
|
+
left: 0,
|
|
287
|
+
right: 0,
|
|
288
|
+
bottom: 0,
|
|
289
|
+
flexDirection: "column",
|
|
290
|
+
backgroundColor: "#fff",
|
|
291
|
+
zIndex: 99999,
|
|
292
|
+
elevation: 99999,
|
|
293
|
+
},
|
|
294
|
+
flowHeader: {
|
|
295
|
+
backgroundColor: "#fff",
|
|
296
|
+
borderBottomWidth: 1,
|
|
297
|
+
borderBottomColor: "#e0e0e0",
|
|
298
|
+
},
|
|
299
|
+
flowBackButton: {
|
|
300
|
+
paddingVertical: 0,
|
|
301
|
+
paddingLeft: 20,
|
|
302
|
+
},
|
|
303
|
+
flowBackChevron: {
|
|
304
|
+
fontSize: 42,
|
|
305
|
+
color: "#333",
|
|
306
|
+
lineHeight: 42,
|
|
307
|
+
},
|
|
308
|
+
flowWebViewContent: {
|
|
309
|
+
flex: 1,
|
|
310
|
+
},
|
|
311
|
+
errorContainer: {
|
|
312
|
+
flex: 1,
|
|
313
|
+
justifyContent: "center",
|
|
314
|
+
alignItems: "center",
|
|
315
|
+
padding: 20,
|
|
316
|
+
backgroundColor: "#fff",
|
|
317
|
+
},
|
|
318
|
+
errorText: {
|
|
319
|
+
color: "#d32f2f",
|
|
320
|
+
fontSize: 14,
|
|
321
|
+
textAlign: "center",
|
|
322
|
+
lineHeight: 20,
|
|
323
|
+
},
|
|
324
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
/** The GlomoPay RN SDK exports */
|
|
1
|
+
/** The GlomoPay RN SDK v3 exports */
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
export {
|
|
3
|
+
// v3 public API - unified checkout
|
|
4
|
+
export { GlomoCheckout } from "./glomo-checkout";
|
|
5
|
+
export {
|
|
6
|
+
type GlomoCheckoutRef,
|
|
7
|
+
type GlomoCheckoutProps,
|
|
8
|
+
type GlomoCheckoutPayload,
|
|
9
|
+
type CheckoutStatus,
|
|
10
|
+
type GlomoBankTransferPayload,
|
|
11
|
+
type GlomoPayViaBankConnectionPayload,
|
|
12
|
+
} from "./types/checkout";
|
|
13
|
+
export { type GlomoServer } from "./config/base";
|
|
5
14
|
export { type SdkError } from "./utils/analytics";
|
|
6
|
-
export {
|
|
7
|
-
|
|
8
|
-
// Main UI Component for the LRS Checkout flow
|
|
9
|
-
export { GlomoLrsCheckout, type GlomoLrsCheckoutProps, type GlomoLrsCheckoutRef } from "./glomo-lrs-checkout";
|
|
15
|
+
export { useGlomoCheckout } from "./use-glomo-checkout";
|
package/src/injections/index.ts
CHANGED
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
import { injectedScript as mainScript } from "./webview-main.injection";
|
|
5
5
|
import { injectedScript as flowScript } from "./webview-flow.injection";
|
|
6
6
|
import { injectedScript as educationCarouselScript } from "./webview-education-carousel.injection";
|
|
7
|
+
import { injectedScript as standardScript } from "./webview-standard.injection";
|
|
7
8
|
|
|
8
9
|
export const InjectionScripts = {
|
|
9
10
|
main: mainScript,
|
|
10
11
|
flow: flowScript,
|
|
11
12
|
educationCarousel: educationCarouselScript,
|
|
13
|
+
standard: standardScript,
|
|
12
14
|
};
|