@glomopay/react-native-sdk 1.3.5 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -4
- package/lib/config/base.d.ts +14 -5
- package/lib/config/base.d.ts.map +1 -1
- package/lib/config/base.js +22 -6
- package/lib/glomo-lrs-checkout.d.ts.map +1 -1
- package/lib/glomo-lrs-checkout.js +137 -11
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/injections/index.d.ts +1 -0
- package/lib/injections/index.d.ts.map +1 -1
- package/lib/injections/index.js +2 -0
- package/lib/injections/webview-education-carousel.injection.d.ts +3 -0
- package/lib/injections/webview-education-carousel.injection.d.ts.map +1 -0
- package/lib/injections/webview-education-carousel.injection.js +157 -0
- package/lib/injections/webview-flow.injection.d.ts.map +1 -1
- package/lib/injections/webview-flow.injection.js +3 -5
- package/lib/injections/webview-main.injection.d.ts.map +1 -1
- package/lib/injections/webview-main.injection.js +3 -5
- package/lib/use-lrs-checkout.d.ts +13 -1
- package/lib/use-lrs-checkout.d.ts.map +1 -1
- package/lib/use-lrs-checkout.js +114 -8
- package/lib/utils/analytics.d.ts +11 -0
- package/lib/utils/analytics.d.ts.map +1 -1
- package/lib/utils/analytics.js +22 -0
- package/package.json +1 -1
- package/src/config/base.ts +35 -5
- package/src/glomo-lrs-checkout.tsx +186 -12
- package/src/index.ts +1 -0
- package/src/injections/index.ts +2 -0
- package/src/injections/webview-education-carousel.injection.ts +154 -0
- package/src/injections/webview-flow.injection.ts +3 -5
- package/src/injections/webview-main.injection.ts +3 -5
- package/src/use-lrs-checkout.tsx +149 -8
- package/src/utils/analytics.ts +29 -0
package/README.md
CHANGED
|
@@ -70,6 +70,11 @@ For Expo Go limitations, see [Expo documentation](https://docs.expo.dev/workflow
|
|
|
70
70
|
|
|
71
71
|
Before start the checkout flow, you'll need to create an LRS order using other Glomo SDKs and obtain the Order ID (Alphanumeric, starts with `order_`).
|
|
72
72
|
|
|
73
|
+
### Breaking Changes (latest)
|
|
74
|
+
|
|
75
|
+
- `server` no longer accepts a custom URL string. It now accepts one of: `"prod"`, `"staging"`.
|
|
76
|
+
- `educationURL` has been removed from the public API. The SDK now manages any educational content behavior internally.
|
|
77
|
+
|
|
73
78
|
### 1. Import the SDK
|
|
74
79
|
|
|
75
80
|
```tsx
|
|
@@ -141,7 +146,7 @@ function CheckoutScreen()
|
|
|
141
146
|
|
|
142
147
|
| Prop | Type | Required | Description |
|
|
143
148
|
|------|------|----------|-------------|
|
|
144
|
-
| `server` | `
|
|
149
|
+
| `server` | `"prod" \| "staging"` | No | (For development use ONLY) SDK server environment selector. Defaults to `"prod"` when omitted. |
|
|
145
150
|
| `publicKey` | `string` | Yes | Your public key. If it starts with `test_`, mock mode will be enabled automatically. Otherwise, live mode is used. |
|
|
146
151
|
| `orderId` | `string` | Yes | The order ID for this transaction. Must start with `order_` |
|
|
147
152
|
| `onPaymentSuccess` | `(payload: GlomoLrsCheckoutPayload) => void` | Yes | Callback function called when the payment is successful |
|
|
@@ -291,7 +296,7 @@ ready → payment_in_progress → payment_successful (order complete)
|
|
|
291
296
|
- **Device Security Compliance**: If peer dependency `jail-monkey` is installed and the device does not meet compliance requirements (the device is rooted/jailbroken), `start()` will return `false`. Check `onSdkError` callback for `device_forbidden` errors.
|
|
292
297
|
- However, if `jail-monkey` has not been installed, security compliance checks will be skipped.
|
|
293
298
|
- Check that `orderId` is provided and valid (must start with `order_`)
|
|
294
|
-
- If you're providing `server`,
|
|
299
|
+
- If you're providing `server`, ensure it is one of: `"prod"`, `"staging"` (defaults to `"prod"` when omitted)
|
|
295
300
|
- Ensure `publicKey` is valid (must start with `live_`)
|
|
296
301
|
- Implement `onSdkError` callback to receive validation and device compliance error details
|
|
297
302
|
|
|
@@ -410,11 +415,11 @@ The SDK automatically validates all inputs:
|
|
|
410
415
|
|
|
411
416
|
- **`publicKey`**: Must start with `live_` and have a minimum length of 6 characters
|
|
412
417
|
- **`orderId`**: Must start with `order_` and have a minimum length of 7 characters
|
|
413
|
-
- **`server`**: Must be
|
|
418
|
+
- **`server`**: Optional. Must be one of `"prod"`, `"staging"` (defaults to `"prod"` when omitted)
|
|
414
419
|
|
|
415
420
|
Validation errors are reported through the `onSdkError` callback. The SDK validates inputs when `start()` is called:
|
|
416
421
|
- Device security compliance check (first, before any other validation)
|
|
417
|
-
- Input validation (publicKey, orderId, server)
|
|
422
|
+
- Input validation (publicKey, orderId, and server environment)
|
|
418
423
|
- Checkout URL validation (before building the final URL)
|
|
419
424
|
|
|
420
425
|
**Example:**
|
package/lib/config/base.d.ts
CHANGED
|
@@ -2,9 +2,18 @@
|
|
|
2
2
|
* Base Configuration variables for GlomoPay RN SDK
|
|
3
3
|
* This file contains the default base configuration variables for the GlomoPay RN SDK.
|
|
4
4
|
*/
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
/** The publicly documented server environments for the SDK */
|
|
6
|
+
export type GlomoLrsServer = "prod" | "staging";
|
|
7
|
+
/** Internal extension that adds "local" for development use — not exported */
|
|
8
|
+
type InternalGlomoLrsServer = GlomoLrsServer | "local";
|
|
9
|
+
/** Base URLs for a given server environment */
|
|
10
|
+
export interface GlomoLrsServerConfig {
|
|
11
|
+
checkoutBaseUrl: string;
|
|
12
|
+
educationCarouselBaseUrl: string;
|
|
13
|
+
}
|
|
14
|
+
export declare const DEFAULT_SERVER: InternalGlomoLrsServer;
|
|
15
|
+
export declare const SERVER_CONFIGS: Record<InternalGlomoLrsServer, GlomoLrsServerConfig>;
|
|
16
|
+
/** Returns the server config for the given environment, falling back to the default (prod) server */
|
|
17
|
+
export declare function resolveServerConfig(server?: InternalGlomoLrsServer): GlomoLrsServerConfig;
|
|
18
|
+
export {};
|
|
10
19
|
//# sourceMappingURL=base.d.ts.map
|
package/lib/config/base.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/config/base.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/config/base.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,8DAA8D;AAC9D,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,SAAS,CAAC;AAEhD,8EAA8E;AAC9E,KAAK,sBAAsB,GAAG,cAAc,GAAG,OAAO,CAAC;AAEvD,+CAA+C;AAC/C,MAAM,WAAW,oBAAoB;IACjC,eAAe,EAAE,MAAM,CAAC;IACxB,wBAAwB,EAAE,MAAM,CAAC;CACpC;AAED,eAAO,MAAM,cAAc,EAAE,sBAA+B,CAAC;AAE7D,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,sBAAsB,EAAE,oBAAoB,CAa/E,CAAC;AAEF,qGAAqG;AACrG,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,sBAAsB,GAAG,oBAAoB,CAIzF"}
|
package/lib/config/base.js
CHANGED
|
@@ -4,9 +4,25 @@
|
|
|
4
4
|
* This file contains the default base configuration variables for the GlomoPay RN SDK.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
exports.SERVER_CONFIGS = exports.DEFAULT_SERVER = void 0;
|
|
8
|
+
exports.resolveServerConfig = resolveServerConfig;
|
|
9
|
+
exports.DEFAULT_SERVER = "prod";
|
|
10
|
+
exports.SERVER_CONFIGS = {
|
|
11
|
+
prod: {
|
|
12
|
+
checkoutBaseUrl: "https://lrs-checkout.glomopay.com/",
|
|
13
|
+
educationCarouselBaseUrl: "https://glomopay-utilities.web.app/lrs-education-carousel/",
|
|
14
|
+
},
|
|
15
|
+
staging: {
|
|
16
|
+
checkoutBaseUrl: "https://lrs-checkout-page-staging.web.app/",
|
|
17
|
+
educationCarouselBaseUrl: "https://glomopay-utilities-staging.web.app/lrs-education-carousel/",
|
|
18
|
+
},
|
|
19
|
+
local: {
|
|
20
|
+
checkoutBaseUrl: "http://localhost:6870/",
|
|
21
|
+
educationCarouselBaseUrl: "http://localhost:6871/lrs-education-carousel/",
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
/** Returns the server config for the given environment, falling back to the default (prod) server */
|
|
25
|
+
function resolveServerConfig(server) {
|
|
26
|
+
const resolvedServer = server && server in exports.SERVER_CONFIGS ? server : exports.DEFAULT_SERVER;
|
|
27
|
+
return exports.SERVER_CONFIGS[resolvedServer];
|
|
28
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glomo-lrs-checkout.d.ts","sourceRoot":"","sources":["../src/glomo-lrs-checkout.tsx"],"names":[],"mappings":"AAAA,0CAA0C;AAE1C,OAAO,KAAmD,MAAM,OAAO,CAAC;AAIxE,OAAO,EAAkB,KAAK,qBAAqB,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACxG,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAGlD,MAAM,WAAW,qBAAsB,SAAQ,qBAAqB;IAChE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;CACjD;AAED,MAAM,WAAW,mBAAmB;IAChC,KAAK,EAAE,MAAM,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,iBAAiB,CAAC;CACtC;
|
|
1
|
+
{"version":3,"file":"glomo-lrs-checkout.d.ts","sourceRoot":"","sources":["../src/glomo-lrs-checkout.tsx"],"names":[],"mappings":"AAAA,0CAA0C;AAE1C,OAAO,KAAmD,MAAM,OAAO,CAAC;AAIxE,OAAO,EAAkB,KAAK,qBAAqB,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACxG,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAGlD,MAAM,WAAW,qBAAsB,SAAQ,qBAAqB;IAChE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;CACjD;AAED,MAAM,WAAW,mBAAmB;IAChC,KAAK,EAAE,MAAM,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,iBAAiB,CAAC;CACtC;AAwWD,eAAO,MAAM,gBAAgB,mGAAoF,CAAC"}
|
|
@@ -43,7 +43,7 @@ const validation_1 = require("./utils/validation");
|
|
|
43
43
|
/**
|
|
44
44
|
* The Main GlomoPay LRS Checkout Component
|
|
45
45
|
*
|
|
46
|
-
* @param server - Optional. The
|
|
46
|
+
* @param server - Optional. The SDK server environment. For development builds ONLY.
|
|
47
47
|
* @param publicKey - The public key for the merchant. If it starts with "test_", mock mode will be enabled automatically. Otherwise, live mode is used.
|
|
48
48
|
* @param orderId - The order ID. Always starts with "order_"
|
|
49
49
|
*
|
|
@@ -63,12 +63,13 @@ function GlomoLrsCheckoutComponent({ server, publicKey, orderId, onPaymentSucces
|
|
|
63
63
|
// Computing mockMode based on the publicKey prefix
|
|
64
64
|
const mockMode = (0, react_1.useMemo)(() => {
|
|
65
65
|
var _a;
|
|
66
|
+
const resolvedMockMode = (_a = publicKey === null || publicKey === void 0 ? void 0 : publicKey.toLowerCase().startsWith("test_")) !== null && _a !== void 0 ? _a : false;
|
|
66
67
|
if (devMode) {
|
|
67
|
-
console.log(`[GlomoPay RN SDK] ${
|
|
68
|
+
console.log(`[GlomoPay RN SDK] ${resolvedMockMode ? "Using" : "Not using"} Mock mode for publicKey: ${publicKey}`);
|
|
68
69
|
}
|
|
69
|
-
return
|
|
70
|
+
return resolvedMockMode;
|
|
70
71
|
}, [publicKey, devMode]);
|
|
71
|
-
const { start, status, showCheckout, flowWebViewUrl, showFlowWebView, checkoutUrl, mainWebViewRef, flowWebViewRef, handleMainWebViewMessage, handleFlowWebViewMessage, handleError, handleHttpError, handleNavigationStateChange, handleModalBackButton, handleFlowBack, injectedMain, injectedFlow, } = (0, use_lrs_checkout_1.useLrsCheckout)({
|
|
72
|
+
const { start, status, showCheckout, flowWebViewUrl, showFlowWebView, educationCarouselUrl: resolvedEducationCarouselUrl, educationCarouselState, checkoutUrl, mainWebViewRef, flowWebViewRef, educationCarouselWebViewRef, handleMainWebViewMessage, handleFlowWebViewMessage, handleEducationCarouselWebViewMessage, handleError, handleHttpError, handleNavigationStateChange, handleModalBackButton, handleFlowBack, injectedMain, injectedFlow, injectedEducationCarousel, } = (0, use_lrs_checkout_1.useLrsCheckout)({
|
|
72
73
|
server,
|
|
73
74
|
publicKey,
|
|
74
75
|
orderId,
|
|
@@ -84,8 +85,57 @@ function GlomoLrsCheckoutComponent({ server, publicKey, orderId, onPaymentSucces
|
|
|
84
85
|
start,
|
|
85
86
|
getStatus: () => status,
|
|
86
87
|
}));
|
|
88
|
+
/**
|
|
89
|
+
* Injecting a viewport meta tag and CSS text-size-adjust guard into the carousel WebView on load.
|
|
90
|
+
* This prevents the OS from auto-scaling text (especially on Android), which can break the carousel layout.
|
|
91
|
+
*/
|
|
92
|
+
const carouselViewportGuardScript = (0, react_1.useMemo)(() => `
|
|
93
|
+
(function() {
|
|
94
|
+
try {
|
|
95
|
+
var viewportContent = "width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover";
|
|
96
|
+
var viewportTag = document.querySelector("meta[name='viewport']");
|
|
97
|
+
|
|
98
|
+
if (!viewportTag) {
|
|
99
|
+
viewportTag = document.createElement("meta");
|
|
100
|
+
viewportTag.setAttribute("name", "viewport");
|
|
101
|
+
var headOrRoot = document.head || document.documentElement;
|
|
102
|
+
if (headOrRoot) {
|
|
103
|
+
headOrRoot.appendChild(viewportTag);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (viewportTag) {
|
|
108
|
+
viewportTag.setAttribute("content", viewportContent);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
var styleTagId = "__glomo_rn_webview_scale_guard__";
|
|
112
|
+
var existingStyleTag = document.getElementById(styleTagId);
|
|
113
|
+
if (!existingStyleTag) {
|
|
114
|
+
var styleTag = document.createElement("style");
|
|
115
|
+
styleTag.id = styleTagId;
|
|
116
|
+
styleTag.textContent = "html, body, * { -webkit-text-size-adjust: 100% !important; text-size-adjust: 100% !important; }";
|
|
117
|
+
var styleHost = document.head || document.documentElement;
|
|
118
|
+
if (styleHost) {
|
|
119
|
+
styleHost.appendChild(styleTag);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
} catch (error) {}
|
|
123
|
+
true;
|
|
124
|
+
})();
|
|
125
|
+
`, []);
|
|
126
|
+
/**
|
|
127
|
+
* Locking down zoom and scaling behaviour for the carousel WebView.
|
|
128
|
+
* setSupportZoom/scalesPageToFit prevent user-initiated and system-initiated zoom;
|
|
129
|
+
* textZoom=100 on Android normalises the system font-size setting so the carousel isn't affected.
|
|
130
|
+
*/
|
|
131
|
+
const carouselWebViewProps = (0, react_1.useMemo)(() => ({
|
|
132
|
+
setSupportZoom: false,
|
|
133
|
+
scalesPageToFit: false,
|
|
134
|
+
overScrollMode: "never",
|
|
135
|
+
textZoom: react_native_1.Platform.OS === "android" ? 100 : undefined,
|
|
136
|
+
}), []);
|
|
87
137
|
// Making the WebView component
|
|
88
|
-
const makeWebView = react_1.default.useCallback((ref, url, messageHandler, identifier, injectedJavaScript) => {
|
|
138
|
+
const makeWebView = react_1.default.useCallback((ref, url, messageHandler, identifier, injectedJavaScript, injectedJavaScriptBeforeContentLoaded, additionalProps) => {
|
|
89
139
|
// Preventing a render if no injection script is provided
|
|
90
140
|
if (!injectedJavaScript) {
|
|
91
141
|
if (devMode) {
|
|
@@ -107,12 +157,37 @@ function GlomoLrsCheckoutComponent({ server, publicKey, orderId, onPaymentSucces
|
|
|
107
157
|
}
|
|
108
158
|
return null;
|
|
109
159
|
}
|
|
110
|
-
return (<react_native_webview_1.WebView ref={ref} webviewDebuggingEnabled={__DEV__ && devMode} javaScriptEnabled={true} domStorageEnabled={true} onMessage={messageHandler} onError={handleError} onHttpError={handleHttpError} onNavigationStateChange={handleNavigationStateChange}
|
|
111
|
-
|
|
160
|
+
return (<react_native_webview_1.WebView ref={ref} webviewDebuggingEnabled={__DEV__ && devMode} javaScriptEnabled={true} domStorageEnabled={true} onMessage={messageHandler} onError={handleError} onHttpError={handleHttpError} onNavigationStateChange={handleNavigationStateChange} onLoadStart={() => {
|
|
161
|
+
if (devMode) {
|
|
162
|
+
console.log(`[GlomoPay RN SDK] [${identifier}] WebView load started for ${url}`);
|
|
163
|
+
}
|
|
164
|
+
}} onLoadEnd={() => {
|
|
165
|
+
if (identifier === "educationCarousel" && ref.current && carouselViewportGuardScript) {
|
|
166
|
+
ref.current.injectJavaScript(carouselViewportGuardScript);
|
|
167
|
+
}
|
|
168
|
+
if (devMode) {
|
|
169
|
+
console.log(`[GlomoPay RN SDK] [${identifier}] WebView load ended for ${url}`);
|
|
170
|
+
}
|
|
171
|
+
}} onLoadProgress={({ nativeEvent }) => {
|
|
172
|
+
if (devMode && identifier === "educationCarousel") {
|
|
173
|
+
console.log(`[GlomoPay RN SDK] [educationCarousel] load progress=${nativeEvent.progress} url=${nativeEvent.url}`);
|
|
174
|
+
}
|
|
175
|
+
}} source={{ uri: url }} javaScriptCanOpenWindowsAutomatically={true} setSupportMultipleWindows={true} incognito={true} cacheEnabled={false} cacheMode='LOAD_NO_CACHE' pullToRefreshEnabled={false} limitsNavigationsToAppBoundDomains={false} menuItems={[]} injectedJavaScript={injectedJavaScript} injectedJavaScriptBeforeContentLoaded={injectedJavaScriptBeforeContentLoaded} style={styles.webview} showsHorizontalScrollIndicator={false} showsVerticalScrollIndicator={false} mixedContentMode='always' thirdPartyCookiesEnabled={true} sharedCookiesEnabled={true} allowsInlineMediaPlayback={true} mediaPlaybackRequiresUserAction={false} {...additionalProps}/>);
|
|
176
|
+
}, [handleError, handleHttpError, handleNavigationStateChange, devMode, carouselViewportGuardScript]);
|
|
112
177
|
const MainWebViewComponent = (0, react_1.useMemo)(() => makeWebView(mainWebViewRef, checkoutUrl, handleMainWebViewMessage, "main", injectedMain), [makeWebView, checkoutUrl, handleMainWebViewMessage, injectedMain, mainWebViewRef]);
|
|
113
178
|
const FlowWebViewComponent = (0, react_1.useMemo)(() => flowWebViewUrl
|
|
114
179
|
? makeWebView(flowWebViewRef, flowWebViewUrl, handleFlowWebViewMessage, "flow", injectedFlow)
|
|
115
180
|
: null, [makeWebView, flowWebViewUrl, handleFlowWebViewMessage, injectedFlow, flowWebViewRef]);
|
|
181
|
+
const EducationCarouselWebViewComponent = (0, react_1.useMemo)(() => resolvedEducationCarouselUrl
|
|
182
|
+
? makeWebView(educationCarouselWebViewRef, resolvedEducationCarouselUrl, handleEducationCarouselWebViewMessage, "educationCarousel", injectedEducationCarousel, undefined, carouselWebViewProps)
|
|
183
|
+
: null, [
|
|
184
|
+
makeWebView,
|
|
185
|
+
resolvedEducationCarouselUrl,
|
|
186
|
+
educationCarouselWebViewRef,
|
|
187
|
+
handleEducationCarouselWebViewMessage,
|
|
188
|
+
injectedEducationCarousel,
|
|
189
|
+
carouselWebViewProps,
|
|
190
|
+
]);
|
|
116
191
|
// Using the controlled visible if provided, otherwise using the internal state
|
|
117
192
|
const isVisible = (0, react_1.useMemo)(() => controlledVisible !== null && controlledVisible !== void 0 ? controlledVisible : showCheckout, [controlledVisible, showCheckout]);
|
|
118
193
|
// Prevent extreme edge cases where validations inside start() do not prevent the flow initialization
|
|
@@ -125,17 +200,44 @@ function GlomoLrsCheckoutComponent({ server, publicKey, orderId, onPaymentSucces
|
|
|
125
200
|
}, [isVisible, checkoutUrl, devMode]);
|
|
126
201
|
// Alias to ensure explicit component reference for React Native
|
|
127
202
|
const ModalComponent = react_native_1.Modal;
|
|
203
|
+
/**
|
|
204
|
+
* Deriving render gates from state:
|
|
205
|
+
* showCarousel: carousel WebView is visible only after it signals it has content
|
|
206
|
+
* shouldRenderFlowOverlay: flow overlay is mounted only when there is an active flow URL
|
|
207
|
+
* shouldRenderEducationCarousel: carousel is rendered inside the flow overlay (depends on shouldRenderFlowOverlay)
|
|
208
|
+
*/
|
|
209
|
+
const showCarousel = educationCarouselState === "hasContent";
|
|
210
|
+
const shouldRenderFlowOverlay = Boolean(showFlowWebView && flowWebViewUrl && FlowWebViewComponent);
|
|
211
|
+
const shouldRenderEducationCarousel = Boolean(shouldRenderFlowOverlay && EducationCarouselWebViewComponent);
|
|
212
|
+
if (devMode) {
|
|
213
|
+
console.log(`[GlomoPay RN SDK] Render gates: modal=${shouldShowModal}, flowOverlay=${shouldRenderFlowOverlay}, educationCarouselWebView=${shouldRenderEducationCarousel}, educationCarouselVisible=${showCarousel}, flowWebViewUrl=${flowWebViewUrl || "<empty>"}, educationCarouselUrl=${resolvedEducationCarouselUrl || "<empty>"}`);
|
|
214
|
+
}
|
|
128
215
|
return (<ModalComponent visible={shouldShowModal} animationType='slide' presentationStyle={react_native_1.Platform.OS === "ios" ? "pageSheet" : "fullScreen"} onRequestClose={handleModalBackButton}>
|
|
129
216
|
<react_native_1.View style={styles.modalContainer}>
|
|
130
217
|
<react_native_1.View style={styles.mainWebViewContainer}>{MainWebViewComponent}</react_native_1.View>
|
|
131
218
|
|
|
132
|
-
{
|
|
219
|
+
{shouldRenderFlowOverlay && (<react_native_1.View style={styles.flowWebViewContainer}>
|
|
133
220
|
<react_native_1.SafeAreaView style={styles.flowHeader}>
|
|
134
221
|
<react_native_1.TouchableOpacity onPress={handleFlowBack} style={styles.flowBackButton}>
|
|
135
222
|
<react_native_1.Text style={styles.flowBackChevron}>‹</react_native_1.Text>
|
|
136
223
|
</react_native_1.TouchableOpacity>
|
|
137
224
|
</react_native_1.SafeAreaView>
|
|
138
|
-
<react_native_1.View style={styles.
|
|
225
|
+
<react_native_1.View style={styles.overlayContentContainer}>
|
|
226
|
+
{shouldRenderEducationCarousel && (<react_native_1.View pointerEvents={showCarousel ? "auto" : "none"} style={[
|
|
227
|
+
styles.educationCarouselContainer,
|
|
228
|
+
showCarousel
|
|
229
|
+
? styles.educationCarouselContainerVisible
|
|
230
|
+
: styles.educationCarouselContainerHidden,
|
|
231
|
+
]}>
|
|
232
|
+
{EducationCarouselWebViewComponent}
|
|
233
|
+
</react_native_1.View>)}
|
|
234
|
+
<react_native_1.View style={[
|
|
235
|
+
styles.flowWebViewContent,
|
|
236
|
+
showCarousel ? styles.flowWebViewContentWithCarousel : null,
|
|
237
|
+
]}>
|
|
238
|
+
{FlowWebViewComponent}
|
|
239
|
+
</react_native_1.View>
|
|
240
|
+
</react_native_1.View>
|
|
139
241
|
</react_native_1.View>)}
|
|
140
242
|
</react_native_1.View>
|
|
141
243
|
</ModalComponent>);
|
|
@@ -169,10 +271,9 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
169
271
|
backgroundColor: "#fff",
|
|
170
272
|
borderBottomWidth: 1,
|
|
171
273
|
borderBottomColor: "#e0e0e0",
|
|
172
|
-
paddingTop: react_native_1.Platform.OS === "android" ? react_native_1.StatusBar.currentHeight : 0,
|
|
173
274
|
},
|
|
174
275
|
flowBackButton: {
|
|
175
|
-
paddingVertical:
|
|
276
|
+
paddingVertical: 0,
|
|
176
277
|
paddingLeft: 20,
|
|
177
278
|
},
|
|
178
279
|
flowBackChevron: {
|
|
@@ -183,6 +284,31 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
183
284
|
flowWebViewContent: {
|
|
184
285
|
flex: 1,
|
|
185
286
|
},
|
|
287
|
+
flowWebViewContentWithCarousel: {
|
|
288
|
+
flex: 8.5,
|
|
289
|
+
},
|
|
290
|
+
overlayContentContainer: {
|
|
291
|
+
flex: 1,
|
|
292
|
+
},
|
|
293
|
+
educationCarouselContainer: {
|
|
294
|
+
flex: 1.5,
|
|
295
|
+
},
|
|
296
|
+
educationCarouselContainerVisible: {
|
|
297
|
+
opacity: 1,
|
|
298
|
+
zIndex: 2,
|
|
299
|
+
elevation: 2,
|
|
300
|
+
},
|
|
301
|
+
educationCarouselContainerHidden: {
|
|
302
|
+
position: "absolute",
|
|
303
|
+
top: 0,
|
|
304
|
+
left: 0,
|
|
305
|
+
width: 1,
|
|
306
|
+
height: 1,
|
|
307
|
+
opacity: 0,
|
|
308
|
+
zIndex: -1,
|
|
309
|
+
elevation: 0,
|
|
310
|
+
overflow: "hidden",
|
|
311
|
+
},
|
|
186
312
|
errorContainer: {
|
|
187
313
|
flex: 1,
|
|
188
314
|
justifyContent: "center",
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** The GlomoPay RN SDK exports */
|
|
2
2
|
export { type GlomoLrsCheckoutPayload, type LrsCheckoutStatus } from "./use-lrs-checkout";
|
|
3
3
|
export { type SdkError } from "./utils/analytics";
|
|
4
|
+
export { type GlomoLrsServer } from "./config/base";
|
|
4
5
|
export { GlomoLrsCheckout, type GlomoLrsCheckoutProps, type GlomoLrsCheckoutRef } from "./glomo-lrs-checkout";
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAGlC,OAAO,EAAE,KAAK,uBAAuB,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1F,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAGlC,OAAO,EAAE,KAAK,uBAAuB,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1F,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/injections/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/injections/index.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,gBAAgB;;;;CAI5B,CAAC"}
|
package/lib/injections/index.js
CHANGED
|
@@ -6,7 +6,9 @@ exports.InjectionScripts = void 0;
|
|
|
6
6
|
*/
|
|
7
7
|
const webview_main_injection_1 = require("./webview-main.injection");
|
|
8
8
|
const webview_flow_injection_1 = require("./webview-flow.injection");
|
|
9
|
+
const webview_education_carousel_injection_1 = require("./webview-education-carousel.injection");
|
|
9
10
|
exports.InjectionScripts = {
|
|
10
11
|
main: webview_main_injection_1.injectedScript,
|
|
11
12
|
flow: webview_flow_injection_1.injectedScript,
|
|
13
|
+
educationCarousel: webview_education_carousel_injection_1.injectedScript,
|
|
12
14
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webview-education-carousel.injection.d.ts","sourceRoot":"","sources":["../../src/injections/webview-education-carousel.injection.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,eAAO,MAAM,cAAc,EAAE,MAwJ5B,CAAC"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.injectedScript = void 0;
|
|
4
|
+
/** Injection JavaScript for the Education Carousel WebView */
|
|
5
|
+
exports.injectedScript = `
|
|
6
|
+
(function() {
|
|
7
|
+
// Handling the carousel
|
|
8
|
+
const LOG_PREFIX = 'EDUCATION_CAROUSEL_WEBVIEW: ';
|
|
9
|
+
|
|
10
|
+
function formatMessage(args) {
|
|
11
|
+
return args.map(function(arg) {
|
|
12
|
+
if (typeof arg === 'object') {
|
|
13
|
+
try {
|
|
14
|
+
return LOG_PREFIX + JSON.stringify(arg, null, 2);
|
|
15
|
+
} catch (error) {
|
|
16
|
+
return LOG_PREFIX + '[unserializable object]';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return LOG_PREFIX + String(arg);
|
|
21
|
+
}).join(' ');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function parseMessageData(rawData) {
|
|
25
|
+
if (typeof rawData === 'string') {
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(rawData);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
return rawData;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return rawData;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function forwardEducationStepsMessage(data, source) {
|
|
37
|
+
const parsedData = parseMessageData(data);
|
|
38
|
+
|
|
39
|
+
if (!parsedData || typeof parsedData !== 'object') {
|
|
40
|
+
safePostMessage({
|
|
41
|
+
type: 'console',
|
|
42
|
+
level: 'debug',
|
|
43
|
+
message: formatMessage(['Ignored non-object carousel message from ' + source, parsedData])
|
|
44
|
+
});
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (parsedData.type !== 'lrs.has_education_steps') {
|
|
49
|
+
safePostMessage({
|
|
50
|
+
type: 'console',
|
|
51
|
+
level: 'debug',
|
|
52
|
+
message: formatMessage(['Ignored unrelated carousel message from ' + source, parsedData])
|
|
53
|
+
});
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
safePostMessage({
|
|
58
|
+
type: 'lrs.has_education_steps',
|
|
59
|
+
value: Boolean(parsedData.value),
|
|
60
|
+
source: source,
|
|
61
|
+
payload: parsedData
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
safePostMessage({
|
|
65
|
+
type: 'console',
|
|
66
|
+
level: 'info',
|
|
67
|
+
message: formatMessage(['Forwarded lrs.has_education_steps from ' + source, parsedData])
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function safePostMessage(payload) {
|
|
72
|
+
try {
|
|
73
|
+
if (window.ReactNativeWebView && typeof window.ReactNativeWebView.postMessage === 'function') {
|
|
74
|
+
window.ReactNativeWebView.postMessage(JSON.stringify(payload));
|
|
75
|
+
}
|
|
76
|
+
} catch (error) {
|
|
77
|
+
originalError && originalError.call(console, LOG_PREFIX + 'Failed to post message to ReactNativeWebView', error);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Overriding console methods
|
|
82
|
+
const originalLog = console.log;
|
|
83
|
+
const originalWarn = console.warn;
|
|
84
|
+
const originalError = console.error;
|
|
85
|
+
const originalInfo = console.info;
|
|
86
|
+
|
|
87
|
+
console.log = function(...args) {
|
|
88
|
+
originalLog.apply(console, args);
|
|
89
|
+
safePostMessage({
|
|
90
|
+
type: 'console',
|
|
91
|
+
level: 'log',
|
|
92
|
+
message: formatMessage(args)
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
console.warn = function(...args) {
|
|
97
|
+
originalWarn.apply(console, args);
|
|
98
|
+
safePostMessage({
|
|
99
|
+
type: 'console',
|
|
100
|
+
level: 'warn',
|
|
101
|
+
message: formatMessage(args)
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
console.error = function(...args) {
|
|
106
|
+
originalError.apply(console, args);
|
|
107
|
+
safePostMessage({
|
|
108
|
+
type: 'console',
|
|
109
|
+
level: 'error',
|
|
110
|
+
message: formatMessage(args)
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
console.info = function(...args) {
|
|
115
|
+
originalInfo.apply(console, args);
|
|
116
|
+
safePostMessage({
|
|
117
|
+
type: 'console',
|
|
118
|
+
level: 'info',
|
|
119
|
+
message: formatMessage(args)
|
|
120
|
+
});
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Listening for unhandled errors
|
|
124
|
+
window.addEventListener('error', function(event) {
|
|
125
|
+
safePostMessage({
|
|
126
|
+
type: 'console',
|
|
127
|
+
level: 'error',
|
|
128
|
+
message: LOG_PREFIX + 'Unhandled Error: ' + event.message + ' at ' + event.filename + ':' + event.lineno
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Listening for unhandled promise rejections
|
|
133
|
+
window.addEventListener('unhandledrejection', function(event) {
|
|
134
|
+
safePostMessage({
|
|
135
|
+
type: 'console',
|
|
136
|
+
level: 'error',
|
|
137
|
+
message: LOG_PREFIX + 'Unhandled Promise Rejection: ' + (event.reason?.toString() || 'Unknown')
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Listening for messages from the WebView
|
|
142
|
+
window.addEventListener('message', function(event) {
|
|
143
|
+
console.log(LOG_PREFIX + 'Message received from window: ' + event.data);
|
|
144
|
+
forwardEducationStepsMessage(event.data, 'window.message');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
document.addEventListener('message', function(event) {
|
|
148
|
+
console.log(LOG_PREFIX + 'Message received from document: ' + event.data);
|
|
149
|
+
forwardEducationStepsMessage(event.data, 'document.message');
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Logging that injection is complete
|
|
153
|
+
console.log(LOG_PREFIX + 'GlomoPay WebView JavaScript injection complete and waiting for lrs.has_education_steps');
|
|
154
|
+
|
|
155
|
+
true; // Required for injected JavaScript
|
|
156
|
+
})();
|
|
157
|
+
`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webview-flow.injection.d.ts","sourceRoot":"","sources":["../../src/injections/webview-flow.injection.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,eAAO,MAAM,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"webview-flow.injection.d.ts","sourceRoot":"","sources":["../../src/injections/webview-flow.injection.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,eAAO,MAAM,cAAc,EAAE,MA4K5B,CAAC"}
|
|
@@ -4,7 +4,7 @@ exports.injectedScript = void 0;
|
|
|
4
4
|
/** Injection JavaScript for the Secondary WebView */
|
|
5
5
|
exports.injectedScript = `
|
|
6
6
|
(function() {
|
|
7
|
-
//
|
|
7
|
+
// Overriding console methods
|
|
8
8
|
const originalLog = console.log;
|
|
9
9
|
const originalWarn = console.warn;
|
|
10
10
|
const originalError = console.error;
|
|
@@ -61,8 +61,7 @@ exports.injectedScript = `
|
|
|
61
61
|
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
62
62
|
type: 'console',
|
|
63
63
|
level: 'network',
|
|
64
|
-
message: "FLOW_WEBVIEW: " + 'FETCH RESPONSE: ' + url + ' - Status: ' + response.status
|
|
65
|
-
extraData: { data: response.responseText }
|
|
64
|
+
message: "FLOW_WEBVIEW: " + 'FETCH RESPONSE: ' + url + ' - Status: ' + response.status
|
|
66
65
|
}));
|
|
67
66
|
return response;
|
|
68
67
|
})
|
|
@@ -97,8 +96,7 @@ exports.injectedScript = `
|
|
|
97
96
|
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
98
97
|
type: 'console',
|
|
99
98
|
level: 'network',
|
|
100
|
-
message: "FLOW_WEBVIEW: " + 'XHR RESPONSE: ' + this._url + ' - Status: ' + this.status
|
|
101
|
-
extraData: { data: this.responseText }
|
|
99
|
+
message: "FLOW_WEBVIEW: " + 'XHR RESPONSE: ' + this._url + ' - Status: ' + this.status
|
|
102
100
|
}));
|
|
103
101
|
});
|
|
104
102
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webview-main.injection.d.ts","sourceRoot":"","sources":["../../src/injections/webview-main.injection.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,eAAO,MAAM,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"webview-main.injection.d.ts","sourceRoot":"","sources":["../../src/injections/webview-main.injection.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,eAAO,MAAM,cAAc,EAAE,MAoL5B,CAAC"}
|
|
@@ -4,7 +4,7 @@ exports.injectedScript = void 0;
|
|
|
4
4
|
/** Injection JavaScript for the Primary WebView */
|
|
5
5
|
exports.injectedScript = `
|
|
6
6
|
(function() {
|
|
7
|
-
//
|
|
7
|
+
// Overriding console methods
|
|
8
8
|
const originalLog = console.log;
|
|
9
9
|
const originalWarn = console.warn;
|
|
10
10
|
const originalError = console.error;
|
|
@@ -97,15 +97,13 @@ exports.injectedScript = `
|
|
|
97
97
|
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
98
98
|
type: 'console',
|
|
99
99
|
level: 'network',
|
|
100
|
-
message: 'XHR RESPONSE LOAD: ' + this._url + ' - Status: ' + this.status
|
|
101
|
-
extraData: { data: this.responseText }
|
|
100
|
+
message: 'XHR RESPONSE LOAD: ' + this._url + ' - Status: ' + this.status
|
|
102
101
|
}));
|
|
103
102
|
} catch (e) {
|
|
104
103
|
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
105
104
|
type: 'console',
|
|
106
105
|
level: 'network',
|
|
107
|
-
message: 'XHR RESPONSE ERROR: ' + this._url + ' - Status: ' + this.status
|
|
108
|
-
extraData: { data: this.responseText }
|
|
106
|
+
message: 'XHR RESPONSE ERROR: ' + this._url + ' - Status: ' + this.status
|
|
109
107
|
}));
|
|
110
108
|
}
|
|
111
109
|
});
|