@deuna/react-native-sdk 1.0.2 → 1.0.4
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 +21 -0
- package/lib/module/DeunaSDK.js +96 -75
- package/lib/module/DeunaSDK.js.map +1 -1
- package/lib/module/components/DeunaWidget.js +54 -26
- package/lib/module/components/DeunaWidget.js.map +1 -1
- package/lib/module/components/ExternalUrlWebView.js +56 -0
- package/lib/module/components/ExternalUrlWebView.js.map +1 -0
- package/lib/module/controllers/BaseWebViewController.js +21 -20
- package/lib/module/controllers/BaseWebViewController.js.map +1 -1
- package/lib/module/controllers/ElementsWidgetController.js +5 -5
- package/lib/module/controllers/ElementsWidgetController.js.map +1 -1
- package/lib/module/controllers/{OpenInNewTabController.js → ExternalUrlController.js} +4 -4
- package/lib/module/controllers/ExternalUrlController.js.map +1 -0
- package/lib/module/controllers/PaymentWidgetController.js +5 -4
- package/lib/module/controllers/PaymentWidgetController.js.map +1 -1
- package/lib/module/helpers/Completer.js +2 -2
- package/lib/module/helpers/Completer.js.map +1 -1
- package/lib/module/helpers/CrossPlatformBrowser.js +51 -0
- package/lib/module/helpers/CrossPlatformBrowser.js.map +1 -0
- package/lib/module/helpers/ExternalUrlHelper.js +96 -0
- package/lib/module/helpers/ExternalUrlHelper.js.map +1 -0
- package/lib/module/helpers/SubmitStrategy.js +44 -0
- package/lib/module/helpers/SubmitStrategy.js.map +1 -0
- package/lib/module/helpers/ViewManager.js +32 -0
- package/lib/module/helpers/ViewManager.js.map +1 -0
- package/lib/module/helpers/{getController.js → buildDeunaWidgetController.js} +12 -4
- package/lib/module/helpers/buildDeunaWidgetController.js.map +1 -0
- package/lib/module/helpers/getSubmitStrategy.js +32 -0
- package/lib/module/helpers/getSubmitStrategy.js.map +1 -0
- package/lib/module/interfaces/constants.js +2 -0
- package/lib/module/interfaces/constants.js.map +1 -1
- package/lib/module/interfaces/types.js.map +1 -1
- package/lib/module/types/helpers/buildElementsLink.js +3 -1
- package/lib/module/types/helpers/buildElementsLink.js.map +1 -1
- package/lib/module/types/helpers/buildPaymentLink.js +3 -1
- package/lib/module/types/helpers/buildPaymentLink.js.map +1 -1
- package/lib/module/types/helpers/buildVoucherLink.js +3 -1
- package/lib/module/types/helpers/buildVoucherLink.js.map +1 -1
- package/lib/module/types/helpers/constants.js +4 -0
- package/lib/module/types/helpers/constants.js.map +1 -0
- package/lib/module/types/helpers/urlConfig.js +1 -1
- package/lib/module/types/helpers/urlConfig.js.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/DeunaSDK.d.ts +14 -13
- package/lib/typescript/deuna-sdk-react-native/src/DeunaSDK.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/components/DeunaWidget.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/components/ExternalUrlWebView.d.ts +7 -0
- package/lib/typescript/deuna-sdk-react-native/src/components/ExternalUrlWebView.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/controllers/BaseWebViewController.d.ts +7 -6
- package/lib/typescript/deuna-sdk-react-native/src/controllers/BaseWebViewController.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/controllers/ElementsWidgetController.d.ts +3 -1
- package/lib/typescript/deuna-sdk-react-native/src/controllers/ElementsWidgetController.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/controllers/{OpenInNewTabController.d.ts → ExternalUrlController.d.ts} +2 -2
- package/lib/typescript/deuna-sdk-react-native/src/controllers/ExternalUrlController.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/controllers/PaymentWidgetController.d.ts +3 -2
- package/lib/typescript/deuna-sdk-react-native/src/controllers/PaymentWidgetController.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/helpers/CrossPlatformBrowser.d.ts +25 -0
- package/lib/typescript/deuna-sdk-react-native/src/helpers/CrossPlatformBrowser.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/helpers/ExternalUrlHelper.d.ts +48 -0
- package/lib/typescript/deuna-sdk-react-native/src/helpers/ExternalUrlHelper.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/helpers/SubmitStrategy.d.ts +23 -0
- package/lib/typescript/deuna-sdk-react-native/src/helpers/SubmitStrategy.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/helpers/ViewManager.d.ts +19 -0
- package/lib/typescript/deuna-sdk-react-native/src/helpers/ViewManager.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/helpers/{getController.d.ts → buildDeunaWidgetController.d.ts} +2 -2
- package/lib/typescript/deuna-sdk-react-native/src/helpers/buildDeunaWidgetController.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/helpers/getSubmitStrategy.d.ts +4 -0
- package/lib/typescript/deuna-sdk-react-native/src/helpers/getSubmitStrategy.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/interfaces/constants.d.ts +2 -0
- package/lib/typescript/deuna-sdk-react-native/src/interfaces/constants.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/interfaces/types.d.ts +6 -0
- package/lib/typescript/deuna-sdk-react-native/src/interfaces/types.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/buildElementsLink.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/buildPaymentLink.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/buildVoucherLink.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/constants.d.ts +2 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/constants.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/urlConfig.d.ts +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/urlConfig.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/callbacks.d.ts +8 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/callbacks.d.ts.map +1 -1
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/initWidgetBase.d.ts +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/initWidgetBase.d.ts.map +1 -1
- package/package.json +7 -5
- package/src/DeunaSDK.ts +115 -83
- package/src/components/DeunaWidget.tsx +75 -35
- package/src/components/ExternalUrlWebView.tsx +65 -0
- package/src/controllers/BaseWebViewController.ts +28 -27
- package/src/controllers/ElementsWidgetController.ts +8 -6
- package/src/controllers/{OpenInNewTabController.ts → ExternalUrlController.ts} +3 -3
- package/src/controllers/PaymentWidgetController.ts +12 -5
- package/src/helpers/Completer.ts +2 -2
- package/src/helpers/CrossPlatformBrowser.ts +49 -0
- package/src/helpers/ExternalUrlHelper.ts +118 -0
- package/src/helpers/SubmitStrategy.ts +67 -0
- package/src/helpers/ViewManager.ts +45 -0
- package/src/helpers/{getController.ts → buildDeunaWidgetController.ts} +11 -4
- package/src/helpers/getSubmitStrategy.ts +42 -0
- package/src/interfaces/constants.ts +5 -1
- package/src/interfaces/types.ts +8 -0
- package/src/types/helpers/buildElementsLink.ts +4 -1
- package/src/types/helpers/buildPaymentLink.ts +2 -0
- package/src/types/helpers/buildVoucherLink.ts +2 -0
- package/src/types/helpers/constants.ts +1 -0
- package/src/types/helpers/urlConfig.ts +3 -1
- package/src/types/interfaces/callbacks.ts +10 -1
- package/src/types/interfaces/initWidgetBase.ts +1 -0
- package/lib/module/components/NewTabWebView.js +0 -56
- package/lib/module/components/NewTabWebView.js.map +0 -1
- package/lib/module/controllers/OpenInNewTabController.js.map +0 -1
- package/lib/module/helpers/getController.js.map +0 -1
- package/lib/typescript/deuna-sdk-react-native/src/components/NewTabWebView.d.ts +0 -7
- package/lib/typescript/deuna-sdk-react-native/src/components/NewTabWebView.d.ts.map +0 -1
- package/lib/typescript/deuna-sdk-react-native/src/controllers/OpenInNewTabController.d.ts.map +0 -1
- package/lib/typescript/deuna-sdk-react-native/src/helpers/getController.d.ts.map +0 -1
- package/src/components/NewTabWebView.tsx +0 -64
|
@@ -8,25 +8,24 @@ import {
|
|
|
8
8
|
State,
|
|
9
9
|
SubmitResult,
|
|
10
10
|
} from '../types';
|
|
11
|
-
import { submitError } from '../interfaces';
|
|
11
|
+
import { submitError, WidgetConfig } from '../interfaces';
|
|
12
12
|
import { Platform } from 'react-native';
|
|
13
13
|
import { ShouldStartLoadRequest } from 'react-native-webview/lib/WebViewTypes';
|
|
14
14
|
|
|
15
15
|
export interface WebViewDelegate {
|
|
16
|
-
|
|
16
|
+
onOpenExternalUrl?: (url: string) => void;
|
|
17
17
|
onCloseButtonPressed?: () => void;
|
|
18
|
-
onCloseSubWebView?: () => void;
|
|
19
18
|
onFileDownload?: (url: string) => void;
|
|
20
|
-
|
|
19
|
+
onCloseExternalUrl?: () => void;
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
export enum WebViewEventType {
|
|
24
23
|
consoleLog = 'consoleLog',
|
|
25
24
|
eventDispatch = 'eventDispatch',
|
|
26
25
|
jsExecutor = 'jsExecutor',
|
|
27
|
-
|
|
26
|
+
openExternalUrl = 'openExternalUrl',
|
|
28
27
|
redirect = 'redirect',
|
|
29
|
-
|
|
28
|
+
closeExternalUrl = 'closeExternalUrl',
|
|
30
29
|
}
|
|
31
30
|
|
|
32
31
|
const DOWNLOAD_FILE_REGEX =
|
|
@@ -34,7 +33,6 @@ const DOWNLOAD_FILE_REGEX =
|
|
|
34
33
|
|
|
35
34
|
export abstract class BaseWebViewController {
|
|
36
35
|
initialized = false;
|
|
37
|
-
redirectUrl: string | null = null;
|
|
38
36
|
webView: WebView | null = null;
|
|
39
37
|
url: string | null = null;
|
|
40
38
|
|
|
@@ -78,26 +76,22 @@ export abstract class BaseWebViewController {
|
|
|
78
76
|
* @returns boolean indicating if the URL should be loaded in current WebView
|
|
79
77
|
*/
|
|
80
78
|
onShouldStartLoadWithRequest = (request: ShouldStartLoadRequest) => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return false;
|
|
79
|
+
if (this.url === request.url) {
|
|
80
|
+
return true;
|
|
84
81
|
}
|
|
85
82
|
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
const
|
|
83
|
+
const isAndroid = Platform.OS === 'android';
|
|
84
|
+
|
|
85
|
+
const isNewNavigation = isAndroid
|
|
86
|
+
? request.url.startsWith('https://')
|
|
87
|
+
: request.navigationType === 'click';
|
|
88
|
+
|
|
89
|
+
const shouldOpenExternally = !this.urlMustBeLoadedInTheSameWebView(
|
|
89
90
|
request.url
|
|
90
91
|
);
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const shouldOpenInNewTab =
|
|
95
|
-
Platform.OS === 'ios'
|
|
96
|
-
? (isClickNavigation || isNewNavigation) && shouldHandleInNewTab
|
|
97
|
-
: isNewNavigation && shouldHandleInNewTab;
|
|
98
|
-
|
|
99
|
-
if (shouldOpenInNewTab) {
|
|
100
|
-
this.delegate?.onOpenInNewTab?.(request.url);
|
|
93
|
+
if (isNewNavigation && shouldOpenExternally) {
|
|
94
|
+
this.delegate?.onOpenExternalUrl?.(request.url);
|
|
101
95
|
return false;
|
|
102
96
|
}
|
|
103
97
|
|
|
@@ -118,6 +112,10 @@ export abstract class DeunaWebViewController extends BaseWebViewController {
|
|
|
118
112
|
redirectUrl: string | null = null;
|
|
119
113
|
closedAction: ClosedAction = 'systemAction';
|
|
120
114
|
|
|
115
|
+
constructor(readonly widgetConfig: WidgetConfig) {
|
|
116
|
+
super();
|
|
117
|
+
}
|
|
118
|
+
|
|
121
119
|
abstract onEventDispatch: (event: Record<string, any>) => void;
|
|
122
120
|
|
|
123
121
|
onLoad = () => {
|
|
@@ -154,18 +152,18 @@ export abstract class DeunaWebViewController extends BaseWebViewController {
|
|
|
154
152
|
this.jsExecutor.requests.get(requestId)?.(data);
|
|
155
153
|
this.jsExecutor.requests.delete(requestId);
|
|
156
154
|
},
|
|
157
|
-
[WebViewEventType.
|
|
158
|
-
this.delegate?.
|
|
155
|
+
[WebViewEventType.openExternalUrl]: () => {
|
|
156
|
+
this.delegate?.onOpenExternalUrl?.(eventData.url);
|
|
159
157
|
},
|
|
160
158
|
[WebViewEventType.redirect]: () => {
|
|
161
159
|
if (this.redirectUrl) {
|
|
162
160
|
return;
|
|
163
161
|
}
|
|
164
162
|
this.redirectUrl = eventData.url;
|
|
165
|
-
this.delegate?.
|
|
163
|
+
this.delegate?.onOpenExternalUrl?.(eventData.url);
|
|
166
164
|
},
|
|
167
|
-
[WebViewEventType.
|
|
168
|
-
this.delegate?.
|
|
165
|
+
[WebViewEventType.closeExternalUrl]: () => {
|
|
166
|
+
this.delegate?.onCloseExternalUrl?.();
|
|
169
167
|
},
|
|
170
168
|
};
|
|
171
169
|
|
|
@@ -175,6 +173,9 @@ export abstract class DeunaWebViewController extends BaseWebViewController {
|
|
|
175
173
|
setXprops = () => {
|
|
176
174
|
this.webView?.injectJavaScript(
|
|
177
175
|
`
|
|
176
|
+
window.open = function(url, target, features) {
|
|
177
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({ type: '${WebViewEventType.openExternalUrl}', url }));
|
|
178
|
+
};
|
|
178
179
|
console.log = function(message) {
|
|
179
180
|
window.ReactNativeWebView.postMessage(JSON.stringify({ type: '${WebViewEventType.consoleLog}', message }));
|
|
180
181
|
};
|
|
@@ -4,11 +4,14 @@ import {
|
|
|
4
4
|
ElementsEventType,
|
|
5
5
|
} from '../interfaces/events/elements';
|
|
6
6
|
import { ElementsWidgetCallbacks } from '../types';
|
|
7
|
-
import { ElementsErrorType } from '../interfaces';
|
|
7
|
+
import { ElementsErrorType, WidgetConfig } from '../interfaces';
|
|
8
8
|
|
|
9
9
|
export class ElementsWidgetController extends DeunaWebViewController {
|
|
10
|
-
constructor(
|
|
11
|
-
|
|
10
|
+
constructor(
|
|
11
|
+
readonly callbacks: ElementsWidgetCallbacks,
|
|
12
|
+
readonly widgetConfig: WidgetConfig
|
|
13
|
+
) {
|
|
14
|
+
super(widgetConfig);
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
onError = (event: any) => {
|
|
@@ -34,12 +37,11 @@ export class ElementsWidgetController extends DeunaWebViewController {
|
|
|
34
37
|
this.delegate?.onCloseButtonPressed?.();
|
|
35
38
|
},
|
|
36
39
|
[ElementsEventType.vaultSaveSuccess]: () => {
|
|
37
|
-
this.delegate?.
|
|
40
|
+
this.delegate?.onCloseExternalUrl?.();
|
|
38
41
|
this.callbacks.onSuccess?.(event.data);
|
|
39
42
|
},
|
|
40
43
|
[ElementsEventType.vaultSaveError]: () => {
|
|
41
|
-
this.delegate?.
|
|
42
|
-
this.delegate?.onCloseSubWebView?.();
|
|
44
|
+
this.delegate?.onCloseExternalUrl?.();
|
|
43
45
|
const { metadata } = elementsEvent.data;
|
|
44
46
|
|
|
45
47
|
if (metadata) {
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from './BaseWebViewController';
|
|
6
6
|
import { DeunaLogs } from '../DeunaLogs';
|
|
7
7
|
|
|
8
|
-
export class
|
|
8
|
+
export class ExternalUrlController extends BaseWebViewController {
|
|
9
9
|
constructor(readonly url: string) {
|
|
10
10
|
super();
|
|
11
11
|
this.url = url;
|
|
@@ -16,7 +16,7 @@ export class OpenInNewTabController extends BaseWebViewController {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
onError = (event: any) => {
|
|
19
|
-
|
|
19
|
+
DeunaLogs.error(`EXTERNAL URL ERROR`, event);
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
urlMustBeLoadedInTheSameWebView = (url: string) => {
|
|
@@ -41,7 +41,7 @@ export class OpenInNewTabController extends BaseWebViewController {
|
|
|
41
41
|
window.ReactNativeWebView.postMessage(JSON.stringify({ type: '${WebViewEventType.consoleLog}', message }));
|
|
42
42
|
};
|
|
43
43
|
window.close = function() {
|
|
44
|
-
window.ReactNativeWebView.postMessage(JSON.stringify({ type: '${WebViewEventType.
|
|
44
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({ type: '${WebViewEventType.closeExternalUrl}', data: '' }));
|
|
45
45
|
};
|
|
46
46
|
(function() {
|
|
47
47
|
setTimeout(function() {
|
|
@@ -4,7 +4,11 @@ import {
|
|
|
4
4
|
PaymentErrorType,
|
|
5
5
|
} from '../interfaces';
|
|
6
6
|
import { constants } from '../interfaces/constants';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
DownloadType,
|
|
9
|
+
OnDownloadFile,
|
|
10
|
+
WidgetConfig,
|
|
11
|
+
} from '../interfaces/types';
|
|
8
12
|
import {
|
|
9
13
|
PaymentWidgetCallbacks,
|
|
10
14
|
NextActionWidgetCallbacks,
|
|
@@ -18,8 +22,11 @@ type Callbacks = PaymentWidgetCallbacks &
|
|
|
18
22
|
OnDownloadFile;
|
|
19
23
|
|
|
20
24
|
export class PaymentWidgetController extends DeunaWebViewController {
|
|
21
|
-
constructor(
|
|
22
|
-
|
|
25
|
+
constructor(
|
|
26
|
+
readonly callbacks: Callbacks,
|
|
27
|
+
readonly widgetConfig: WidgetConfig
|
|
28
|
+
) {
|
|
29
|
+
super(widgetConfig);
|
|
23
30
|
}
|
|
24
31
|
|
|
25
32
|
onError = (event: any) => {
|
|
@@ -78,11 +85,11 @@ export class PaymentWidgetController extends DeunaWebViewController {
|
|
|
78
85
|
this.callbacks.onPaymentProcessing?.();
|
|
79
86
|
},
|
|
80
87
|
[CheckoutEventType.purchase]: () => {
|
|
81
|
-
this.delegate?.
|
|
88
|
+
this.delegate?.onCloseExternalUrl?.();
|
|
82
89
|
this.callbacks.onSuccess?.(checkoutEvent.data.order);
|
|
83
90
|
},
|
|
84
91
|
[CheckoutEventType.purchaseError]: () => {
|
|
85
|
-
this.delegate?.
|
|
92
|
+
this.delegate?.onCloseExternalUrl?.();
|
|
86
93
|
const { metadata } = checkoutEvent.data;
|
|
87
94
|
|
|
88
95
|
if (metadata) {
|
package/src/helpers/Completer.ts
CHANGED
|
@@ -17,14 +17,14 @@ export class Completer<T> {
|
|
|
17
17
|
|
|
18
18
|
complete(value: T): void {
|
|
19
19
|
if (this.completed) return;
|
|
20
|
-
this.completed = true;
|
|
21
20
|
this.resolvePromise?.(value);
|
|
21
|
+
this.completed = true;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
completeError(error: any): void {
|
|
25
25
|
if (this.completed) return;
|
|
26
|
-
this.completed = true;
|
|
27
26
|
this.rejectPromise?.(error);
|
|
27
|
+
this.completed = true;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
isCompleted(): boolean {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as WebBrowser from 'expo-web-browser';
|
|
2
|
+
import { Platform } from 'react-native';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* This class is used to open a browser in a SafariView Controller (iOS) or
|
|
6
|
+
* a Chrome Custom Tab (Android) depending on the platform.
|
|
7
|
+
*
|
|
8
|
+
* It is used to open the external URLs in the DEUNA widget.
|
|
9
|
+
*/
|
|
10
|
+
class CrossPlatformBrowser {
|
|
11
|
+
private initialized = false;
|
|
12
|
+
/**
|
|
13
|
+
* Initialize the browser
|
|
14
|
+
*/
|
|
15
|
+
async initialize() {
|
|
16
|
+
if (this.initialized) return;
|
|
17
|
+
await WebBrowser.maybeCompleteAuthSession();
|
|
18
|
+
this.initialized = true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Open an URL in a SafariView Controller (iOS) or a Chrome Custom Tab (Android) depending on the platform
|
|
23
|
+
* @param url - The URL to open
|
|
24
|
+
*/
|
|
25
|
+
async openBrowser(url: string) {
|
|
26
|
+
try {
|
|
27
|
+
await this.initialize();
|
|
28
|
+
await WebBrowser.openBrowserAsync(url);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error('Error opening browser', error);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Close the browser
|
|
36
|
+
*/
|
|
37
|
+
async closeBrowser() {
|
|
38
|
+
if (Platform.OS !== 'ios') {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
await WebBrowser.dismissBrowser();
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error('Error closing browser', error);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const crossPlatformBrowser = new CrossPlatformBrowser();
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { AppState, Platform } from 'react-native';
|
|
2
|
+
import { WebViewDelegate } from '../controllers/BaseWebViewController';
|
|
3
|
+
import { ExternalUrlController } from '../controllers/ExternalUrlController';
|
|
4
|
+
import { Completer } from './Completer';
|
|
5
|
+
import { crossPlatformBrowser } from './CrossPlatformBrowser';
|
|
6
|
+
|
|
7
|
+
export enum ExternalUrlBrowser {
|
|
8
|
+
WEB_VIEW = 'web_view',
|
|
9
|
+
CROSS_PLATFORM_BROWSER = 'cross_platform_browser',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface OpenUrlParams {
|
|
13
|
+
url: string;
|
|
14
|
+
browser: ExternalUrlBrowser;
|
|
15
|
+
delegate: WebViewDelegate;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface ExternalUrlManager<T extends ExternalUrlBrowser> {
|
|
19
|
+
type: T;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface WebViewManager
|
|
23
|
+
extends ExternalUrlManager<ExternalUrlBrowser.WEB_VIEW> {
|
|
24
|
+
controller: ExternalUrlController;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface CrossPlatformBrowserManager
|
|
28
|
+
extends ExternalUrlManager<ExternalUrlBrowser.CROSS_PLATFORM_BROWSER> {
|
|
29
|
+
type: ExternalUrlBrowser.CROSS_PLATFORM_BROWSER;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class ExternalUrlHelper {
|
|
33
|
+
private manager: ExternalUrlManager<ExternalUrlBrowser> | null = null;
|
|
34
|
+
private completer: Completer<void> | null = null;
|
|
35
|
+
|
|
36
|
+
constructor() {
|
|
37
|
+
this.startCloseChecker();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get externalUrlWebViewController() {
|
|
41
|
+
if (this.manager?.type === ExternalUrlBrowser.WEB_VIEW) {
|
|
42
|
+
return (this.manager as WebViewManager).controller;
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Wait until the webview or cross platform browser is closed
|
|
49
|
+
*/
|
|
50
|
+
async waitForClose() {
|
|
51
|
+
if (this.completer) {
|
|
52
|
+
await this.completer.wait;
|
|
53
|
+
this.completer = null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Listen when the app is brought back to the foreground
|
|
59
|
+
*/
|
|
60
|
+
private startCloseChecker() {
|
|
61
|
+
AppState.addEventListener('change', (state) => {
|
|
62
|
+
if (
|
|
63
|
+
state === 'active' &&
|
|
64
|
+
this.manager?.type === ExternalUrlBrowser.CROSS_PLATFORM_BROWSER
|
|
65
|
+
) {
|
|
66
|
+
this.manager = null;
|
|
67
|
+
this.completeClose();
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Opens the webview or cross platform browser
|
|
74
|
+
*/
|
|
75
|
+
async openUrl(params: OpenUrlParams) {
|
|
76
|
+
const { url, browser, delegate } = params;
|
|
77
|
+
|
|
78
|
+
const mapper = {
|
|
79
|
+
[ExternalUrlBrowser.WEB_VIEW]: async () => {
|
|
80
|
+
const controller = new ExternalUrlController(url);
|
|
81
|
+
controller.delegate = delegate;
|
|
82
|
+
this.manager = {
|
|
83
|
+
type: ExternalUrlBrowser.WEB_VIEW,
|
|
84
|
+
controller,
|
|
85
|
+
} as WebViewManager;
|
|
86
|
+
},
|
|
87
|
+
[ExternalUrlBrowser.CROSS_PLATFORM_BROWSER]: async () => {
|
|
88
|
+
this.completer = new Completer<void>();
|
|
89
|
+
this.manager = {
|
|
90
|
+
type: ExternalUrlBrowser.CROSS_PLATFORM_BROWSER,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
await crossPlatformBrowser.openBrowser(url);
|
|
94
|
+
if (Platform.OS === 'ios') {
|
|
95
|
+
this.completer?.complete();
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
await mapper[browser]();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Notify that the browser has been closed
|
|
104
|
+
*/
|
|
105
|
+
private completeClose() {
|
|
106
|
+
this.completer?.complete();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Closes the web view
|
|
111
|
+
*/
|
|
112
|
+
async closeWebView() {
|
|
113
|
+
if (this.manager?.type === ExternalUrlBrowser.WEB_VIEW) {
|
|
114
|
+
(this.manager as WebViewManager).controller?.dispose();
|
|
115
|
+
this.manager = null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { DeunaSDK } from '../DeunaSDK';
|
|
2
|
+
import { Mode } from '../interfaces';
|
|
3
|
+
import { Environment, SubmitResult } from '../types';
|
|
4
|
+
|
|
5
|
+
export type SubmitStrategyType = 'PayPal';
|
|
6
|
+
|
|
7
|
+
export type SubmitStrategyConfig = {
|
|
8
|
+
publicApiKey: string;
|
|
9
|
+
environment: Environment;
|
|
10
|
+
orderToken?: string;
|
|
11
|
+
userToken?: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export abstract class SubmitStrategy {
|
|
15
|
+
abstract deunaSDK: DeunaSDK;
|
|
16
|
+
constructor(
|
|
17
|
+
readonly config: SubmitStrategyConfig,
|
|
18
|
+
readonly type: SubmitStrategyType
|
|
19
|
+
) {}
|
|
20
|
+
|
|
21
|
+
abstract submit(): Promise<SubmitResult>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class PayPalSubmitStrategy extends SubmitStrategy {
|
|
25
|
+
deunaSDK: DeunaSDK;
|
|
26
|
+
|
|
27
|
+
constructor(
|
|
28
|
+
config: SubmitStrategyConfig,
|
|
29
|
+
readonly onDestroyed: () => void
|
|
30
|
+
) {
|
|
31
|
+
super(config, 'PayPal');
|
|
32
|
+
this.deunaSDK = new DeunaSDK(
|
|
33
|
+
{
|
|
34
|
+
publicApiKey: this.config.publicApiKey,
|
|
35
|
+
environment: this.config.environment,
|
|
36
|
+
},
|
|
37
|
+
this.onDestroyed
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async submit(): Promise<SubmitResult> {
|
|
42
|
+
await this.deunaSDK.initPaymentWidget({
|
|
43
|
+
mode: Mode.MODAL,
|
|
44
|
+
orderToken: this.config.orderToken ?? '',
|
|
45
|
+
userToken: this.config.userToken,
|
|
46
|
+
paymentMethods: [
|
|
47
|
+
{
|
|
48
|
+
paymentMethod: 'wallet',
|
|
49
|
+
processors: ['paypal_wallet'],
|
|
50
|
+
configuration: {
|
|
51
|
+
express: true,
|
|
52
|
+
flowType: {
|
|
53
|
+
type: 'twoStep',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
callbacks: {},
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
status: 'success',
|
|
63
|
+
code: 'success',
|
|
64
|
+
message: 'Payment submitted successfully',
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BaseWebViewController,
|
|
3
|
+
WebViewDelegate,
|
|
4
|
+
} from '../controllers/BaseWebViewController';
|
|
5
|
+
import { Mode } from '../interfaces';
|
|
6
|
+
|
|
7
|
+
export class WebViewManager<
|
|
8
|
+
T extends BaseWebViewController = BaseWebViewController,
|
|
9
|
+
> {
|
|
10
|
+
private _controller: T | null = null;
|
|
11
|
+
private _mode: Mode | null = null;
|
|
12
|
+
|
|
13
|
+
initialize = (params: {
|
|
14
|
+
controller: T;
|
|
15
|
+
delegate: WebViewDelegate;
|
|
16
|
+
mode: Mode;
|
|
17
|
+
}): void => {
|
|
18
|
+
this._controller = params.controller;
|
|
19
|
+
this._controller.delegate = params.delegate;
|
|
20
|
+
this._mode = params.mode;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
get isInitialized(): boolean {
|
|
24
|
+
return !!this._controller;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get mode(): Mode | null {
|
|
28
|
+
return this._mode;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get controller(): T {
|
|
32
|
+
if (!this._controller) {
|
|
33
|
+
throw new Error('WebView not initialized');
|
|
34
|
+
}
|
|
35
|
+
return this._controller;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Destroy the webview and the modal (if it exists)
|
|
40
|
+
*/
|
|
41
|
+
destroy = () => {
|
|
42
|
+
this._controller?.dispose();
|
|
43
|
+
this._controller = null;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -34,7 +34,7 @@ type ControllerProps =
|
|
|
34
34
|
| VoucherWidgetControllerProps
|
|
35
35
|
| ElementsWidgetControllerProps;
|
|
36
36
|
|
|
37
|
-
export const
|
|
37
|
+
export const buildDeunaWidgetController = (
|
|
38
38
|
config: InitializeParams,
|
|
39
39
|
props: ControllerProps & { mode?: Mode; sessionId?: string }
|
|
40
40
|
): DeunaWebViewController => {
|
|
@@ -47,7 +47,8 @@ export const getWidgetController = (
|
|
|
47
47
|
userToken: rest.userToken ?? '',
|
|
48
48
|
language: rest.language ?? 'es',
|
|
49
49
|
sessionId: rest.sessionId ?? '',
|
|
50
|
-
mode: mode
|
|
50
|
+
mode: mode === Mode.MODAL ? 'modal' : 'target',
|
|
51
|
+
...(rest.domain && { domain: rest.domain }),
|
|
51
52
|
};
|
|
52
53
|
|
|
53
54
|
const widgetMappers = {
|
|
@@ -69,10 +70,16 @@ export const getWidgetController = (
|
|
|
69
70
|
voucher: () => baseParams,
|
|
70
71
|
};
|
|
71
72
|
|
|
73
|
+
const widgetConfig = {
|
|
74
|
+
orderToken: rest.orderToken,
|
|
75
|
+
behavior: rest.behavior,
|
|
76
|
+
userToken: rest.userToken,
|
|
77
|
+
};
|
|
78
|
+
|
|
72
79
|
const controller =
|
|
73
80
|
widget === 'elements'
|
|
74
|
-
? new ElementsWidgetController(callbacks)
|
|
75
|
-
: new PaymentWidgetController(callbacks);
|
|
81
|
+
? new ElementsWidgetController(callbacks, widgetConfig)
|
|
82
|
+
: new PaymentWidgetController(callbacks, widgetConfig);
|
|
76
83
|
|
|
77
84
|
controller.url = linkBuilders[widget](widgetMappers[widget]());
|
|
78
85
|
controller.hidePayButton = rest.hidePayButton ?? false;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { DeunaSDK } from '../DeunaSDK';
|
|
2
|
+
import { TWO_STEP_FLOW } from '../interfaces/constants';
|
|
3
|
+
import { PayPalSubmitStrategy, SubmitStrategy } from './SubmitStrategy';
|
|
4
|
+
|
|
5
|
+
export const getSubmitStrategy = async (
|
|
6
|
+
deunaSDK: DeunaSDK
|
|
7
|
+
): Promise<SubmitStrategy | null> => {
|
|
8
|
+
const selectedPaymentMethod = await deunaSDK.getSelectedPaymentMethod();
|
|
9
|
+
if (!selectedPaymentMethod) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const { widgetConfig } = deunaSDK.deunaWidgetManager.controller;
|
|
14
|
+
|
|
15
|
+
const processorName = selectedPaymentMethod.processor_name as string;
|
|
16
|
+
|
|
17
|
+
const configFlowType = selectedPaymentMethod.configuration?.flowType?.type;
|
|
18
|
+
const behaviorFlowType =
|
|
19
|
+
widgetConfig.behavior?.paymentMethods?.flowType?.type;
|
|
20
|
+
|
|
21
|
+
const isTwoStepFlow =
|
|
22
|
+
configFlowType === TWO_STEP_FLOW ||
|
|
23
|
+
(!configFlowType && behaviorFlowType === TWO_STEP_FLOW);
|
|
24
|
+
|
|
25
|
+
if (isTwoStepFlow && processorName === 'paypal_wallet') {
|
|
26
|
+
return new PayPalSubmitStrategy(
|
|
27
|
+
{
|
|
28
|
+
publicApiKey: deunaSDK.config.publicApiKey,
|
|
29
|
+
environment: deunaSDK.config.environment ?? 'production',
|
|
30
|
+
orderToken: widgetConfig.orderToken,
|
|
31
|
+
userToken: widgetConfig.userToken,
|
|
32
|
+
},
|
|
33
|
+
() => {
|
|
34
|
+
if (deunaSDK.submitStrategy) {
|
|
35
|
+
deunaSDK.submitStrategy = null;
|
|
36
|
+
deunaSDK.notifyListeners();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
};
|
|
@@ -4,5 +4,9 @@ export const constants = {
|
|
|
4
4
|
voucherPdfDownloadUrl: 'voucherPdfDownloadUrl',
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
+
export const DEVICE_FINGERPRINT_URL =
|
|
8
|
+
'https://cdn.stg.deuna.io/mobile-sdks/get_fraud_id.html';
|
|
7
9
|
|
|
8
|
-
export const
|
|
10
|
+
export const TWO_STEP_FLOW = 'twoStep';
|
|
11
|
+
|
|
12
|
+
export const DOMAINS_MUST_BE_USE_CROSS_PLATFORM_BROWSER = ['mercadopago.com'];
|
package/src/interfaces/types.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Environment } from "../base";
|
|
2
2
|
import { hasKey } from "../utils/hasKey";
|
|
3
3
|
import { getIntegrationType, UrlConfig } from "./urlConfig";
|
|
4
|
+
import { PLATFORM_DEFAULT } from "./constants";
|
|
4
5
|
|
|
5
6
|
const ELEMENTS_URLS: Record<Environment, string> = {
|
|
6
|
-
production: "https://elements.deuna.
|
|
7
|
+
production: "https://elements.deuna.com",
|
|
7
8
|
sandbox: "https://elements.sandbox.deuna.io",
|
|
8
9
|
staging: "https://elements.stg.deuna.io",
|
|
9
10
|
develop: "https://elements.dev.deuna.io",
|
|
@@ -28,6 +29,7 @@ interface SearchParams {
|
|
|
28
29
|
userToken?: string;
|
|
29
30
|
showSavedCardsFlow?: string;
|
|
30
31
|
showDefaultCardFlow?: string;
|
|
32
|
+
platform?: string;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
/**
|
|
@@ -50,6 +52,7 @@ const buildSearchParams = (config: UrlConfig): URLSearchParams => {
|
|
|
50
52
|
const searchParams: SearchParams = {
|
|
51
53
|
publicApiKey: config.publicApiKey,
|
|
52
54
|
orderToken: config.orderToken,
|
|
55
|
+
platform: config.platform || PLATFORM_DEFAULT,
|
|
53
56
|
email: userInfo?.email || "",
|
|
54
57
|
firstName: userInfo?.firstName || "",
|
|
55
58
|
lastName: userInfo?.lastName || "",
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
getIntegrationType,
|
|
11
11
|
UrlConfig,
|
|
12
12
|
} from "./urlConfig";
|
|
13
|
+
import { PLATFORM_DEFAULT } from "./constants";
|
|
13
14
|
|
|
14
15
|
const urls: Record<Environment, string> = {
|
|
15
16
|
production: "https://pay.deuna.io",
|
|
@@ -31,6 +32,7 @@ export const buildPaymentLink = (config: UrlConfig): string => {
|
|
|
31
32
|
mode: "widget",
|
|
32
33
|
int: getIntegrationType(config.mode),
|
|
33
34
|
language: config.language,
|
|
35
|
+
platform: config.platform || PLATFORM_DEFAULT,
|
|
34
36
|
});
|
|
35
37
|
|
|
36
38
|
// config.
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { Environment } from "../base";
|
|
8
|
+
import { PLATFORM_DEFAULT } from "./constants";
|
|
8
9
|
import { getIntegrationType, UrlConfig } from "./urlConfig";
|
|
9
10
|
|
|
10
11
|
const urls: Record<Environment, string> = {
|
|
@@ -28,6 +29,7 @@ export const buildVoucherLink = (config: UrlConfig): string => {
|
|
|
28
29
|
int: getIntegrationType(config.mode),
|
|
29
30
|
language: config.language,
|
|
30
31
|
orderToken,
|
|
32
|
+
platform: config.platform || PLATFORM_DEFAULT,
|
|
31
33
|
});
|
|
32
34
|
|
|
33
35
|
const xpropsB64 = {
|