@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
|
@@ -0,0 +1,832 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** Main SDK hook for the GlomoPay Standard Checkout flow */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.useStandardCheckout = useStandardCheckout;
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const react_native_1 = require("react-native");
|
|
7
|
+
const index_1 = require("./injections/index");
|
|
8
|
+
const segment_1 = require("./config/segment");
|
|
9
|
+
const base_1 = require("./config/base");
|
|
10
|
+
const validation_1 = require("./utils/validation");
|
|
11
|
+
const device_compliance_1 = require("./utils/device-compliance");
|
|
12
|
+
const analytics_1 = require("./utils/analytics");
|
|
13
|
+
/** The main SDK hook for the GlomoPay Standard Checkout flow */
|
|
14
|
+
function useStandardCheckout({ server, publicKey, orderId, onPaymentSuccess, onPaymentFailure, onConnectionError, onPaymentTerminate, onSdkError, onBankTransferSubmitted, onPayViaBankCompleted, onPayViaBankBankConnectionSuccessful, onUserRefusedCameraPermissions, devMode = false, }, mockMode) {
|
|
15
|
+
// Refs for the WebViews
|
|
16
|
+
const mainWebViewRef = (0, react_1.useRef)(null);
|
|
17
|
+
const flowWebViewRef = (0, react_1.useRef)(null);
|
|
18
|
+
// Deduplication guard - prevents firing onPayViaBankCompleted twice when both main and flow WebViews emit the event
|
|
19
|
+
const payViaBankCompletedHandledRef = (0, react_1.useRef)(false);
|
|
20
|
+
// Resolving checkout URL from the selected SDK server
|
|
21
|
+
const serverConfig = (0, react_1.useMemo)(() => (0, base_1.resolveServerConfig)(server), [server]);
|
|
22
|
+
const baseCheckoutUrl = serverConfig.baseUrl.standardCheckout;
|
|
23
|
+
/**
|
|
24
|
+
* The main checkout URL for the standard flow
|
|
25
|
+
*/
|
|
26
|
+
const checkoutUrl = (0, react_1.useMemo)(() => {
|
|
27
|
+
try {
|
|
28
|
+
// Building the query string manually since URLSearchParams is not fully supported in React Native
|
|
29
|
+
const baseParams = [`orderId=${encodeURIComponent(orderId)}`];
|
|
30
|
+
const mode = mockMode ? "mock" : "live";
|
|
31
|
+
const params = baseParams.concat(`mode=${encodeURIComponent(mode)}`, `publicKey=${encodeURIComponent(publicKey)}`);
|
|
32
|
+
const queryString = params.join("&");
|
|
33
|
+
// Handling base URL with or without existing query parameters
|
|
34
|
+
const separator = baseCheckoutUrl.includes("?") ? "&" : "?";
|
|
35
|
+
const finalUrl = `${baseCheckoutUrl}${separator}${queryString}`;
|
|
36
|
+
// Validating the final URL
|
|
37
|
+
if (!(0, validation_1.isValidUrl)(finalUrl)) {
|
|
38
|
+
if (devMode) {
|
|
39
|
+
console.error("[Glomo-RN-SDK Standard] Generated invalid checkout URL:", finalUrl);
|
|
40
|
+
}
|
|
41
|
+
return "";
|
|
42
|
+
}
|
|
43
|
+
if (devMode) {
|
|
44
|
+
console.log("[Glomo-RN-SDK Standard] Checkout URL:", finalUrl);
|
|
45
|
+
}
|
|
46
|
+
return finalUrl;
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
if (devMode) {
|
|
50
|
+
console.error("[Glomo-RN-SDK Standard] Error building checkout URL:", error);
|
|
51
|
+
}
|
|
52
|
+
return "";
|
|
53
|
+
}
|
|
54
|
+
}, [baseCheckoutUrl, orderId, publicKey, mockMode, devMode]);
|
|
55
|
+
// Checkout status state
|
|
56
|
+
const [status, setStatus] = (0, react_1.useState)("ready");
|
|
57
|
+
// Visibility state for the main checkout modal
|
|
58
|
+
const [showCheckout, setShowCheckout] = (0, react_1.useState)(false);
|
|
59
|
+
const [showFlowWebView, setShowFlowWebView] = (0, react_1.useState)(false);
|
|
60
|
+
const [flowWebViewUrl, setFlowWebViewUrl] = (0, react_1.useState)("");
|
|
61
|
+
(0, react_1.useEffect)(() => {
|
|
62
|
+
if (devMode) {
|
|
63
|
+
console.log(`[Glomo-RN-SDK Standard] State snapshot: status=${status}, showCheckout=${showCheckout}, showFlowWebView=${showFlowWebView}, flowWebViewUrl=${flowWebViewUrl || "<empty>"}`);
|
|
64
|
+
}
|
|
65
|
+
}, [devMode, status, showCheckout, showFlowWebView, flowWebViewUrl]);
|
|
66
|
+
// Handler for the WebView errors
|
|
67
|
+
const handleError = (0, react_1.useCallback)((syntheticEvent) => {
|
|
68
|
+
try {
|
|
69
|
+
const { nativeEvent } = syntheticEvent;
|
|
70
|
+
// Now checking for connection errors
|
|
71
|
+
// iOS: NSURLErrorDomain errors
|
|
72
|
+
const isIOSConnectionError = (nativeEvent === null || nativeEvent === void 0 ? void 0 : nativeEvent.domain) === "NSURLErrorDomain" &&
|
|
73
|
+
((nativeEvent === null || nativeEvent === void 0 ? void 0 : nativeEvent.code) === -1004 || // Could not connect to the server
|
|
74
|
+
(nativeEvent === null || nativeEvent === void 0 ? void 0 : nativeEvent.code) === -1009 || // The Internet connection appears to be offline
|
|
75
|
+
(nativeEvent === null || nativeEvent === void 0 ? void 0 : nativeEvent.code) === -1001 || // The request timed out
|
|
76
|
+
(nativeEvent === null || nativeEvent === void 0 ? void 0 : nativeEvent.code) === -1003); // Cannot find host
|
|
77
|
+
// Android: Network errors
|
|
78
|
+
const description = (nativeEvent === null || nativeEvent === void 0 ? void 0 : nativeEvent.description) || "";
|
|
79
|
+
const isAndroidConnectionError = typeof description === "string" &&
|
|
80
|
+
(description.includes("ERR_EMPTY_RESPONSE") || // Server unreachable
|
|
81
|
+
description.includes("ERR_CONNECTION_REFUSED") || // Connection refused
|
|
82
|
+
description.includes("ERR_NAME_NOT_RESOLVED") || // DNS resolution failed
|
|
83
|
+
description.includes("ERR_INTERNET_DISCONNECTED") || // No internet
|
|
84
|
+
description.includes("ERR_CONNECTION_TIMED_OUT") || // Connection timeout
|
|
85
|
+
description.includes("ERR_NETWORK_CHANGED")); // Network changed
|
|
86
|
+
if (isIOSConnectionError || isAndroidConnectionError) {
|
|
87
|
+
if (devMode) {
|
|
88
|
+
console.error("[Glomo-RN-SDK Standard] Connection error:", nativeEvent);
|
|
89
|
+
}
|
|
90
|
+
// Closing the checkout modal
|
|
91
|
+
setShowCheckout(false);
|
|
92
|
+
setShowFlowWebView(false);
|
|
93
|
+
setFlowWebViewUrl("");
|
|
94
|
+
// Calling onConnectionError callback if provided
|
|
95
|
+
(0, validation_1.safeCallback)(onConnectionError, [nativeEvent], "onConnectionError", devMode);
|
|
96
|
+
// Tracking connection error
|
|
97
|
+
(0, analytics_1.trackStandardConnectionError)(orderId, nativeEvent === null || nativeEvent === void 0 ? void 0 : nativeEvent.code, publicKey, devMode, mockMode, checkoutUrl);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
if (devMode) {
|
|
101
|
+
console.error("[Glomo-RN-SDK Standard] WebView error:", nativeEvent);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
if (devMode) {
|
|
107
|
+
console.error("[Glomo-RN-SDK Standard] Error in handleError:", error);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}, [devMode, onConnectionError, checkoutUrl, orderId, publicKey, mockMode]);
|
|
111
|
+
// Handler for the WebView HTTP errors
|
|
112
|
+
const handleHttpError = (0, react_1.useCallback)((syntheticEvent) => {
|
|
113
|
+
try {
|
|
114
|
+
const { nativeEvent } = syntheticEvent;
|
|
115
|
+
if (devMode) {
|
|
116
|
+
console.error("[Glomo-RN-SDK Standard] WebView HTTP error:", nativeEvent);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
if (devMode) {
|
|
121
|
+
console.error("[Glomo-RN-SDK Standard] Error in handleHttpError:", error);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}, [devMode]);
|
|
125
|
+
/**
|
|
126
|
+
* Handler for the main WebView messages.
|
|
127
|
+
* The main WebView hosts the checkout page. Messages arrive as JSON strings from the injected
|
|
128
|
+
* JavaScript bridge and include console logs, window.open/close interceptions, and payment
|
|
129
|
+
* lifecycle events (success, failure, terminate, bank transfer, pay via bank).
|
|
130
|
+
*/
|
|
131
|
+
const handleMainWebViewMessage = (0, react_1.useCallback)((event) => {
|
|
132
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
133
|
+
try {
|
|
134
|
+
// Extracting and validating the raw message data from the WebView event
|
|
135
|
+
const data = (_a = event.nativeEvent) === null || _a === void 0 ? void 0 : _a.data;
|
|
136
|
+
if (!data || typeof data !== "string") {
|
|
137
|
+
if (devMode) {
|
|
138
|
+
console.warn("[Glomo-RN-SDK Standard] Invalid message data from MainWebView");
|
|
139
|
+
}
|
|
140
|
+
// Tracking invalid message received
|
|
141
|
+
(0, analytics_1.trackStandardInvalidMessageReceived)("main", data, checkoutUrl, orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const message = JSON.parse(data);
|
|
145
|
+
if (devMode) {
|
|
146
|
+
console.log("[Glomo-RN-SDK Standard] MainWebView Message received:", message.type, message);
|
|
147
|
+
}
|
|
148
|
+
// Forwarding console messages from the injected script to the React Native console
|
|
149
|
+
if (message.type === "console") {
|
|
150
|
+
if (devMode) {
|
|
151
|
+
const level = message.level || "log";
|
|
152
|
+
console.log(`[Glomo-RN-SDK Standard] [WebView ${level.toUpperCase()}]`, message.message);
|
|
153
|
+
}
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
// Intercepting window.open calls - opening the target URL in the flow WebView overlay
|
|
157
|
+
if (message.type === "window.open") {
|
|
158
|
+
const url = message.url;
|
|
159
|
+
if (url && typeof url === "string" && (0, validation_1.isValidUrl)(url)) {
|
|
160
|
+
if (devMode) {
|
|
161
|
+
console.log(`[Glomo-RN-SDK Standard] window.open called from MainWebView: ${url}`);
|
|
162
|
+
}
|
|
163
|
+
setFlowWebViewUrl(url);
|
|
164
|
+
setShowFlowWebView(true);
|
|
165
|
+
// Tracking window.open interception
|
|
166
|
+
(0, analytics_1.trackStandardWindowOpen)("main", url, orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
if (devMode) {
|
|
170
|
+
console.log("[Glomo-RN-SDK Standard] Invalid URL in window.open from MainWebView:", url, typeof url === "undefined" ? "undefined" : "");
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
// Intercepting window.close calls - closing the flow WebView overlay
|
|
176
|
+
if (message.type === "window.close") {
|
|
177
|
+
if (devMode) {
|
|
178
|
+
console.log("[Glomo-RN-SDK Standard] Child window close requested from MainWebView");
|
|
179
|
+
}
|
|
180
|
+
setShowFlowWebView(false);
|
|
181
|
+
setFlowWebViewUrl("");
|
|
182
|
+
// Tracking window.close interception
|
|
183
|
+
(0, analytics_1.trackStandardWindowClose)("main", orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
// Handling merchant JS callbacks on flow completion (payment events, lifecycle events)
|
|
187
|
+
if (message.type === "message" && message.message) {
|
|
188
|
+
const messageData = message.message;
|
|
189
|
+
const messageType = messageData === null || messageData === void 0 ? void 0 : messageData.type;
|
|
190
|
+
// Handling payment success - closing checkout and notifying the merchant
|
|
191
|
+
if (messageType === "payment.success" || messageType === "payment.complete") {
|
|
192
|
+
const paymentMessage = messageData;
|
|
193
|
+
const payload = paymentMessage === null || paymentMessage === void 0 ? void 0 : paymentMessage.payload;
|
|
194
|
+
if ((0, validation_1.isValidPaymentPayload)(payload)) {
|
|
195
|
+
if (devMode) {
|
|
196
|
+
console.log("[Glomo-RN-SDK Standard] Payment successful via merchant callback!");
|
|
197
|
+
}
|
|
198
|
+
setShowCheckout(false);
|
|
199
|
+
setShowFlowWebView(false);
|
|
200
|
+
setFlowWebViewUrl("");
|
|
201
|
+
setStatus("payment_successful");
|
|
202
|
+
(0, validation_1.safeCallback)(onPaymentSuccess, [payload], "onPaymentSuccess", devMode);
|
|
203
|
+
// Tracking payment success callback
|
|
204
|
+
(0, analytics_1.trackStandardPaymentSuccess)(payload.orderId, payload.paymentId, publicKey, devMode, mockMode, checkoutUrl);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
if (devMode) {
|
|
208
|
+
console.error("[Glomo-RN-SDK Standard] Invalid payment success payload:", payload);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
// Handling payment failure - closing checkout and notifying the merchant
|
|
214
|
+
if (messageType === "payment.failure" || messageType === "payment.error") {
|
|
215
|
+
const paymentMessage = messageData;
|
|
216
|
+
const payload = paymentMessage === null || paymentMessage === void 0 ? void 0 : paymentMessage.payload;
|
|
217
|
+
if ((0, validation_1.isValidPaymentPayload)(payload)) {
|
|
218
|
+
if (devMode) {
|
|
219
|
+
console.error("[Glomo-RN-SDK Standard] Payment failed via merchant callback");
|
|
220
|
+
}
|
|
221
|
+
setShowCheckout(false);
|
|
222
|
+
setShowFlowWebView(false);
|
|
223
|
+
setFlowWebViewUrl("");
|
|
224
|
+
setStatus("payment_failed");
|
|
225
|
+
(0, validation_1.safeCallback)(onPaymentFailure, [payload], "onPaymentFailure", devMode);
|
|
226
|
+
// Tracking payment failure callback
|
|
227
|
+
(0, analytics_1.trackStandardPaymentFailure)(payload.orderId, payload.paymentId, publicKey, devMode, mockMode, checkoutUrl);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
if (devMode) {
|
|
231
|
+
console.error("[Glomo-RN-SDK Standard] Invalid payment failure payload:", payload);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
// Handling bank transfer submission - user has submitted transfer details
|
|
237
|
+
if (messageType === "payment.bank_transfer_submitted") {
|
|
238
|
+
const payload = messageData === null || messageData === void 0 ? void 0 : messageData.payload;
|
|
239
|
+
if (devMode) {
|
|
240
|
+
console.log("[Glomo-RN-SDK Standard] Bank transfer submitted:", payload);
|
|
241
|
+
}
|
|
242
|
+
setShowCheckout(false);
|
|
243
|
+
setShowFlowWebView(false);
|
|
244
|
+
setFlowWebViewUrl("");
|
|
245
|
+
setStatus("bank_transfer_submitted");
|
|
246
|
+
(0, validation_1.safeCallback)(onBankTransferSubmitted, [
|
|
247
|
+
{
|
|
248
|
+
orderId: (_b = payload === null || payload === void 0 ? void 0 : payload.orderId) !== null && _b !== void 0 ? _b : "",
|
|
249
|
+
senderAccountNumber: (_c = payload === null || payload === void 0 ? void 0 : payload.senderAccountNumber) !== null && _c !== void 0 ? _c : "",
|
|
250
|
+
transactionReference: (_d = payload === null || payload === void 0 ? void 0 : payload.transactionReference) !== null && _d !== void 0 ? _d : "",
|
|
251
|
+
},
|
|
252
|
+
], "onBankTransferSubmitted", devMode);
|
|
253
|
+
(0, analytics_1.trackStandardBankTransferSubmitted)(orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
// Handling pay via bank - bank connection successful event (informational, no status change)
|
|
257
|
+
if (messageType === "pay_via_bank.bank.connection_successful") {
|
|
258
|
+
const payload = messageData === null || messageData === void 0 ? void 0 : messageData.payload;
|
|
259
|
+
if (devMode) {
|
|
260
|
+
console.log("[Glomo-RN-SDK Standard] Pay via bank - bank connection successful:", payload);
|
|
261
|
+
}
|
|
262
|
+
(0, validation_1.safeCallback)(onPayViaBankBankConnectionSuccessful, [
|
|
263
|
+
{
|
|
264
|
+
bankIdentifier: (_e = payload === null || payload === void 0 ? void 0 : payload.bankIdentifier) !== null && _e !== void 0 ? _e : "",
|
|
265
|
+
cooldownPeriodInMinutes: (_f = payload === null || payload === void 0 ? void 0 : payload.cooldownPeriodInMinutes) !== null && _f !== void 0 ? _f : 0,
|
|
266
|
+
bankName: (_g = payload === null || payload === void 0 ? void 0 : payload.bankName) !== null && _g !== void 0 ? _g : "",
|
|
267
|
+
bankImageSrc: (_h = payload === null || payload === void 0 ? void 0 : payload.bankImageSrc) !== null && _h !== void 0 ? _h : "",
|
|
268
|
+
bankImageAlt: (_j = payload === null || payload === void 0 ? void 0 : payload.bankImageAlt) !== null && _j !== void 0 ? _j : "",
|
|
269
|
+
},
|
|
270
|
+
], "onPayViaBankBankConnectionSuccessful", devMode);
|
|
271
|
+
(0, analytics_1.trackStandardPayViaBankBankConnectionSuccessful)(orderId, publicKey, (_k = payload === null || payload === void 0 ? void 0 : payload.bankIdentifier) !== null && _k !== void 0 ? _k : "", devMode, mockMode, checkoutUrl);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Handling the generic glomoCheckoutJourneyTerminate event.
|
|
276
|
+
* This event is fired by the checkout page when the pay via bank (lean/open finance)
|
|
277
|
+
* flow completes. The deduplication ref prevents firing the callback twice when both
|
|
278
|
+
* main and flow WebViews emit this event.
|
|
279
|
+
*/
|
|
280
|
+
if (messageType === "glomoCheckoutJourneyTerminate") {
|
|
281
|
+
// Deduplication - both main and flow WebViews can emit this event
|
|
282
|
+
if (payViaBankCompletedHandledRef.current) {
|
|
283
|
+
if (devMode) {
|
|
284
|
+
console.log("[Glomo-RN-SDK Standard] Pay via bank completed already handled, ignoring duplicate");
|
|
285
|
+
}
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
payViaBankCompletedHandledRef.current = true;
|
|
289
|
+
const payload = messageData === null || messageData === void 0 ? void 0 : messageData.payload;
|
|
290
|
+
if (devMode) {
|
|
291
|
+
console.log("[Glomo-RN-SDK Standard] Pay via bank completed via MainWebView:", payload);
|
|
292
|
+
}
|
|
293
|
+
setShowFlowWebView(false);
|
|
294
|
+
setShowCheckout(false);
|
|
295
|
+
setFlowWebViewUrl("");
|
|
296
|
+
setStatus("pay_via_bank_completed");
|
|
297
|
+
(0, validation_1.safeCallback)(onPayViaBankCompleted, [{ status: (_l = payload === null || payload === void 0 ? void 0 : payload.status) !== null && _l !== void 0 ? _l : "unknown" }], "onPayViaBankCompleted", devMode);
|
|
298
|
+
(0, analytics_1.trackStandardPayViaBankCompleted)(orderId, publicKey, (_m = payload === null || payload === void 0 ? void 0 : payload.status) !== null && _m !== void 0 ? _m : "unknown", devMode, mockMode, checkoutUrl);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
// Handling checkout.closed events
|
|
302
|
+
if (messageType === "checkout.closed") {
|
|
303
|
+
if (devMode) {
|
|
304
|
+
console.log("[Glomo-RN-SDK Standard] Checkout closed event received");
|
|
305
|
+
}
|
|
306
|
+
setShowCheckout(false);
|
|
307
|
+
setShowFlowWebView(false);
|
|
308
|
+
setFlowWebViewUrl("");
|
|
309
|
+
(0, validation_1.safeCallback)(onPaymentTerminate, [], "onPaymentTerminate", devMode);
|
|
310
|
+
// Tracking payment terminate callback
|
|
311
|
+
(0, analytics_1.trackStandardPaymentTerminate)(orderId, "checkout_closed", publicKey, devMode, mockMode, checkoutUrl);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
if (devMode) {
|
|
318
|
+
console.error("[Glomo-RN-SDK Standard] Error parsing MainWebView message:", error);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}, [
|
|
322
|
+
onPaymentSuccess,
|
|
323
|
+
onPaymentFailure,
|
|
324
|
+
onPaymentTerminate,
|
|
325
|
+
onBankTransferSubmitted,
|
|
326
|
+
onPayViaBankCompleted,
|
|
327
|
+
onPayViaBankBankConnectionSuccessful,
|
|
328
|
+
devMode,
|
|
329
|
+
mockMode,
|
|
330
|
+
orderId,
|
|
331
|
+
publicKey,
|
|
332
|
+
checkoutUrl,
|
|
333
|
+
]);
|
|
334
|
+
/**
|
|
335
|
+
* Handler for the flow WebView messages.
|
|
336
|
+
* The flow WebView hosts child pages opened via window.open (e.g. 3DS, bank redirects).
|
|
337
|
+
* Message structure mirrors the main WebView handler but operates on the overlay WebView.
|
|
338
|
+
*/
|
|
339
|
+
const handleFlowWebViewMessage = (0, react_1.useCallback)((event) => {
|
|
340
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
341
|
+
try {
|
|
342
|
+
// Extracting and validating the raw message data from the flow WebView event
|
|
343
|
+
const data = (_a = event.nativeEvent) === null || _a === void 0 ? void 0 : _a.data;
|
|
344
|
+
if (!data || typeof data !== "string") {
|
|
345
|
+
if (devMode) {
|
|
346
|
+
console.warn("[Glomo-RN-SDK Standard] Invalid message data from FlowWebView");
|
|
347
|
+
}
|
|
348
|
+
// Tracking invalid message received
|
|
349
|
+
(0, analytics_1.trackStandardInvalidMessageReceived)("flow", data, flowWebViewUrl, orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const message = JSON.parse(data);
|
|
353
|
+
if (devMode) {
|
|
354
|
+
console.log("[Glomo-RN-SDK Standard] FlowWebView Message received:", message.type, message);
|
|
355
|
+
}
|
|
356
|
+
// Forwarding console messages from the flow WebView's injected script
|
|
357
|
+
if (message.type === "console") {
|
|
358
|
+
if (devMode) {
|
|
359
|
+
console.log(`[Glomo-RN-SDK Standard] [Flow] ${message.message}`);
|
|
360
|
+
}
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
// Intercepting window.open calls from the flow WebView - navigating within the same overlay
|
|
364
|
+
if (message.type === "window.open") {
|
|
365
|
+
const url = message.url;
|
|
366
|
+
if (url && typeof url === "string" && (0, validation_1.isValidUrl)(url)) {
|
|
367
|
+
if (devMode) {
|
|
368
|
+
console.log(`[Glomo-RN-SDK Standard] window.open called from FlowWebView: ${url}`);
|
|
369
|
+
}
|
|
370
|
+
setFlowWebViewUrl(url);
|
|
371
|
+
// Tracking window.open interception
|
|
372
|
+
(0, analytics_1.trackStandardWindowOpen)("flow", url, orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
if (devMode) {
|
|
376
|
+
console.log("[Glomo-RN-SDK Standard] Invalid URL in window.open from FlowWebView:", url, typeof url === "undefined" ? "undefined" : "");
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
// Intercepting window.close calls from the flow WebView - closing the overlay
|
|
382
|
+
if (message.type === "window.close") {
|
|
383
|
+
if (devMode) {
|
|
384
|
+
console.log("[Glomo-RN-SDK Standard] FlowWebView close requested");
|
|
385
|
+
}
|
|
386
|
+
setShowFlowWebView(false);
|
|
387
|
+
setFlowWebViewUrl("");
|
|
388
|
+
// Tracking window.close interception
|
|
389
|
+
(0, analytics_1.trackStandardWindowClose)("flow", orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
// Handling merchant JS callbacks from the flow WebView (payment events, lifecycle events)
|
|
393
|
+
if (message.type === "message" && message.message) {
|
|
394
|
+
const messageData = message.message;
|
|
395
|
+
const messageType = messageData === null || messageData === void 0 ? void 0 : messageData.type;
|
|
396
|
+
// Handling payment success from the flow WebView
|
|
397
|
+
if (messageType === "payment.success" || messageType === "payment.complete") {
|
|
398
|
+
const paymentMessage = messageData;
|
|
399
|
+
const payload = paymentMessage === null || paymentMessage === void 0 ? void 0 : paymentMessage.payload;
|
|
400
|
+
if ((0, validation_1.isValidPaymentPayload)(payload)) {
|
|
401
|
+
if (devMode) {
|
|
402
|
+
console.log("[Glomo-RN-SDK Standard] Payment successful via FlowWebView callback!");
|
|
403
|
+
}
|
|
404
|
+
setShowFlowWebView(false);
|
|
405
|
+
setShowCheckout(false);
|
|
406
|
+
setFlowWebViewUrl("");
|
|
407
|
+
setStatus("payment_successful");
|
|
408
|
+
(0, validation_1.safeCallback)(onPaymentSuccess, [payload], "onPaymentSuccess", devMode);
|
|
409
|
+
// Tracking payment success callback
|
|
410
|
+
(0, analytics_1.trackStandardPaymentSuccess)(payload.orderId, payload.paymentId, publicKey, devMode, mockMode, checkoutUrl);
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
if (devMode) {
|
|
414
|
+
console.error("[Glomo-RN-SDK Standard] Invalid payment success payload from FlowWebView:", payload);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
// Handling payment failure from the flow WebView
|
|
420
|
+
if (messageType === "payment.failure" || messageType === "payment.error") {
|
|
421
|
+
const paymentMessage = messageData;
|
|
422
|
+
const payload = paymentMessage === null || paymentMessage === void 0 ? void 0 : paymentMessage.payload;
|
|
423
|
+
if ((0, validation_1.isValidPaymentPayload)(payload)) {
|
|
424
|
+
if (devMode) {
|
|
425
|
+
console.error("[Glomo-RN-SDK Standard] Payment failed via FlowWebView callback");
|
|
426
|
+
}
|
|
427
|
+
setShowFlowWebView(false);
|
|
428
|
+
setShowCheckout(false);
|
|
429
|
+
setFlowWebViewUrl("");
|
|
430
|
+
setStatus("payment_failed");
|
|
431
|
+
(0, validation_1.safeCallback)(onPaymentFailure, [payload], "onPaymentFailure", devMode);
|
|
432
|
+
// Tracking payment failure callback
|
|
433
|
+
(0, analytics_1.trackStandardPaymentFailure)(payload.orderId, payload.paymentId, publicKey, devMode, mockMode, checkoutUrl);
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
if (devMode) {
|
|
437
|
+
console.error("[Glomo-RN-SDK Standard] Invalid payment failure payload from FlowWebView:", payload);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
// Handling pay via bank - bank connection successful event from the flow WebView
|
|
443
|
+
if (messageType === "pay_via_bank.bank.connection_successful") {
|
|
444
|
+
const payload = messageData === null || messageData === void 0 ? void 0 : messageData.payload;
|
|
445
|
+
if (devMode) {
|
|
446
|
+
console.log("[Glomo-RN-SDK Standard] Pay via bank - bank connection successful via FlowWebView:", payload);
|
|
447
|
+
}
|
|
448
|
+
(0, validation_1.safeCallback)(onPayViaBankBankConnectionSuccessful, [
|
|
449
|
+
{
|
|
450
|
+
bankIdentifier: (_b = payload === null || payload === void 0 ? void 0 : payload.bankIdentifier) !== null && _b !== void 0 ? _b : "",
|
|
451
|
+
cooldownPeriodInMinutes: (_c = payload === null || payload === void 0 ? void 0 : payload.cooldownPeriodInMinutes) !== null && _c !== void 0 ? _c : 0,
|
|
452
|
+
bankName: (_d = payload === null || payload === void 0 ? void 0 : payload.bankName) !== null && _d !== void 0 ? _d : "",
|
|
453
|
+
bankImageSrc: (_e = payload === null || payload === void 0 ? void 0 : payload.bankImageSrc) !== null && _e !== void 0 ? _e : "",
|
|
454
|
+
bankImageAlt: (_f = payload === null || payload === void 0 ? void 0 : payload.bankImageAlt) !== null && _f !== void 0 ? _f : "",
|
|
455
|
+
},
|
|
456
|
+
], "onPayViaBankBankConnectionSuccessful", devMode);
|
|
457
|
+
(0, analytics_1.trackStandardPayViaBankBankConnectionSuccessful)(orderId, publicKey, (_g = payload === null || payload === void 0 ? void 0 : payload.bankIdentifier) !== null && _g !== void 0 ? _g : "", devMode, mockMode, checkoutUrl);
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
// Handling glomoCheckoutJourneyTerminate from the flow WebView (pay via bank completion)
|
|
461
|
+
if (messageType === "glomoCheckoutJourneyTerminate") {
|
|
462
|
+
// Deduplication - both main and flow WebViews can emit this event
|
|
463
|
+
if (payViaBankCompletedHandledRef.current) {
|
|
464
|
+
if (devMode) {
|
|
465
|
+
console.log("[Glomo-RN-SDK Standard] Pay via bank completed already handled, ignoring duplicate");
|
|
466
|
+
}
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
payViaBankCompletedHandledRef.current = true;
|
|
470
|
+
const payload = messageData === null || messageData === void 0 ? void 0 : messageData.payload;
|
|
471
|
+
if (devMode) {
|
|
472
|
+
console.log("[Glomo-RN-SDK Standard] Pay via bank completed via FlowWebView:", payload);
|
|
473
|
+
}
|
|
474
|
+
setShowFlowWebView(false);
|
|
475
|
+
setShowCheckout(false);
|
|
476
|
+
setFlowWebViewUrl("");
|
|
477
|
+
setStatus("pay_via_bank_completed");
|
|
478
|
+
(0, validation_1.safeCallback)(onPayViaBankCompleted, [{ status: (_h = payload === null || payload === void 0 ? void 0 : payload.status) !== null && _h !== void 0 ? _h : "unknown" }], "onPayViaBankCompleted", devMode);
|
|
479
|
+
(0, analytics_1.trackStandardPayViaBankCompleted)(orderId, publicKey, (_j = payload === null || payload === void 0 ? void 0 : payload.status) !== null && _j !== void 0 ? _j : "unknown", devMode, mockMode, checkoutUrl);
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
catch (error) {
|
|
485
|
+
if (devMode) {
|
|
486
|
+
console.error("[Glomo-RN-SDK Standard] Error parsing FlowWebView message:", error);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}, [
|
|
490
|
+
onPaymentSuccess,
|
|
491
|
+
onPaymentFailure,
|
|
492
|
+
onPayViaBankCompleted,
|
|
493
|
+
onPayViaBankBankConnectionSuccessful,
|
|
494
|
+
devMode,
|
|
495
|
+
mockMode,
|
|
496
|
+
orderId,
|
|
497
|
+
publicKey,
|
|
498
|
+
flowWebViewUrl,
|
|
499
|
+
checkoutUrl,
|
|
500
|
+
]);
|
|
501
|
+
// Handler for the navigation state changes
|
|
502
|
+
const handleNavigationStateChange = (0, react_1.useCallback)((navState) => {
|
|
503
|
+
if (devMode) {
|
|
504
|
+
console.log("[Glomo-RN-SDK Standard] Navigation state:", navState);
|
|
505
|
+
}
|
|
506
|
+
}, [devMode]);
|
|
507
|
+
// Handler for the modal back button press events
|
|
508
|
+
const handleModalBackButton = (0, react_1.useCallback)(() => {
|
|
509
|
+
try {
|
|
510
|
+
if (devMode) {
|
|
511
|
+
console.log("[Glomo-RN-SDK Standard] Modal dismissed/back button pressed");
|
|
512
|
+
}
|
|
513
|
+
if (showFlowWebView) {
|
|
514
|
+
setShowFlowWebView(false);
|
|
515
|
+
setFlowWebViewUrl("");
|
|
516
|
+
}
|
|
517
|
+
setShowCheckout(false);
|
|
518
|
+
if (status === "payment_in_progress") {
|
|
519
|
+
if (devMode) {
|
|
520
|
+
console.log("[Glomo-RN-SDK Standard] In progress payment cancelled");
|
|
521
|
+
}
|
|
522
|
+
setStatus("payment_cancelled");
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
if (devMode) {
|
|
526
|
+
console.log("[Glomo-RN-SDK Standard] Ignoring checkout status update for: " + status);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
(0, validation_1.safeCallback)(onPaymentTerminate, [], "onPaymentTerminate", devMode);
|
|
530
|
+
// Tracking payment terminate callback (user dismiss/back button)
|
|
531
|
+
const terminateSource = react_native_1.Platform.OS === "ios" ? "user_dismiss" : "back_button";
|
|
532
|
+
(0, analytics_1.trackStandardPaymentTerminate)(orderId, terminateSource, publicKey, devMode, mockMode, checkoutUrl);
|
|
533
|
+
}
|
|
534
|
+
catch (error) {
|
|
535
|
+
if (devMode) {
|
|
536
|
+
console.error("[Glomo-RN-SDK Standard] Error in handleModalBackButton:", error);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}, [showFlowWebView, devMode, onPaymentTerminate, status, orderId, publicKey, mockMode, checkoutUrl]);
|
|
540
|
+
/** Closes the flow WebView and returns to the main checkout */
|
|
541
|
+
const handleFlowBack = (0, react_1.useCallback)(() => {
|
|
542
|
+
if (devMode) {
|
|
543
|
+
console.log("[Glomo-RN-SDK Standard] Flow WebView back button pressed");
|
|
544
|
+
}
|
|
545
|
+
setShowFlowWebView(false);
|
|
546
|
+
setFlowWebViewUrl("");
|
|
547
|
+
(0, analytics_1.trackStandardWindowClose)("flow", orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
548
|
+
}, [devMode, orderId, publicKey, mockMode, checkoutUrl]);
|
|
549
|
+
/**
|
|
550
|
+
* Handler for WebView permission requests (e.g. camera access for bank authentication).
|
|
551
|
+
* On Android, prompts the user for camera permission via PermissionsAndroid.
|
|
552
|
+
* On iOS, grants camera access automatically (iOS handles its own permission prompt).
|
|
553
|
+
* Non-camera permissions are denied by default.
|
|
554
|
+
*/
|
|
555
|
+
const handlePermissionRequest = (0, react_1.useCallback)(async (request) => {
|
|
556
|
+
try {
|
|
557
|
+
const { resources } = request.nativeEvent;
|
|
558
|
+
// Checking if the requested permission is camera-related
|
|
559
|
+
const isCameraPermissionRequest = resources.some((resource) => resource === "camera" || resource.toLowerCase().includes("camera"));
|
|
560
|
+
if (!isCameraPermissionRequest) {
|
|
561
|
+
if (devMode) {
|
|
562
|
+
console.log("[Glomo-RN-SDK Standard] Non-camera permission requested, denying:", resources);
|
|
563
|
+
}
|
|
564
|
+
request.deny();
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
if (devMode) {
|
|
568
|
+
console.log("[Glomo-RN-SDK Standard] Camera permission requested by webpage");
|
|
569
|
+
}
|
|
570
|
+
if (react_native_1.Platform.OS === "android") {
|
|
571
|
+
try {
|
|
572
|
+
const granted = await react_native_1.PermissionsAndroid.request(react_native_1.PermissionsAndroid.PERMISSIONS.CAMERA, {
|
|
573
|
+
title: "Camera Permission",
|
|
574
|
+
message: "This app needs camera access for identity verification during checkout",
|
|
575
|
+
buttonNeutral: "Ask Me Later",
|
|
576
|
+
buttonNegative: "Cancel",
|
|
577
|
+
buttonPositive: "OK",
|
|
578
|
+
});
|
|
579
|
+
if (granted === react_native_1.PermissionsAndroid.RESULTS.GRANTED) {
|
|
580
|
+
if (devMode) {
|
|
581
|
+
console.log("[Glomo-RN-SDK Standard] Camera permission granted");
|
|
582
|
+
}
|
|
583
|
+
request.grant(resources);
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
if (devMode) {
|
|
587
|
+
console.log("[Glomo-RN-SDK Standard] Camera permission denied by user");
|
|
588
|
+
}
|
|
589
|
+
setShowCheckout(false);
|
|
590
|
+
if (status === "payment_in_progress") {
|
|
591
|
+
setStatus("payment_cancelled");
|
|
592
|
+
}
|
|
593
|
+
(0, validation_1.safeCallback)(onUserRefusedCameraPermissions, [], "onUserRefusedCameraPermissions", devMode);
|
|
594
|
+
request.deny();
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
catch (err) {
|
|
598
|
+
if (devMode) {
|
|
599
|
+
console.error("[Glomo-RN-SDK Standard] Error requesting camera permission:", err);
|
|
600
|
+
}
|
|
601
|
+
setShowCheckout(false);
|
|
602
|
+
if (status === "payment_in_progress") {
|
|
603
|
+
setStatus("payment_cancelled");
|
|
604
|
+
}
|
|
605
|
+
(0, validation_1.safeCallback)(onUserRefusedCameraPermissions, [], "onUserRefusedCameraPermissions", devMode);
|
|
606
|
+
request.deny();
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
else if (react_native_1.Platform.OS === "ios") {
|
|
610
|
+
if (devMode) {
|
|
611
|
+
console.log("[Glomo-RN-SDK Standard] Granting camera permission request on iOS");
|
|
612
|
+
}
|
|
613
|
+
request.grant(resources);
|
|
614
|
+
}
|
|
615
|
+
else {
|
|
616
|
+
if (devMode) {
|
|
617
|
+
console.warn("[Glomo-RN-SDK Standard] Unsupported platform for camera permissions");
|
|
618
|
+
}
|
|
619
|
+
request.deny();
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
catch (error) {
|
|
623
|
+
if (devMode) {
|
|
624
|
+
console.error("[Glomo-RN-SDK Standard] Error in handlePermissionRequest:", error);
|
|
625
|
+
}
|
|
626
|
+
request.deny();
|
|
627
|
+
}
|
|
628
|
+
}, [devMode, status, onUserRefusedCameraPermissions]);
|
|
629
|
+
/**
|
|
630
|
+
* Initiator method for the Standard Checkout flow.
|
|
631
|
+
* Using a ref, the standard flow can be started by calling this method.
|
|
632
|
+
* Example:
|
|
633
|
+
* const checkoutRef = useRef<GlomoStandardCheckoutRef>(null);
|
|
634
|
+
* checkoutRef.current?.start();
|
|
635
|
+
*
|
|
636
|
+
* The standard checkout can only be started if
|
|
637
|
+
* - The status is "ready", "payment_cancelled", or "payment_failed"
|
|
638
|
+
* - The status is NOT "payment_successful"
|
|
639
|
+
* - Input validation passes
|
|
640
|
+
*/
|
|
641
|
+
const start = (0, react_1.useCallback)(() => {
|
|
642
|
+
/**
|
|
643
|
+
* Checking device security compliance (if peerDependencies are available)
|
|
644
|
+
* A null value indicates that recommended security dependencies were not installed and compliance checks will be skipped in this case
|
|
645
|
+
*/
|
|
646
|
+
const deviceComplianceCheck = (0, device_compliance_1.checkDeviceCompliance)(devMode);
|
|
647
|
+
const jailbreakDetectionLibraryInstalled = (0, device_compliance_1.isComplianceCheckAvailable)();
|
|
648
|
+
const jailbreakDetectionInfo = {
|
|
649
|
+
jailbreakDetectionLibraryInstalled,
|
|
650
|
+
jailbreakDetected: deviceComplianceCheck,
|
|
651
|
+
};
|
|
652
|
+
if (devMode) {
|
|
653
|
+
console.log(`[Glomo-RN-SDK Standard] Attempting to start checkout of ${checkoutUrl} from status: ${status}`);
|
|
654
|
+
}
|
|
655
|
+
// Tracking start attempt with current status
|
|
656
|
+
(0, analytics_1.trackStandardStartAttempt)(status, orderId, publicKey, devMode, mockMode, checkoutUrl, jailbreakDetectionInfo);
|
|
657
|
+
if (deviceComplianceCheck === true) {
|
|
658
|
+
// Device detected as compromised
|
|
659
|
+
if (devMode) {
|
|
660
|
+
console.error("[Glomo-RN-SDK Standard] Cannot start checkout. Device is rooted or jailbroken.");
|
|
661
|
+
}
|
|
662
|
+
const errors = [
|
|
663
|
+
{
|
|
664
|
+
type: "device_forbidden",
|
|
665
|
+
message: "Standard checkout is not allowed on rooted or jailbroken devices.",
|
|
666
|
+
},
|
|
667
|
+
];
|
|
668
|
+
(0, validation_1.safeCallback)(onSdkError, [errors], "onSdkError", devMode);
|
|
669
|
+
// Tracking start() failure
|
|
670
|
+
(0, analytics_1.trackStandardStartFailure)("device_forbidden", orderId, publicKey, devMode, mockMode, checkoutUrl, jailbreakDetectionInfo);
|
|
671
|
+
setShowCheckout(false);
|
|
672
|
+
return false;
|
|
673
|
+
}
|
|
674
|
+
else if (deviceComplianceCheck === null) {
|
|
675
|
+
// This warning was intentionally not gated behind a devMode check to ensure merchants are aware of the strong recommendation to install jail-monkey for enhanced security compliance.
|
|
676
|
+
console.warn("[Glomo-RN-SDK Standard] Device security library not installed - the SDK won't be able to automatically detect rooted/jailbroken devices. It is HIGHLY recommended to install jail-monkey as per the README, and prevent standard checkouts from compromised devices.");
|
|
677
|
+
}
|
|
678
|
+
// Enforcing devMode requirement for development servers
|
|
679
|
+
const resolvedServer = server || "prod";
|
|
680
|
+
if (!devMode && resolvedServer !== "prod") {
|
|
681
|
+
const errors = [
|
|
682
|
+
{
|
|
683
|
+
type: "validation_error",
|
|
684
|
+
message: "Development servers can only be used when devMode is enabled.",
|
|
685
|
+
},
|
|
686
|
+
];
|
|
687
|
+
(0, validation_1.safeCallback)(onSdkError, [errors], "onSdkError", devMode);
|
|
688
|
+
(0, analytics_1.trackStandardSdkError)(errors, orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
689
|
+
(0, analytics_1.trackStandardStartFailure)("validation_error", orderId, publicKey, devMode, mockMode, checkoutUrl, jailbreakDetectionInfo);
|
|
690
|
+
setShowCheckout(false);
|
|
691
|
+
return false;
|
|
692
|
+
}
|
|
693
|
+
// Checking validation errors with detailed field-level messages
|
|
694
|
+
const errors = [];
|
|
695
|
+
if (!(0, validation_1.isValidPublicKey)(publicKey)) {
|
|
696
|
+
const error = {
|
|
697
|
+
type: "validation_error",
|
|
698
|
+
message: "Invalid publicKey: must start with 'live_', 'mock_', or 'test_' and be a valid string",
|
|
699
|
+
field: "publicKey",
|
|
700
|
+
};
|
|
701
|
+
errors.push(error);
|
|
702
|
+
}
|
|
703
|
+
if (!(0, validation_1.isValidOrderId)(orderId)) {
|
|
704
|
+
const error = {
|
|
705
|
+
type: "validation_error",
|
|
706
|
+
message: "Invalid orderId: must start with 'order_' and be a valid string",
|
|
707
|
+
field: "orderId",
|
|
708
|
+
};
|
|
709
|
+
errors.push(error);
|
|
710
|
+
}
|
|
711
|
+
if (!(0, validation_1.isValidUrl)(checkoutUrl)) {
|
|
712
|
+
const error = !(0, validation_1.isValidUrl)(baseCheckoutUrl)
|
|
713
|
+
? {
|
|
714
|
+
type: "validation_error",
|
|
715
|
+
message: "Invalid baseCheckoutUrl: must be a valid HTTP or HTTPS URL",
|
|
716
|
+
field: "baseCheckoutUrl",
|
|
717
|
+
}
|
|
718
|
+
: {
|
|
719
|
+
type: "validation_error",
|
|
720
|
+
message: "Invalid checkoutUrl: must be a valid HTTP or HTTPS URL",
|
|
721
|
+
field: "generatedCheckoutUrl",
|
|
722
|
+
};
|
|
723
|
+
errors.push(error);
|
|
724
|
+
}
|
|
725
|
+
if (errors.length > 0) {
|
|
726
|
+
if (devMode) {
|
|
727
|
+
console.error(`[Glomo-RN-SDK Standard] Cannot start checkout. Validation failed.`);
|
|
728
|
+
}
|
|
729
|
+
(0, validation_1.safeCallback)(onSdkError, [errors], "onSdkError", devMode);
|
|
730
|
+
// Tracking start() failure
|
|
731
|
+
(0, analytics_1.trackStandardSdkError)(errors, orderId, publicKey, devMode, mockMode, checkoutUrl);
|
|
732
|
+
(0, analytics_1.trackStandardStartFailure)("validation_error", orderId, publicKey, devMode, mockMode, checkoutUrl, jailbreakDetectionInfo);
|
|
733
|
+
setShowCheckout(false);
|
|
734
|
+
return false;
|
|
735
|
+
}
|
|
736
|
+
if (status === "payment_successful") {
|
|
737
|
+
if (devMode) {
|
|
738
|
+
console.log(`[Glomo-RN-SDK Standard] Cannot start checkout. Current status: ${status}. Payment already successful.`);
|
|
739
|
+
}
|
|
740
|
+
// Tracking start() failure
|
|
741
|
+
(0, analytics_1.trackStandardStartFailure)("payment_successful", orderId, publicKey, devMode, mockMode, checkoutUrl, jailbreakDetectionInfo);
|
|
742
|
+
setShowCheckout(false);
|
|
743
|
+
return false;
|
|
744
|
+
}
|
|
745
|
+
if (status !== "ready" &&
|
|
746
|
+
status !== "payment_cancelled" &&
|
|
747
|
+
status !== "payment_failed" &&
|
|
748
|
+
status !== "payment_in_progress" &&
|
|
749
|
+
status !== "bank_transfer_submitted" &&
|
|
750
|
+
status !== "pay_via_bank_completed") {
|
|
751
|
+
if (devMode) {
|
|
752
|
+
console.log(`[Glomo-RN-SDK Standard] Cannot start checkout. Unknown status: ${status}.`);
|
|
753
|
+
}
|
|
754
|
+
// Tracking start() failure
|
|
755
|
+
(0, analytics_1.trackStandardStartFailure)("invalid_status", orderId, publicKey, devMode, mockMode, checkoutUrl, jailbreakDetectionInfo);
|
|
756
|
+
setShowCheckout(false);
|
|
757
|
+
return false;
|
|
758
|
+
}
|
|
759
|
+
if (!checkoutUrl) {
|
|
760
|
+
if (devMode) {
|
|
761
|
+
console.error("[Glomo-RN-SDK Standard] Cannot start checkout. Invalid checkout URL.");
|
|
762
|
+
}
|
|
763
|
+
// Tracking start() failure
|
|
764
|
+
(0, analytics_1.trackStandardStartFailure)("invalid_url", orderId, publicKey, devMode, mockMode, checkoutUrl, jailbreakDetectionInfo);
|
|
765
|
+
setShowCheckout(false);
|
|
766
|
+
return false;
|
|
767
|
+
}
|
|
768
|
+
if (devMode) {
|
|
769
|
+
console.log("[Glomo-RN-SDK Standard] Starting checkout from previous state: " + status);
|
|
770
|
+
}
|
|
771
|
+
// Resetting any stale state from a previous checkout attempt before starting a new one
|
|
772
|
+
setShowFlowWebView(false);
|
|
773
|
+
setFlowWebViewUrl("");
|
|
774
|
+
payViaBankCompletedHandledRef.current = false;
|
|
775
|
+
setStatus("payment_in_progress");
|
|
776
|
+
// Tracking successful start
|
|
777
|
+
(0, analytics_1.trackStandardStartSuccess)(orderId, publicKey, devMode, mockMode, checkoutUrl, jailbreakDetectionInfo);
|
|
778
|
+
// Opening the checkout modal
|
|
779
|
+
setShowCheckout(true);
|
|
780
|
+
return true;
|
|
781
|
+
}, [devMode, status, publicKey, orderId, baseCheckoutUrl, checkoutUrl, mockMode, onSdkError, server]);
|
|
782
|
+
// Initializing Segment analytics
|
|
783
|
+
(0, react_1.useEffect)(() => {
|
|
784
|
+
(0, segment_1.initializeSegment)(devMode);
|
|
785
|
+
}, [devMode]);
|
|
786
|
+
// Resetting checkout flow if orderId or publicKey are changed
|
|
787
|
+
(0, react_1.useEffect)(() => {
|
|
788
|
+
if (orderId && publicKey) {
|
|
789
|
+
// Only resetting the checkout flow if the current status is that of a terminal state
|
|
790
|
+
if (status === "payment_successful" ||
|
|
791
|
+
status === "payment_failed" ||
|
|
792
|
+
status === "payment_cancelled" ||
|
|
793
|
+
status === "bank_transfer_submitted" ||
|
|
794
|
+
status === "pay_via_bank_completed") {
|
|
795
|
+
if (devMode) {
|
|
796
|
+
console.log(`[Glomo-RN-SDK Standard] Resetting checkout status ${status} for new orderId ${orderId} and publicKey ${publicKey}`);
|
|
797
|
+
}
|
|
798
|
+
setStatus("ready");
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}, [orderId, publicKey, status, devMode]);
|
|
802
|
+
// Cleaning up on unmount
|
|
803
|
+
(0, react_1.useEffect)(() => {
|
|
804
|
+
return () => {
|
|
805
|
+
// Cleaning up - resetting state on unmount
|
|
806
|
+
setStatus("ready");
|
|
807
|
+
setShowCheckout(false);
|
|
808
|
+
setShowFlowWebView(false);
|
|
809
|
+
setFlowWebViewUrl("");
|
|
810
|
+
};
|
|
811
|
+
}, []);
|
|
812
|
+
return {
|
|
813
|
+
start,
|
|
814
|
+
status,
|
|
815
|
+
showCheckout,
|
|
816
|
+
flowWebViewUrl,
|
|
817
|
+
showFlowWebView,
|
|
818
|
+
checkoutUrl,
|
|
819
|
+
mainWebViewRef,
|
|
820
|
+
flowWebViewRef,
|
|
821
|
+
handleMainWebViewMessage,
|
|
822
|
+
handleFlowWebViewMessage,
|
|
823
|
+
handleError,
|
|
824
|
+
handleHttpError,
|
|
825
|
+
handlePermissionRequest,
|
|
826
|
+
handleNavigationStateChange,
|
|
827
|
+
handleModalBackButton,
|
|
828
|
+
handleFlowBack,
|
|
829
|
+
injectedMain: index_1.InjectionScripts.standard,
|
|
830
|
+
injectedFlow: index_1.InjectionScripts.flow,
|
|
831
|
+
};
|
|
832
|
+
}
|