@glomopay/react-native-sdk 2.0.2 → 3.1.0
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 +79 -0
- package/MIGRATION.md +50 -0
- package/README.md +348 -316
- 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 +106 -0
- package/lib/glomo-lrs-checkout.js +9 -9
- package/lib/glomo-standard-checkout.d.ts +25 -0
- package/lib/glomo-standard-checkout.d.ts.map +1 -0
- package/lib/glomo-standard-checkout.js +229 -0
- package/lib/glomo-subscriptions-checkout.d.ts +8 -0
- package/lib/glomo-subscriptions-checkout.d.ts.map +1 -0
- package/lib/glomo-subscriptions-checkout.js +85 -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 +65 -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/types/subscriptions-checkout.d.ts +29 -0
- package/lib/types/subscriptions-checkout.d.ts.map +1 -0
- package/lib/types/subscriptions-checkout.js +3 -0
- package/lib/use-glomo-checkout.d.ts +54 -0
- package/lib/use-glomo-checkout.d.ts.map +1 -0
- package/lib/use-glomo-checkout.js +261 -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 +76 -93
- package/lib/use-standard-checkout.d.ts +74 -0
- package/lib/use-standard-checkout.d.ts.map +1 -0
- package/lib/use-standard-checkout.js +849 -0
- package/lib/utils/analytics.d.ts +188 -2
- package/lib/utils/analytics.d.ts.map +1 -1
- package/lib/utils/analytics.js +636 -22
- package/lib/utils/device-compliance.d.ts.map +1 -1
- package/lib/utils/device-compliance.js +3 -4
- package/lib/utils/validation.d.ts.map +1 -1
- package/lib/utils/validation.js +7 -6
- package/package.json +17 -5
- package/src/config/base.ts +36 -17
- package/src/config/segment.ts +3 -3
- package/src/glomo-checkout.tsx +147 -0
- package/src/glomo-lrs-checkout.tsx +9 -9
- package/src/glomo-standard-checkout.tsx +353 -0
- package/src/glomo-subscriptions-checkout.tsx +83 -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 +72 -0
- package/src/types/standard-checkout.ts +49 -0
- package/src/types/subscriptions-checkout.ts +31 -0
- package/src/use-glomo-checkout.tsx +369 -0
- package/src/use-lrs-checkout.tsx +91 -111
- package/src/use-standard-checkout.tsx +1203 -0
- package/src/utils/analytics.ts +908 -34
- package/src/utils/device-compliance.ts +3 -4
- package/src/utils/validation.ts +7 -8
|
@@ -0,0 +1,353 @@
|
|
|
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 { type CheckoutAnalyticsTrackers } from "./utils/analytics";
|
|
10
|
+
import { isValidUrl } from "./utils/validation";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Internal-only props for GlomoStandardCheckout.
|
|
14
|
+
* Used by GlomoSubscriptionsCheckout to inject subscription analytics trackers.
|
|
15
|
+
* Not exported to merchants via index.ts.
|
|
16
|
+
*/
|
|
17
|
+
export interface GlomoStandardCheckoutInternalProps extends GlomoStandardCheckoutProps {
|
|
18
|
+
_analyticsTrackers?: CheckoutAnalyticsTrackers;
|
|
19
|
+
_skipOrderIdValidation?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The Main GlomoPay Standard Checkout Component
|
|
24
|
+
*
|
|
25
|
+
* @param server - Optional. The SDK server environment. For development builds ONLY.
|
|
26
|
+
* @param publicKey - The public key for the merchant. If it starts with "test_", mock mode will be enabled automatically. Otherwise, live mode is used.
|
|
27
|
+
* @param orderId - The order ID. Always starts with "order_"
|
|
28
|
+
*
|
|
29
|
+
* @param onPaymentSuccess - The success callback with payload, for a successful payment
|
|
30
|
+
* @param onPaymentFailure - The failure callback with payload, for a failed payment
|
|
31
|
+
* @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)
|
|
32
|
+
*
|
|
33
|
+
* @param onConnectionError - Optional callback for connection/network errors
|
|
34
|
+
* @param onSdkError - Optional callback for handling SDK validation errors and configuration issues
|
|
35
|
+
*
|
|
36
|
+
* @param ref - The ref for the component
|
|
37
|
+
* @param devMode - Turn on to see all logs, warnings, and errors in the console. Off by default
|
|
38
|
+
*/
|
|
39
|
+
function GlomoStandardCheckoutComponent(
|
|
40
|
+
{
|
|
41
|
+
server,
|
|
42
|
+
publicKey,
|
|
43
|
+
orderId,
|
|
44
|
+
onPaymentSuccess,
|
|
45
|
+
onPaymentFailure,
|
|
46
|
+
onConnectionError,
|
|
47
|
+
onPaymentTerminate,
|
|
48
|
+
onSdkError,
|
|
49
|
+
onBankTransferSubmitted,
|
|
50
|
+
onPayViaBankCompleted,
|
|
51
|
+
onPayViaBankBankConnectionSuccessful,
|
|
52
|
+
onUserRefusedCameraPermissions,
|
|
53
|
+
devMode = false,
|
|
54
|
+
_analyticsTrackers,
|
|
55
|
+
_skipOrderIdValidation,
|
|
56
|
+
}: GlomoStandardCheckoutInternalProps,
|
|
57
|
+
ref: React.ForwardedRef<GlomoStandardCheckoutRef>
|
|
58
|
+
) {
|
|
59
|
+
// Computing mockMode based on the publicKey prefix
|
|
60
|
+
const mockMode = useMemo(() => {
|
|
61
|
+
const resolvedMockMode = publicKey?.toLowerCase().startsWith("test_") ?? false;
|
|
62
|
+
if (devMode) {
|
|
63
|
+
console.log(
|
|
64
|
+
`[Glomo-RN-SDK Standard] ${resolvedMockMode ? "Using" : "Not using"} Mock mode for publicKey: ${publicKey}`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
return resolvedMockMode;
|
|
68
|
+
}, [publicKey, devMode]);
|
|
69
|
+
|
|
70
|
+
const {
|
|
71
|
+
start,
|
|
72
|
+
status,
|
|
73
|
+
showCheckout,
|
|
74
|
+
flowWebViewUrl,
|
|
75
|
+
showFlowWebView,
|
|
76
|
+
checkoutUrl,
|
|
77
|
+
mainWebViewRef,
|
|
78
|
+
flowWebViewRef,
|
|
79
|
+
handleMainWebViewMessage,
|
|
80
|
+
handleFlowWebViewMessage,
|
|
81
|
+
handleError,
|
|
82
|
+
handleHttpError,
|
|
83
|
+
handleNavigationStateChange,
|
|
84
|
+
handleModalBackButton,
|
|
85
|
+
handleFlowBack,
|
|
86
|
+
handlePermissionRequest,
|
|
87
|
+
injectedMain,
|
|
88
|
+
injectedFlow,
|
|
89
|
+
} = useStandardCheckout(
|
|
90
|
+
{
|
|
91
|
+
server,
|
|
92
|
+
publicKey,
|
|
93
|
+
orderId,
|
|
94
|
+
onPaymentSuccess,
|
|
95
|
+
onPaymentFailure,
|
|
96
|
+
onConnectionError,
|
|
97
|
+
onPaymentTerminate,
|
|
98
|
+
onSdkError,
|
|
99
|
+
onBankTransferSubmitted,
|
|
100
|
+
onPayViaBankCompleted,
|
|
101
|
+
onPayViaBankBankConnectionSuccessful,
|
|
102
|
+
onUserRefusedCameraPermissions,
|
|
103
|
+
devMode,
|
|
104
|
+
},
|
|
105
|
+
mockMode,
|
|
106
|
+
{ analyticsTrackers: _analyticsTrackers, _skipOrderIdValidation }
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
// Exposing the start() and getStatus() methods via the ref
|
|
110
|
+
useImperativeHandle(ref, () => ({
|
|
111
|
+
start,
|
|
112
|
+
getStatus: () => status,
|
|
113
|
+
}));
|
|
114
|
+
|
|
115
|
+
// Making the WebView component
|
|
116
|
+
const makeWebView = React.useCallback(
|
|
117
|
+
(
|
|
118
|
+
ref: React.RefObject<WebView>,
|
|
119
|
+
url: string,
|
|
120
|
+
messageHandler: (event: WebViewMessageEvent) => void,
|
|
121
|
+
identifier: "main" | "flow",
|
|
122
|
+
injectedJavaScript?: string,
|
|
123
|
+
injectedJavaScriptBeforeContentLoaded?: string,
|
|
124
|
+
additionalProps?: Partial<WebViewProps>
|
|
125
|
+
) => {
|
|
126
|
+
// Preventing a render if no injection script is provided
|
|
127
|
+
if (!injectedJavaScript) {
|
|
128
|
+
if (devMode) {
|
|
129
|
+
console.warn(
|
|
130
|
+
`[Glomo-RN-SDK Standard] JavaScript Injection missing for ${url}. Skipping ${identifier} Render.`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Preventing a render if URL is empty or invalid
|
|
137
|
+
if (!url || url.trim() === "") {
|
|
138
|
+
// Redundantly checking for surprise/extreme edge cases
|
|
139
|
+
if (!isValidUrl(url)) {
|
|
140
|
+
if (devMode) {
|
|
141
|
+
console.error(
|
|
142
|
+
`[Glomo-RN-SDK Standard] Invalid non-empty URL ${url} provided. Skipping ${identifier} Render.`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (devMode) {
|
|
149
|
+
console.error(
|
|
150
|
+
`[Glomo-RN-SDK Standard] Empty or invalid URL provided. Skipping ${identifier} Render.`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
<WebView
|
|
158
|
+
ref={ref}
|
|
159
|
+
webviewDebuggingEnabled={__DEV__ && devMode}
|
|
160
|
+
javaScriptEnabled={true}
|
|
161
|
+
domStorageEnabled={true}
|
|
162
|
+
onMessage={messageHandler}
|
|
163
|
+
onError={handleError}
|
|
164
|
+
onHttpError={handleHttpError}
|
|
165
|
+
onNavigationStateChange={handleNavigationStateChange}
|
|
166
|
+
onLoadStart={() => {
|
|
167
|
+
if (devMode) {
|
|
168
|
+
console.log(`[Glomo-RN-SDK Standard] [${identifier}] WebView load started for ${url}`);
|
|
169
|
+
}
|
|
170
|
+
}}
|
|
171
|
+
onLoadEnd={() => {
|
|
172
|
+
if (devMode) {
|
|
173
|
+
console.log(`[Glomo-RN-SDK Standard] [${identifier}] WebView load ended for ${url}`);
|
|
174
|
+
}
|
|
175
|
+
}}
|
|
176
|
+
source={{ uri: url }}
|
|
177
|
+
javaScriptCanOpenWindowsAutomatically={true}
|
|
178
|
+
setSupportMultipleWindows={true}
|
|
179
|
+
incognito={true}
|
|
180
|
+
cacheEnabled={false}
|
|
181
|
+
cacheMode='LOAD_NO_CACHE'
|
|
182
|
+
pullToRefreshEnabled={false}
|
|
183
|
+
limitsNavigationsToAppBoundDomains={false}
|
|
184
|
+
menuItems={[]}
|
|
185
|
+
injectedJavaScript={injectedJavaScript}
|
|
186
|
+
injectedJavaScriptBeforeContentLoaded={injectedJavaScriptBeforeContentLoaded}
|
|
187
|
+
style={styles.webview}
|
|
188
|
+
showsHorizontalScrollIndicator={false}
|
|
189
|
+
showsVerticalScrollIndicator={false}
|
|
190
|
+
mixedContentMode='always'
|
|
191
|
+
thirdPartyCookiesEnabled={true}
|
|
192
|
+
sharedCookiesEnabled={true}
|
|
193
|
+
allowsInlineMediaPlayback={true}
|
|
194
|
+
mediaPlaybackRequiresUserAction={false}
|
|
195
|
+
mediaCapturePermissionGrantType='prompt'
|
|
196
|
+
allowFileAccess={true}
|
|
197
|
+
allowUniversalAccessFromFileURLs={true}
|
|
198
|
+
allowFileAccessFromFileURLs={true}
|
|
199
|
+
androidLayerType='hardware'
|
|
200
|
+
// @ts-expect-error onPermissionRequest is an Android-only WebView prop not yet in react-native-webview type definitions
|
|
201
|
+
onPermissionRequest={handlePermissionRequest}
|
|
202
|
+
{...additionalProps}
|
|
203
|
+
/>
|
|
204
|
+
);
|
|
205
|
+
},
|
|
206
|
+
[handleError, handleHttpError, handleNavigationStateChange, handlePermissionRequest, devMode]
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const MainWebViewComponent = useMemo(
|
|
210
|
+
() => makeWebView(mainWebViewRef, checkoutUrl, handleMainWebViewMessage, "main", injectedMain),
|
|
211
|
+
[makeWebView, checkoutUrl, handleMainWebViewMessage, injectedMain, mainWebViewRef]
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
const FlowWebViewComponent = useMemo(
|
|
215
|
+
() =>
|
|
216
|
+
flowWebViewUrl
|
|
217
|
+
? makeWebView(flowWebViewRef, flowWebViewUrl, handleFlowWebViewMessage, "flow", injectedFlow)
|
|
218
|
+
: null,
|
|
219
|
+
[makeWebView, flowWebViewUrl, handleFlowWebViewMessage, injectedFlow, flowWebViewRef]
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
const isVisible = showCheckout;
|
|
223
|
+
|
|
224
|
+
// Prevent extreme edge cases where validations inside start() do not prevent the flow initialization
|
|
225
|
+
const shouldShowModal = useMemo(() => {
|
|
226
|
+
const value = isVisible && (checkoutUrl ?? "").trim().length > 0;
|
|
227
|
+
|
|
228
|
+
if (devMode) {
|
|
229
|
+
console.log(
|
|
230
|
+
`[Glomo-RN-SDK Standard] computed visibilityHook: ${value} for internal switch ${isVisible}, and checkout=${checkoutUrl};`
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
return value;
|
|
234
|
+
}, [isVisible, checkoutUrl, devMode]);
|
|
235
|
+
|
|
236
|
+
// Alias to ensure explicit component reference for React Native
|
|
237
|
+
const ModalComponent = Modal;
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Deriving render gates from state:
|
|
241
|
+
* shouldRenderFlowOverlay: flow overlay is mounted only when there is an active flow URL
|
|
242
|
+
*/
|
|
243
|
+
const shouldRenderFlowOverlay = Boolean(showFlowWebView && flowWebViewUrl && FlowWebViewComponent);
|
|
244
|
+
|
|
245
|
+
if (devMode) {
|
|
246
|
+
console.log(
|
|
247
|
+
`[Glomo-RN-SDK Standard] Render gates: modal=${shouldShowModal}, flowOverlay=${shouldRenderFlowOverlay}, flowWebViewUrl=${flowWebViewUrl || "<empty>"}`
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return (
|
|
252
|
+
<ModalComponent
|
|
253
|
+
visible={shouldShowModal}
|
|
254
|
+
animationType='slide'
|
|
255
|
+
presentationStyle={Platform.OS === "ios" ? "pageSheet" : "fullScreen"}
|
|
256
|
+
onRequestClose={handleModalBackButton}
|
|
257
|
+
>
|
|
258
|
+
<View style={styles.modalContainer}>
|
|
259
|
+
<View style={styles.mainWebViewContainer}>{MainWebViewComponent}</View>
|
|
260
|
+
|
|
261
|
+
{shouldRenderFlowOverlay && (
|
|
262
|
+
<View style={styles.flowWebViewContainer}>
|
|
263
|
+
<SafeAreaView style={styles.flowHeader}>
|
|
264
|
+
<TouchableOpacity
|
|
265
|
+
onPress={handleFlowBack}
|
|
266
|
+
style={styles.flowBackButton}
|
|
267
|
+
>
|
|
268
|
+
<Text style={styles.flowBackChevron}>{"\u2039"}</Text>
|
|
269
|
+
</TouchableOpacity>
|
|
270
|
+
</SafeAreaView>
|
|
271
|
+
<View style={styles.flowWebViewContent}>{FlowWebViewComponent}</View>
|
|
272
|
+
</View>
|
|
273
|
+
)}
|
|
274
|
+
</View>
|
|
275
|
+
</ModalComponent>
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Widening the internal type to GlomoStandardCheckoutInternalProps for internal SDK use,
|
|
281
|
+
* then narrowing the public export to GlomoStandardCheckoutProps so merchants cannot
|
|
282
|
+
* pass internal-only props like _analyticsTrackers.
|
|
283
|
+
*/
|
|
284
|
+
export const GlomoStandardCheckout = forwardRef(GlomoStandardCheckoutComponent) as React.ForwardRefExoticComponent<
|
|
285
|
+
GlomoStandardCheckoutProps & React.RefAttributes<GlomoStandardCheckoutRef>
|
|
286
|
+
>;
|
|
287
|
+
|
|
288
|
+
GlomoStandardCheckout.displayName = "GlomoStandardCheckout";
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Internal reference - accepts GlomoStandardCheckoutInternalProps.
|
|
292
|
+
* Not re-exported from index.ts.
|
|
293
|
+
*/
|
|
294
|
+
export const GlomoStandardCheckoutInternal = forwardRef<GlomoStandardCheckoutRef, GlomoStandardCheckoutInternalProps>(
|
|
295
|
+
GlomoStandardCheckoutComponent
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
GlomoStandardCheckoutInternal.displayName = "GlomoStandardCheckoutInternal";
|
|
299
|
+
|
|
300
|
+
const styles = StyleSheet.create({
|
|
301
|
+
modalContainer: {
|
|
302
|
+
flex: 1,
|
|
303
|
+
backgroundColor: "#fff",
|
|
304
|
+
},
|
|
305
|
+
mainWebViewContainer: {
|
|
306
|
+
flex: 1,
|
|
307
|
+
position: "relative",
|
|
308
|
+
},
|
|
309
|
+
webview: {
|
|
310
|
+
flex: 1,
|
|
311
|
+
},
|
|
312
|
+
flowWebViewContainer: {
|
|
313
|
+
position: "absolute",
|
|
314
|
+
top: 0,
|
|
315
|
+
left: 0,
|
|
316
|
+
right: 0,
|
|
317
|
+
bottom: 0,
|
|
318
|
+
flexDirection: "column",
|
|
319
|
+
backgroundColor: "#fff",
|
|
320
|
+
zIndex: 99999,
|
|
321
|
+
elevation: 99999,
|
|
322
|
+
},
|
|
323
|
+
flowHeader: {
|
|
324
|
+
backgroundColor: "#fff",
|
|
325
|
+
borderBottomWidth: 1,
|
|
326
|
+
borderBottomColor: "#e0e0e0",
|
|
327
|
+
},
|
|
328
|
+
flowBackButton: {
|
|
329
|
+
paddingVertical: 0,
|
|
330
|
+
paddingLeft: 20,
|
|
331
|
+
},
|
|
332
|
+
flowBackChevron: {
|
|
333
|
+
fontSize: 42,
|
|
334
|
+
color: "#333",
|
|
335
|
+
lineHeight: 42,
|
|
336
|
+
},
|
|
337
|
+
flowWebViewContent: {
|
|
338
|
+
flex: 1,
|
|
339
|
+
},
|
|
340
|
+
errorContainer: {
|
|
341
|
+
flex: 1,
|
|
342
|
+
justifyContent: "center",
|
|
343
|
+
alignItems: "center",
|
|
344
|
+
padding: 20,
|
|
345
|
+
backgroundColor: "#fff",
|
|
346
|
+
},
|
|
347
|
+
errorText: {
|
|
348
|
+
color: "#d32f2f",
|
|
349
|
+
fontSize: 14,
|
|
350
|
+
textAlign: "center",
|
|
351
|
+
lineHeight: 20,
|
|
352
|
+
},
|
|
353
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GlomoSubscriptionsCheckout - thin wrapper around GlomoStandardCheckout
|
|
3
|
+
* that accepts a subscriptionId (sub_*) instead of an orderId (order_*).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React, { useRef, useImperativeHandle, forwardRef, useEffect } from "react";
|
|
7
|
+
|
|
8
|
+
import { GlomoStandardCheckoutInternal } from "./glomo-standard-checkout";
|
|
9
|
+
import { type GlomoStandardCheckoutRef } from "./types/standard-checkout";
|
|
10
|
+
import {
|
|
11
|
+
type GlomoSubscriptionsCheckoutProps,
|
|
12
|
+
type GlomoSubscriptionsCheckoutRef,
|
|
13
|
+
} from "./types/subscriptions-checkout";
|
|
14
|
+
import { subscriptionCheckoutTrackers } from "./utils/analytics";
|
|
15
|
+
import { safeCallback } from "./utils/validation";
|
|
16
|
+
|
|
17
|
+
function GlomoSubscriptionsCheckoutComponent(
|
|
18
|
+
props: GlomoSubscriptionsCheckoutProps,
|
|
19
|
+
ref: React.ForwardedRef<GlomoSubscriptionsCheckoutRef>
|
|
20
|
+
) {
|
|
21
|
+
const { subscriptionId: rawSubscriptionId, onSdkError, devMode = false, ...rest } = props;
|
|
22
|
+
const innerRef = useRef<GlomoStandardCheckoutRef>(null);
|
|
23
|
+
const onSdkErrorRef = useRef(onSdkError);
|
|
24
|
+
onSdkErrorRef.current = onSdkError;
|
|
25
|
+
|
|
26
|
+
const subscriptionId = rawSubscriptionId.trim();
|
|
27
|
+
|
|
28
|
+
/** Validating subscriptionId - firing onSdkError via useEffect to avoid side effects during render */
|
|
29
|
+
const validationError = (() => {
|
|
30
|
+
if (subscriptionId.length === 0) {
|
|
31
|
+
return "subscriptionId must not be empty";
|
|
32
|
+
}
|
|
33
|
+
if (!subscriptionId.startsWith("sub_")) {
|
|
34
|
+
return "subscriptionId must start with 'sub_'";
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
})();
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (validationError) {
|
|
41
|
+
safeCallback(
|
|
42
|
+
onSdkErrorRef.current,
|
|
43
|
+
[[{ type: "validation_error", message: validationError }]],
|
|
44
|
+
"onSdkError",
|
|
45
|
+
devMode
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}, [validationError, devMode]);
|
|
49
|
+
|
|
50
|
+
useImperativeHandle(ref, () => ({
|
|
51
|
+
start: () => {
|
|
52
|
+
if (validationError) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
return innerRef.current?.start() ?? false;
|
|
56
|
+
},
|
|
57
|
+
getStatus: () => {
|
|
58
|
+
return innerRef.current?.getStatus() ?? "ready";
|
|
59
|
+
},
|
|
60
|
+
}));
|
|
61
|
+
|
|
62
|
+
if (validationError) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<GlomoStandardCheckoutInternal
|
|
68
|
+
ref={innerRef}
|
|
69
|
+
{...rest}
|
|
70
|
+
orderId={subscriptionId}
|
|
71
|
+
onSdkError={onSdkError}
|
|
72
|
+
devMode={devMode}
|
|
73
|
+
_analyticsTrackers={subscriptionCheckoutTrackers}
|
|
74
|
+
_skipOrderIdValidation={true}
|
|
75
|
+
/>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const GlomoSubscriptionsCheckout = forwardRef<GlomoSubscriptionsCheckoutRef, GlomoSubscriptionsCheckoutProps>(
|
|
80
|
+
GlomoSubscriptionsCheckoutComponent
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
GlomoSubscriptionsCheckout.displayName = "GlomoSubscriptionsCheckout";
|
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 { type
|
|
7
|
-
|
|
8
|
-
// Main UI Component for the LRS Checkout flow
|
|
9
|
-
export { GlomoLrsCheckout, type GlomoLrsCheckoutProps, type GlomoLrsCheckoutRef } from "./glomo-lrs-checkout";
|
|
15
|
+
export { useGlomoCheckout, type UseGlomoCheckoutReturn } 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
|
};
|