@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.
Files changed (34) hide show
  1. package/README.md +9 -4
  2. package/lib/config/base.d.ts +14 -5
  3. package/lib/config/base.d.ts.map +1 -1
  4. package/lib/config/base.js +22 -6
  5. package/lib/glomo-lrs-checkout.d.ts.map +1 -1
  6. package/lib/glomo-lrs-checkout.js +137 -11
  7. package/lib/index.d.ts +1 -0
  8. package/lib/index.d.ts.map +1 -1
  9. package/lib/injections/index.d.ts +1 -0
  10. package/lib/injections/index.d.ts.map +1 -1
  11. package/lib/injections/index.js +2 -0
  12. package/lib/injections/webview-education-carousel.injection.d.ts +3 -0
  13. package/lib/injections/webview-education-carousel.injection.d.ts.map +1 -0
  14. package/lib/injections/webview-education-carousel.injection.js +157 -0
  15. package/lib/injections/webview-flow.injection.d.ts.map +1 -1
  16. package/lib/injections/webview-flow.injection.js +3 -5
  17. package/lib/injections/webview-main.injection.d.ts.map +1 -1
  18. package/lib/injections/webview-main.injection.js +3 -5
  19. package/lib/use-lrs-checkout.d.ts +13 -1
  20. package/lib/use-lrs-checkout.d.ts.map +1 -1
  21. package/lib/use-lrs-checkout.js +114 -8
  22. package/lib/utils/analytics.d.ts +11 -0
  23. package/lib/utils/analytics.d.ts.map +1 -1
  24. package/lib/utils/analytics.js +22 -0
  25. package/package.json +1 -1
  26. package/src/config/base.ts +35 -5
  27. package/src/glomo-lrs-checkout.tsx +186 -12
  28. package/src/index.ts +1 -0
  29. package/src/injections/index.ts +2 -0
  30. package/src/injections/webview-education-carousel.injection.ts +154 -0
  31. package/src/injections/webview-flow.injection.ts +3 -5
  32. package/src/injections/webview-main.injection.ts +3 -5
  33. package/src/use-lrs-checkout.tsx +149 -8
  34. 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` | `string` | No | The base LRS checkout server URL. If not provided, defaults to the production URL (`https://lrs-checkout-page-prod.web.app`). Only override this for localhost or staging setups. Must be a valid HTTP or HTTPS URL. |
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`, verify it is accessible and a valid HTTP/HTTPS URL (note: `server` is optional and defaults to production)
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 a valid HTTP or HTTPS URL (optional, defaults to production URL if not provided)
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:**
@@ -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
- * The default URL points to the production environment.
7
- * - DEFAULT_BASE_CHECKOUT_URL: The default base checkout URL for the LRS checkout flow.
8
- */
9
- export declare const DEFAULT_BASE_CHECKOUT_URL = "https://lrs-checkout.glomopay.com/";
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
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/config/base.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,eAAO,MAAM,yBAAyB,uCAAuC,CAAC"}
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"}
@@ -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.DEFAULT_BASE_CHECKOUT_URL = void 0;
8
- /**
9
- * The default URL points to the production environment.
10
- * - DEFAULT_BASE_CHECKOUT_URL: The default base checkout URL for the LRS checkout flow.
11
- */
12
- exports.DEFAULT_BASE_CHECKOUT_URL = "https://lrs-checkout.glomopay.com/";
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;AAkND,eAAO,MAAM,gBAAgB,mGAAoF,CAAC"}
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 base LRS checkout server. If not provided, defaults to the production URL (https://lrs-checkout-page-prod.web.app). Only override this for localhost or staging setups.
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] ${mockMode ? "Using" : "Not using"} Mock mode for publicKey: ${publicKey}`);
68
+ console.log(`[GlomoPay RN SDK] ${resolvedMockMode ? "Using" : "Not using"} Mock mode for publicKey: ${publicKey}`);
68
69
  }
69
- return (_a = publicKey === null || publicKey === void 0 ? void 0 : publicKey.toLowerCase().startsWith("test_")) !== null && _a !== void 0 ? _a : false;
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} source={{ uri: url }} javaScriptCanOpenWindowsAutomatically={true} setSupportMultipleWindows={true} incognito={true} cacheEnabled={false} cacheMode='LOAD_NO_CACHE' pullToRefreshEnabled={false} limitsNavigationsToAppBoundDomains={false} menuItems={[]} injectedJavaScript={injectedJavaScript} style={styles.webview} showsHorizontalScrollIndicator={false} showsVerticalScrollIndicator={false} mixedContentMode='always' thirdPartyCookiesEnabled={true} sharedCookiesEnabled={true} allowsInlineMediaPlayback={true} mediaPlaybackRequiresUserAction={false}/>);
111
- }, [handleError, handleHttpError, handleNavigationStateChange, devMode]);
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
- {showFlowWebView && flowWebViewUrl && FlowWebViewComponent && (<react_native_1.View style={styles.flowWebViewContainer}>
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.flowWebViewContent}>{FlowWebViewComponent}</react_native_1.View>
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: 6,
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
@@ -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;AAGlD,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,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,5 +1,6 @@
1
1
  export declare const InjectionScripts: {
2
2
  main: string;
3
3
  flow: string;
4
+ educationCarousel: string;
4
5
  };
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/injections/index.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,gBAAgB;;;CAG5B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/injections/index.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,gBAAgB;;;;CAI5B,CAAC"}
@@ -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,3 @@
1
+ /** Injection JavaScript for the Education Carousel WebView */
2
+ export declare const injectedScript: string;
3
+ //# sourceMappingURL=webview-education-carousel.injection.d.ts.map
@@ -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,MA8K5B,CAAC"}
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
- // Override console methods
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,MAsL5B,CAAC"}
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
- // Override console methods
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
  });