@deuna/react-native-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +15 -0
- package/lib/module/DeunaLogs.js +18 -0
- package/lib/module/DeunaLogs.js.map +1 -0
- package/lib/module/DeunaSDK.js +207 -0
- package/lib/module/DeunaSDK.js.map +1 -0
- package/lib/module/components/DeunaWebView.js +37 -0
- package/lib/module/components/DeunaWebView.js.map +1 -0
- package/lib/module/components/DeunaWidget.js +82 -0
- package/lib/module/components/DeunaWidget.js.map +1 -0
- package/lib/module/components/NewTabWebView.js +55 -0
- package/lib/module/components/NewTabWebView.js.map +1 -0
- package/lib/module/components/WebViewLoader.js +25 -0
- package/lib/module/components/WebViewLoader.js.map +1 -0
- package/lib/module/controllers/BaseWebViewController.js +252 -0
- package/lib/module/controllers/BaseWebViewController.js.map +1 -0
- package/lib/module/controllers/ElementsWidgetController.js +64 -0
- package/lib/module/controllers/ElementsWidgetController.js.map +1 -0
- package/lib/module/controllers/OpenInNewTabController.js +34 -0
- package/lib/module/controllers/OpenInNewTabController.js.map +1 -0
- package/lib/module/controllers/PaymentWidgetController.js +98 -0
- package/lib/module/controllers/PaymentWidgetController.js.map +1 -0
- package/lib/module/helpers/Completer.js +30 -0
- package/lib/module/helpers/Completer.js.map +1 -0
- package/lib/module/helpers/getController.js +48 -0
- package/lib/module/helpers/getController.js.map +1 -0
- package/lib/module/index.js +7 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/interfaces/constants.js +8 -0
- package/lib/module/interfaces/constants.js.map +1 -0
- package/lib/module/interfaces/errors.js +36 -0
- package/lib/module/interfaces/errors.js.map +1 -0
- package/lib/module/interfaces/events/checkout.js +45 -0
- package/lib/module/interfaces/events/checkout.js.map +1 -0
- package/lib/module/interfaces/events/elements.js +28 -0
- package/lib/module/interfaces/events/elements.js.map +1 -0
- package/lib/module/interfaces/index.js +6 -0
- package/lib/module/interfaces/index.js.map +1 -0
- package/lib/module/interfaces/types.js +13 -0
- package/lib/module/interfaces/types.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types/base.js +24 -0
- package/lib/module/types/base.js.map +1 -0
- package/lib/module/types/env.js +48 -0
- package/lib/module/types/env.js.map +1 -0
- package/lib/module/types/helpers/buildElementsLink.js +75 -0
- package/lib/module/types/helpers/buildElementsLink.js.map +1 -0
- package/lib/module/types/helpers/buildNextActionLink.js +33 -0
- package/lib/module/types/helpers/buildNextActionLink.js.map +1 -0
- package/lib/module/types/helpers/buildPaymentLink.js +54 -0
- package/lib/module/types/helpers/buildPaymentLink.js.map +1 -0
- package/lib/module/types/helpers/buildVoucherLink.js +48 -0
- package/lib/module/types/helpers/buildVoucherLink.js.map +1 -0
- package/lib/module/types/helpers/index.js +13 -0
- package/lib/module/types/helpers/index.js.map +1 -0
- package/lib/module/types/helpers/urlConfig.js +19 -0
- package/lib/module/types/helpers/urlConfig.js.map +1 -0
- package/lib/module/types/index.js +7 -0
- package/lib/module/types/index.js.map +1 -0
- package/lib/module/types/interfaces/callbacks.js +2 -0
- package/lib/module/types/interfaces/callbacks.js.map +1 -0
- package/lib/module/types/interfaces/customStyle.js +2 -0
- package/lib/module/types/interfaces/customStyle.js.map +1 -0
- package/lib/module/types/interfaces/index.js +9 -0
- package/lib/module/types/interfaces/index.js.map +1 -0
- package/lib/module/types/interfaces/initWidgetBase.js +4 -0
- package/lib/module/types/interfaces/initWidgetBase.js.map +1 -0
- package/lib/module/types/interfaces/merchant.js +2 -0
- package/lib/module/types/interfaces/merchant.js.map +1 -0
- package/lib/module/types/interfaces/order.js +2 -0
- package/lib/module/types/interfaces/order.js.map +1 -0
- package/lib/module/types/interfaces/user.js +2 -0
- package/lib/module/types/interfaces/user.js.map +1 -0
- package/lib/module/types/utils/hasKey.js +8 -0
- package/lib/module/types/utils/hasKey.js.map +1 -0
- package/lib/module/types/utils/index.js +4 -0
- package/lib/module/types/utils/index.js.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/DeunaLogs.d.ts +6 -0
- package/lib/typescript/deuna-sdk-react-native/src/DeunaLogs.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/DeunaSDK.d.ts +88 -0
- package/lib/typescript/deuna-sdk-react-native/src/DeunaSDK.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/components/DeunaWebView.d.ts +11 -0
- package/lib/typescript/deuna-sdk-react-native/src/components/DeunaWebView.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/components/DeunaWidget.d.ts +7 -0
- package/lib/typescript/deuna-sdk-react-native/src/components/DeunaWidget.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/components/NewTabWebView.d.ts +7 -0
- package/lib/typescript/deuna-sdk-react-native/src/components/NewTabWebView.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/components/WebViewLoader.d.ts +2 -0
- package/lib/typescript/deuna-sdk-react-native/src/components/WebViewLoader.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/controllers/BaseWebViewController.d.ts +83 -0
- package/lib/typescript/deuna-sdk-react-native/src/controllers/BaseWebViewController.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/controllers/ElementsWidgetController.d.ts +9 -0
- package/lib/typescript/deuna-sdk-react-native/src/controllers/ElementsWidgetController.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/controllers/OpenInNewTabController.d.ts +12 -0
- package/lib/typescript/deuna-sdk-react-native/src/controllers/OpenInNewTabController.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/controllers/PaymentWidgetController.d.ts +12 -0
- package/lib/typescript/deuna-sdk-react-native/src/controllers/PaymentWidgetController.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/helpers/Completer.d.ts +12 -0
- package/lib/typescript/deuna-sdk-react-native/src/helpers/Completer.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/helpers/getController.d.ts +22 -0
- package/lib/typescript/deuna-sdk-react-native/src/helpers/getController.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/index.d.ts +5 -0
- package/lib/typescript/deuna-sdk-react-native/src/index.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/interfaces/constants.d.ts +6 -0
- package/lib/typescript/deuna-sdk-react-native/src/interfaces/constants.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/interfaces/errors.d.ts +32 -0
- package/lib/typescript/deuna-sdk-react-native/src/interfaces/errors.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/interfaces/events/checkout.d.ts +46 -0
- package/lib/typescript/deuna-sdk-react-native/src/interfaces/events/checkout.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/interfaces/events/elements.d.ts +29 -0
- package/lib/typescript/deuna-sdk-react-native/src/interfaces/events/elements.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/interfaces/index.d.ts +4 -0
- package/lib/typescript/deuna-sdk-react-native/src/interfaces/index.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/interfaces/types.d.ts +15 -0
- package/lib/typescript/deuna-sdk-react-native/src/interfaces/types.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/base.d.ts +91 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/base.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/env.d.ts +45 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/env.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/buildElementsLink.d.ts +3 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/buildElementsLink.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/buildNextActionLink.d.ts +3 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/buildNextActionLink.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/buildPaymentLink.d.ts +8 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/buildPaymentLink.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/buildVoucherLink.d.ts +8 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/buildVoucherLink.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/index.d.ts +7 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/index.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/urlConfig.d.ts +34 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/helpers/urlConfig.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/index.d.ts +5 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/index.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/callbacks.d.ts +38 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/callbacks.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/customStyle.d.ts +156 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/customStyle.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/index.d.ts +7 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/index.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/initWidgetBase.d.ts +78 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/initWidgetBase.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/merchant.d.ts +76 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/merchant.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/order.d.ts +3 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/order.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/user.d.ts +23 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/interfaces/user.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/utils/hasKey.d.ts +2 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/utils/hasKey.d.ts.map +1 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/utils/index.d.ts +2 -0
- package/lib/typescript/deuna-sdk-react-native/src/types/utils/index.d.ts.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/package.json +159 -0
- package/src/DeunaLogs.ts +17 -0
- package/src/DeunaSDK.ts +269 -0
- package/src/components/DeunaWebView.tsx +38 -0
- package/src/components/DeunaWidget.tsx +92 -0
- package/src/components/NewTabWebView.tsx +61 -0
- package/src/components/WebViewLoader.tsx +22 -0
- package/src/controllers/BaseWebViewController.ts +289 -0
- package/src/controllers/ElementsWidgetController.ts +78 -0
- package/src/controllers/OpenInNewTabController.ts +39 -0
- package/src/controllers/PaymentWidgetController.ts +118 -0
- package/src/helpers/Completer.ts +33 -0
- package/src/helpers/getController.ts +83 -0
- package/src/index.tsx +4 -0
- package/src/interfaces/constants.ts +5 -0
- package/src/interfaces/errors.ts +34 -0
- package/src/interfaces/events/checkout.ts +46 -0
- package/src/interfaces/events/elements.ts +29 -0
- package/src/interfaces/index.ts +3 -0
- package/src/interfaces/types.ts +13 -0
- package/src/types/base.ts +126 -0
- package/src/types/env.ts +51 -0
- package/src/types/helpers/buildElementsLink.ts +87 -0
- package/src/types/helpers/buildNextActionLink.ts +42 -0
- package/src/types/helpers/buildPaymentLink.ts +63 -0
- package/src/types/helpers/buildVoucherLink.ts +53 -0
- package/src/types/helpers/index.ts +11 -0
- package/src/types/helpers/urlConfig.ts +80 -0
- package/src/types/index.ts +4 -0
- package/src/types/interfaces/callbacks.ts +43 -0
- package/src/types/interfaces/customStyle.ts +189 -0
- package/src/types/interfaces/index.ts +6 -0
- package/src/types/interfaces/initWidgetBase.ts +97 -0
- package/src/types/interfaces/merchant.ts +79 -0
- package/src/types/interfaces/order.ts +1 -0
- package/src/types/interfaces/user.ts +22 -0
- package/src/types/utils/hasKey.ts +5 -0
- package/src/types/utils/index.ts +1 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import type WebView from 'react-native-webview';
|
|
2
|
+
import { DeunaLogs } from '../DeunaLogs';
|
|
3
|
+
import { WebViewMessageEvent } from 'react-native-webview';
|
|
4
|
+
import {
|
|
5
|
+
ClosedAction,
|
|
6
|
+
CustomStyles,
|
|
7
|
+
Json,
|
|
8
|
+
State,
|
|
9
|
+
SubmitResult,
|
|
10
|
+
} from '../types';
|
|
11
|
+
import { submitError } from '../interfaces';
|
|
12
|
+
|
|
13
|
+
export interface WebViewDelegate {
|
|
14
|
+
onOpenInNewTab?: (url: string) => void;
|
|
15
|
+
onCloseButtonPressed?: () => void;
|
|
16
|
+
onCloseSubWebView?: () => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export enum WebViewEventType {
|
|
20
|
+
consoleLog = 'consoleLog',
|
|
21
|
+
eventDispatch = 'eventDispatch',
|
|
22
|
+
jsExecutor = 'jsExecutor',
|
|
23
|
+
openInNewTab = 'openInNewTab',
|
|
24
|
+
redirect = 'redirect',
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export abstract class BaseWebViewController {
|
|
28
|
+
webView: WebView | null = null;
|
|
29
|
+
url: string | null = null;
|
|
30
|
+
|
|
31
|
+
delegate: WebViewDelegate | null = null;
|
|
32
|
+
|
|
33
|
+
abstract setWebView: (webView: WebView) => void;
|
|
34
|
+
abstract onMessage: (event: WebViewMessageEvent) => void;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Called when the web view url is loaded successfully
|
|
38
|
+
*/
|
|
39
|
+
abstract onLoad: () => void;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Called when the web view fails to load a URL
|
|
43
|
+
*/
|
|
44
|
+
abstract onError: (event: any) => void;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Release the web view resources
|
|
48
|
+
*/
|
|
49
|
+
dispose() {
|
|
50
|
+
this.webView?.stopLoading();
|
|
51
|
+
this.webView = null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export abstract class DeunaWebViewController extends BaseWebViewController {
|
|
56
|
+
hidePayButton = false;
|
|
57
|
+
redirectUrl: string | null = null;
|
|
58
|
+
closedAction: ClosedAction = 'systemAction';
|
|
59
|
+
jsExecutor = new JsExecutor();
|
|
60
|
+
|
|
61
|
+
abstract onEventDispatch: (event: Record<string, any>) => void;
|
|
62
|
+
|
|
63
|
+
setWebView = (webView: WebView) => {
|
|
64
|
+
this.webView = webView;
|
|
65
|
+
this.jsExecutor.webView = webView;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
onLoad = () => {
|
|
69
|
+
this.setXprops();
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
onMessage = (event: WebViewMessageEvent) => {
|
|
73
|
+
const eventData = JSON.parse(event.nativeEvent.data);
|
|
74
|
+
|
|
75
|
+
const mapper = {
|
|
76
|
+
[WebViewEventType.consoleLog]: () => {
|
|
77
|
+
DeunaLogs.info(
|
|
78
|
+
`CONSOLE LOG`,
|
|
79
|
+
JSON.stringify(eventData.message, null, 2)
|
|
80
|
+
);
|
|
81
|
+
},
|
|
82
|
+
[WebViewEventType.eventDispatch]: () => {
|
|
83
|
+
this.onEventDispatch(eventData.event);
|
|
84
|
+
},
|
|
85
|
+
[WebViewEventType.jsExecutor]: () => {
|
|
86
|
+
const { data, requestId } = eventData as {
|
|
87
|
+
requestId: number;
|
|
88
|
+
data: Record<string, any> | null;
|
|
89
|
+
};
|
|
90
|
+
this.jsExecutor.requests.get(requestId)?.(data);
|
|
91
|
+
this.jsExecutor.requests.delete(requestId);
|
|
92
|
+
},
|
|
93
|
+
[WebViewEventType.openInNewTab]: () => {
|
|
94
|
+
this.delegate?.onOpenInNewTab?.(eventData.url);
|
|
95
|
+
},
|
|
96
|
+
[WebViewEventType.redirect]: () => {
|
|
97
|
+
if (this.redirectUrl) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
this.redirectUrl = eventData.url;
|
|
101
|
+
this.delegate?.onOpenInNewTab?.(eventData.url);
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
mapper[eventData.type as WebViewEventType]?.();
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
setXprops = () => {
|
|
109
|
+
this.webView?.injectJavaScript(
|
|
110
|
+
`
|
|
111
|
+
document.addEventListener('click', function(event) {
|
|
112
|
+
if (event.target.tagName === 'A' && event.target.href) {
|
|
113
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({ type: '${WebViewEventType.redirect}', url: event.target.href }));
|
|
114
|
+
event.preventDefault(); // Prevent default navigation
|
|
115
|
+
event.stopPropagation();
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
console.log = function(message) {
|
|
119
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({ type: '${WebViewEventType.consoleLog}', message }));
|
|
120
|
+
};
|
|
121
|
+
window.open = function(url, target, features) {
|
|
122
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({ type: '${WebViewEventType.openInNewTab}', url }));
|
|
123
|
+
};
|
|
124
|
+
window.xprops = {
|
|
125
|
+
hidePayButton: ${this.hidePayButton},
|
|
126
|
+
onEventDispatch: function (event) {
|
|
127
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({ type: '${WebViewEventType.eventDispatch}', event }));
|
|
128
|
+
},
|
|
129
|
+
onCustomStyleSubscribe: function (fn) {
|
|
130
|
+
window.setCustomStyle = fn;
|
|
131
|
+
},
|
|
132
|
+
onRefetchOrderSubscribe: function (fn) {
|
|
133
|
+
window.deunaRefetchOrder = fn;
|
|
134
|
+
},
|
|
135
|
+
onGetStateSubscribe: function (state){
|
|
136
|
+
window.deunaWidgetState = state;
|
|
137
|
+
},
|
|
138
|
+
isValid: function(fn){
|
|
139
|
+
window.isValid = fn;
|
|
140
|
+
},
|
|
141
|
+
onSubmit: function (fn) {
|
|
142
|
+
window.submit = fn;
|
|
143
|
+
},
|
|
144
|
+
}
|
|
145
|
+
`
|
|
146
|
+
);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Gets the current widget state
|
|
151
|
+
* @returns The widget state
|
|
152
|
+
*/
|
|
153
|
+
getWidgetState = async (): Promise<State> => {
|
|
154
|
+
const result = await this.jsExecutor.execute(`
|
|
155
|
+
if(!window.deunaWidgetState){
|
|
156
|
+
sendResult({ deunaWidgetState: null });
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
sendResult({ deunaWidgetState: window.deunaWidgetState });
|
|
160
|
+
`);
|
|
161
|
+
return result?.deunaWidgetState;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Refetches the order
|
|
166
|
+
* @returns The order data | returns null if the order is not found or an error occurs
|
|
167
|
+
*/
|
|
168
|
+
refetchOrder = async (): Promise<Json | null> => {
|
|
169
|
+
const result = await this.jsExecutor.execute(`
|
|
170
|
+
if(typeof window.deunaRefetchOrder !== 'function'){
|
|
171
|
+
sendResult({order: null});
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
window.deunaRefetchOrder()
|
|
175
|
+
.then((order) => {
|
|
176
|
+
sendResult({order});
|
|
177
|
+
})
|
|
178
|
+
.catch(() => {
|
|
179
|
+
sendResult({data: null});
|
|
180
|
+
});
|
|
181
|
+
`);
|
|
182
|
+
return result?.order ?? null;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Sets the custom style for the widget
|
|
187
|
+
* @param style - The custom style to set
|
|
188
|
+
*/
|
|
189
|
+
setCustomStyle = async (style: Partial<CustomStyles>): Promise<void> => {
|
|
190
|
+
await this.jsExecutor.execute(`
|
|
191
|
+
window.setCustomStyle(${JSON.stringify(style)});
|
|
192
|
+
`);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Checks if the widget form data is valid
|
|
197
|
+
*/
|
|
198
|
+
isValid = async (): Promise<boolean> => {
|
|
199
|
+
const data = await this.jsExecutor.execute(`
|
|
200
|
+
if(typeof window.isValid !== 'function'){
|
|
201
|
+
console.log('❌ window.isValid is not a function');
|
|
202
|
+
sendResult({isValid:false});
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
sendResult( {isValid: window.isValid() });
|
|
206
|
+
`);
|
|
207
|
+
return data?.isValid ?? false;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Submits the form data to the server
|
|
212
|
+
* @returns The result of the submission
|
|
213
|
+
*/
|
|
214
|
+
submit = async (): Promise<SubmitResult> => {
|
|
215
|
+
const data = await this.jsExecutor.execute(`
|
|
216
|
+
if(typeof window.submit !== 'function'){
|
|
217
|
+
console.log('❌ window.submit is not a function');
|
|
218
|
+
sendResult({status:"${submitError.status}", code:"${submitError.code}", message:"${submitError.message}" });
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
window.submit()
|
|
222
|
+
.then((data) => {
|
|
223
|
+
sendResult(data);
|
|
224
|
+
})
|
|
225
|
+
.catch((error) => {
|
|
226
|
+
sendResult({status:"${submitError.status}", code:"${submitError.code}", message: error.message ?? "${submitError.message}" });
|
|
227
|
+
});
|
|
228
|
+
`);
|
|
229
|
+
return data as SubmitResult;
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
takeScreenshot = async (): Promise<string> => {
|
|
233
|
+
const data = await this.jsExecutor.execute(`
|
|
234
|
+
function takeScreenshot() {
|
|
235
|
+
html2canvas(document.body, { allowTaint: true, useCORS: true })
|
|
236
|
+
.then((canvas) => {
|
|
237
|
+
// Convert the canvas to a base64 image
|
|
238
|
+
var imgData = canvas.toDataURL("image/png");
|
|
239
|
+
sendResult({imgData: imgData});
|
|
240
|
+
})
|
|
241
|
+
.catch((error) => {
|
|
242
|
+
sendResult({imgData: null});
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// If html2canvas is not added
|
|
247
|
+
if (typeof html2canvas === "undefined") {
|
|
248
|
+
var script = document.createElement("script");
|
|
249
|
+
script.src = "https://html2canvas.hertzen.com/dist/html2canvas.min.js";
|
|
250
|
+
script.onload = function() {
|
|
251
|
+
takeScreenshot();
|
|
252
|
+
};
|
|
253
|
+
document.head.appendChild(script);
|
|
254
|
+
} else {
|
|
255
|
+
takeScreenshot();
|
|
256
|
+
}
|
|
257
|
+
`);
|
|
258
|
+
return data?.imgData ?? null;
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
class JsExecutor {
|
|
263
|
+
requestId = 0;
|
|
264
|
+
webView: WebView | null = null;
|
|
265
|
+
requests: Map<number, (data: Record<string, any> | null) => void> = new Map();
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Executes javascript code in the web view
|
|
269
|
+
* @param jsCode - The javascript code to execute
|
|
270
|
+
* @returns The result of the javascript code
|
|
271
|
+
*/
|
|
272
|
+
|
|
273
|
+
execute = (jsCode: string): Promise<Record<string, any> | null> => {
|
|
274
|
+
this.requestId++;
|
|
275
|
+
this.webView?.injectJavaScript(
|
|
276
|
+
`
|
|
277
|
+
(function() {
|
|
278
|
+
function sendResult(data){
|
|
279
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({ type: '${WebViewEventType.jsExecutor}', data: data, requestId: ${this.requestId} }));
|
|
280
|
+
}
|
|
281
|
+
${jsCode}
|
|
282
|
+
})();
|
|
283
|
+
`
|
|
284
|
+
);
|
|
285
|
+
return new Promise((resolve) => {
|
|
286
|
+
this.requests.set(this.requestId, resolve);
|
|
287
|
+
});
|
|
288
|
+
};
|
|
289
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { DeunaWebViewController } from './BaseWebViewController';
|
|
2
|
+
import {
|
|
3
|
+
ElementsEvent,
|
|
4
|
+
ElementsEventType,
|
|
5
|
+
} from '../interfaces/events/elements';
|
|
6
|
+
import { ElementsWidgetCallbacks } from '../types';
|
|
7
|
+
import { ElementsErrorType } from '../interfaces';
|
|
8
|
+
|
|
9
|
+
export class ElementsWidgetController extends DeunaWebViewController {
|
|
10
|
+
constructor(readonly callbacks: ElementsWidgetCallbacks) {
|
|
11
|
+
super();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
onError = (event: any) => {
|
|
15
|
+
this.callbacks.onError?.({
|
|
16
|
+
type: ElementsErrorType.errorWhileLoadingTheURL,
|
|
17
|
+
metadata: {
|
|
18
|
+
code: ElementsErrorType.errorWhileLoadingTheURL,
|
|
19
|
+
message: event.message ?? 'Error while loading the URL',
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
onEventDispatch = (event: Record<string, any>) => {
|
|
25
|
+
const elementsEvent = event as ElementsEvent;
|
|
26
|
+
|
|
27
|
+
if (this.callbacks.onEventDispatch) {
|
|
28
|
+
this.callbacks.onEventDispatch(elementsEvent.type, elementsEvent.data);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const mapper: Partial<Record<ElementsEventType, () => void>> = {
|
|
32
|
+
[ElementsEventType.vaultClosed]: () => {
|
|
33
|
+
this.closedAction = 'userAction';
|
|
34
|
+
this.delegate?.onCloseButtonPressed?.();
|
|
35
|
+
},
|
|
36
|
+
[ElementsEventType.vaultSaveSuccess]: () => {
|
|
37
|
+
this.delegate?.onCloseSubWebView?.();
|
|
38
|
+
this.callbacks.onSuccess?.(event.data);
|
|
39
|
+
},
|
|
40
|
+
[ElementsEventType.vaultSaveError]: () => {
|
|
41
|
+
this.delegate?.onCloseSubWebView?.();
|
|
42
|
+
this.delegate?.onCloseSubWebView?.();
|
|
43
|
+
const { metadata } = elementsEvent.data;
|
|
44
|
+
|
|
45
|
+
if (metadata) {
|
|
46
|
+
const errorCode =
|
|
47
|
+
metadata.code ??
|
|
48
|
+
metadata.errorCode ??
|
|
49
|
+
ElementsErrorType.unknownError;
|
|
50
|
+
|
|
51
|
+
const errorMessage =
|
|
52
|
+
metadata.message ??
|
|
53
|
+
metadata.errorMessage ??
|
|
54
|
+
metadata.reason ??
|
|
55
|
+
'unknown error';
|
|
56
|
+
|
|
57
|
+
this.callbacks.onError?.({
|
|
58
|
+
type: ElementsErrorType.vaultSaveError,
|
|
59
|
+
metadata: {
|
|
60
|
+
code: errorCode,
|
|
61
|
+
message: errorMessage,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
} else {
|
|
65
|
+
this.callbacks.onError?.({
|
|
66
|
+
type: ElementsErrorType.unknownError,
|
|
67
|
+
metadata: {
|
|
68
|
+
code: ElementsErrorType.unknownError,
|
|
69
|
+
message: 'unknown error',
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
mapper[elementsEvent.type]?.();
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import WebView, { WebViewMessageEvent } from 'react-native-webview';
|
|
2
|
+
import { BaseWebViewController } from './BaseWebViewController';
|
|
3
|
+
import { DeunaLogs } from '../DeunaLogs';
|
|
4
|
+
|
|
5
|
+
export class OpenInNewTabController extends BaseWebViewController {
|
|
6
|
+
constructor(readonly url: string) {
|
|
7
|
+
super();
|
|
8
|
+
this.url = url;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
setWebView = (webView: WebView) => {
|
|
12
|
+
this.webView = webView;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
onLoad = () => {
|
|
16
|
+
this.setXprops();
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
onError = (event: any) => {
|
|
20
|
+
console.warn(event);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
onMessage = (event: WebViewMessageEvent) => {
|
|
24
|
+
const eventData = JSON.parse(event.nativeEvent.data);
|
|
25
|
+
if (eventData.type === 'console_log') {
|
|
26
|
+
DeunaLogs.info(`CONSOLE LOG`, eventData.message);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
setXprops = () => {
|
|
31
|
+
this.webView?.injectJavaScript(
|
|
32
|
+
`
|
|
33
|
+
console.log = function(message) {
|
|
34
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({ type: 'console_log', message }));
|
|
35
|
+
};
|
|
36
|
+
`
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CheckoutEvent,
|
|
3
|
+
CheckoutEventType,
|
|
4
|
+
PaymentErrorType,
|
|
5
|
+
} from '../interfaces';
|
|
6
|
+
import { constants } from '../interfaces/constants';
|
|
7
|
+
import { DownloadType, OnDownloadFile } from '../interfaces/types';
|
|
8
|
+
import {
|
|
9
|
+
PaymentWidgetCallbacks,
|
|
10
|
+
NextActionWidgetCallbacks,
|
|
11
|
+
VoucherWidgetCallbacks,
|
|
12
|
+
} from '../types';
|
|
13
|
+
import { DeunaWebViewController } from './BaseWebViewController';
|
|
14
|
+
|
|
15
|
+
type Callbacks = PaymentWidgetCallbacks &
|
|
16
|
+
NextActionWidgetCallbacks &
|
|
17
|
+
VoucherWidgetCallbacks &
|
|
18
|
+
OnDownloadFile;
|
|
19
|
+
|
|
20
|
+
export class PaymentWidgetController extends DeunaWebViewController {
|
|
21
|
+
constructor(readonly callbacks: Callbacks) {
|
|
22
|
+
super();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
onError = (event: any) => {
|
|
26
|
+
this.callbacks.onError?.({
|
|
27
|
+
type: PaymentErrorType.errorWhileLoadingTheURL,
|
|
28
|
+
metadata: {
|
|
29
|
+
code: PaymentErrorType.errorWhileLoadingTheURL,
|
|
30
|
+
message: event.message ?? 'Error while loading the URL',
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
onEventDispatch = async (event: Record<string, any>) => {
|
|
36
|
+
const checkoutEvent = event as CheckoutEvent;
|
|
37
|
+
|
|
38
|
+
// This event is used to listen when a voucher save request is made
|
|
39
|
+
if (checkoutEvent.type === constants.apmSaveId) {
|
|
40
|
+
const { voucherPdfDownloadUrl }: { voucherPdfDownloadUrl?: string } =
|
|
41
|
+
checkoutEvent.data.metadata;
|
|
42
|
+
|
|
43
|
+
// If the file url is provided, download the file and save it to the device
|
|
44
|
+
if (voucherPdfDownloadUrl) {
|
|
45
|
+
this.callbacks.onDownloadFile?.({
|
|
46
|
+
type: DownloadType.URL,
|
|
47
|
+
data: voucherPdfDownloadUrl,
|
|
48
|
+
});
|
|
49
|
+
} else {
|
|
50
|
+
// Take a screenshot of current content in the webview
|
|
51
|
+
const base64Image = await this.takeScreenshot();
|
|
52
|
+
if (base64Image) {
|
|
53
|
+
this.callbacks.onDownloadFile?.({
|
|
54
|
+
type: DownloadType.BASE64,
|
|
55
|
+
data: base64Image,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (this.callbacks.onEventDispatch) {
|
|
63
|
+
this.callbacks.onEventDispatch(checkoutEvent.type, checkoutEvent.data);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const mapper: Partial<Record<CheckoutEventType, () => void>> = {
|
|
67
|
+
[CheckoutEventType.linkClose]: () => {
|
|
68
|
+
this.closedAction = 'userAction';
|
|
69
|
+
this.delegate?.onCloseButtonPressed?.();
|
|
70
|
+
},
|
|
71
|
+
[CheckoutEventType.onBinDetected]: () => {
|
|
72
|
+
this.callbacks.onCardBinDetected?.(checkoutEvent.data.metadata);
|
|
73
|
+
},
|
|
74
|
+
[CheckoutEventType.onInstallmentSelected]: () => {
|
|
75
|
+
this.callbacks.onInstallmentSelected?.(checkoutEvent.data.metadata);
|
|
76
|
+
},
|
|
77
|
+
[CheckoutEventType.paymentProcessing]: () => {
|
|
78
|
+
this.callbacks.onPaymentProcessing?.();
|
|
79
|
+
},
|
|
80
|
+
[CheckoutEventType.purchase]: () => {
|
|
81
|
+
this.delegate?.onCloseSubWebView?.();
|
|
82
|
+
this.callbacks.onSuccess?.(checkoutEvent.data.order);
|
|
83
|
+
},
|
|
84
|
+
[CheckoutEventType.purchaseError]: () => {
|
|
85
|
+
this.delegate?.onCloseSubWebView?.();
|
|
86
|
+
const { metadata } = checkoutEvent.data;
|
|
87
|
+
|
|
88
|
+
if (metadata) {
|
|
89
|
+
const errorCode =
|
|
90
|
+
metadata.code ??
|
|
91
|
+
metadata.errorCode ??
|
|
92
|
+
PaymentErrorType.unknownError;
|
|
93
|
+
|
|
94
|
+
const errorMessage =
|
|
95
|
+
metadata.message ??
|
|
96
|
+
metadata.errorMessage ??
|
|
97
|
+
metadata.reason ??
|
|
98
|
+
'unknown error';
|
|
99
|
+
|
|
100
|
+
this.callbacks.onError?.({
|
|
101
|
+
type: PaymentErrorType.paymentError,
|
|
102
|
+
metadata: { code: errorCode, message: errorMessage },
|
|
103
|
+
});
|
|
104
|
+
} else {
|
|
105
|
+
this.callbacks.onError?.({
|
|
106
|
+
type: PaymentErrorType.unknownError,
|
|
107
|
+
metadata: {
|
|
108
|
+
code: PaymentErrorType.unknownError,
|
|
109
|
+
message: 'unknown error',
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
mapper[checkoutEvent.type]?.();
|
|
117
|
+
};
|
|
118
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export class Completer<T> {
|
|
2
|
+
private promise: Promise<T>;
|
|
3
|
+
private resolvePromise: ((value: T | PromiseLike<T>) => void) | null = null;
|
|
4
|
+
private rejectPromise: ((reason?: any) => void) | null = null;
|
|
5
|
+
private completed = false;
|
|
6
|
+
|
|
7
|
+
constructor() {
|
|
8
|
+
this.promise = new Promise<T>((resolve, reject) => {
|
|
9
|
+
this.resolvePromise = resolve;
|
|
10
|
+
this.rejectPromise = reject;
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
get wait(): Promise<T> {
|
|
15
|
+
return this.promise;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
complete(value: T): void {
|
|
19
|
+
if (this.completed) return;
|
|
20
|
+
this.completed = true;
|
|
21
|
+
this.resolvePromise?.(value);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
completeError(error: any): void {
|
|
25
|
+
if (this.completed) return;
|
|
26
|
+
this.completed = true;
|
|
27
|
+
this.rejectPromise?.(error);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
isCompleted(): boolean {
|
|
31
|
+
return this.completed;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { DeunaWebViewController } from '../controllers/BaseWebViewController';
|
|
2
|
+
import { PaymentWidgetController } from '../controllers/PaymentWidgetController';
|
|
3
|
+
import { ElementsWidgetController } from '../controllers/ElementsWidgetController';
|
|
4
|
+
import {
|
|
5
|
+
InitElementsWidgetParams,
|
|
6
|
+
InitializeParams,
|
|
7
|
+
InitNextActionWidgetParams,
|
|
8
|
+
InitPaymentWidgetParams,
|
|
9
|
+
InitVoucherWidgetParams,
|
|
10
|
+
} from '../types';
|
|
11
|
+
import { linkBuilders } from '../types/helpers';
|
|
12
|
+
import { Mode } from '../interfaces/types';
|
|
13
|
+
import { DeunaLogs } from '../DeunaLogs';
|
|
14
|
+
|
|
15
|
+
type PaymentWidgetControllerProps = InitPaymentWidgetParams & {
|
|
16
|
+
widget: 'payment';
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
type NextActionWidgetControllerProps = InitNextActionWidgetParams & {
|
|
20
|
+
widget: 'nextAction';
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type VoucherWidgetControllerProps = InitVoucherWidgetParams & {
|
|
24
|
+
widget: 'voucher';
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
type ElementsWidgetControllerProps = InitElementsWidgetParams & {
|
|
28
|
+
widget: 'elements';
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type ControllerProps =
|
|
32
|
+
| PaymentWidgetControllerProps
|
|
33
|
+
| NextActionWidgetControllerProps
|
|
34
|
+
| VoucherWidgetControllerProps
|
|
35
|
+
| ElementsWidgetControllerProps;
|
|
36
|
+
|
|
37
|
+
export const getWidgetController = (
|
|
38
|
+
config: InitializeParams,
|
|
39
|
+
props: ControllerProps & { mode?: Mode; sessionId?: string }
|
|
40
|
+
): DeunaWebViewController => {
|
|
41
|
+
const { widget, mode, callbacks, ...rest } = props;
|
|
42
|
+
|
|
43
|
+
const baseParams = {
|
|
44
|
+
env: config.environment!,
|
|
45
|
+
publicApiKey: config.publicApiKey,
|
|
46
|
+
orderToken: rest.orderToken ?? '',
|
|
47
|
+
userToken: rest.userToken ?? '',
|
|
48
|
+
language: rest.language ?? 'es',
|
|
49
|
+
sessionId: rest.sessionId ?? '',
|
|
50
|
+
mode: mode ?? Mode.MODAL,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const widgetMappers = {
|
|
54
|
+
elements: () => ({
|
|
55
|
+
...baseParams,
|
|
56
|
+
userInfo: rest.userInfo,
|
|
57
|
+
styleFile: rest.styleFile,
|
|
58
|
+
behavior: rest.behavior,
|
|
59
|
+
widgetExperience: rest.widgetExperience,
|
|
60
|
+
types: (props as ElementsWidgetControllerProps).types,
|
|
61
|
+
}),
|
|
62
|
+
payment: () => ({
|
|
63
|
+
...baseParams,
|
|
64
|
+
behavior: rest.behavior,
|
|
65
|
+
paymentMethods: (props as PaymentWidgetControllerProps).paymentMethods,
|
|
66
|
+
styleFile: rest.styleFile,
|
|
67
|
+
}),
|
|
68
|
+
nextAction: () => baseParams,
|
|
69
|
+
voucher: () => baseParams,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const controller =
|
|
73
|
+
widget === 'elements'
|
|
74
|
+
? new ElementsWidgetController(callbacks)
|
|
75
|
+
: new PaymentWidgetController(callbacks);
|
|
76
|
+
|
|
77
|
+
controller.url = linkBuilders[widget](widgetMappers[widget]());
|
|
78
|
+
controller.hidePayButton = rest.hidePayButton ?? false;
|
|
79
|
+
|
|
80
|
+
DeunaLogs.info('👀 loading link', controller.url);
|
|
81
|
+
|
|
82
|
+
return controller;
|
|
83
|
+
};
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const initializationError = {
|
|
2
|
+
type: 'INITIALIZATION_ERROR',
|
|
3
|
+
code: 'INITIALIZATION_ERROR',
|
|
4
|
+
message: 'Failed to initialize the widget',
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const submitError = {
|
|
8
|
+
status: 'error',
|
|
9
|
+
code: 'error',
|
|
10
|
+
message: 'Error al procesar la solicitud.',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export enum PaymentErrorType {
|
|
14
|
+
noInternetConnection = 'noInternetConnection',
|
|
15
|
+
invalidOrderToken = 'invalidOrderToken',
|
|
16
|
+
initializationFailed = 'initializationFailed',
|
|
17
|
+
errorWhileLoadingTheURL = 'errorWhileLoadingTheURL',
|
|
18
|
+
orderNotFound = 'orderNotFound',
|
|
19
|
+
orderCouldNotBeRetrieved = 'orderCouldNotBeRetrieved',
|
|
20
|
+
paymentError = 'paymentError',
|
|
21
|
+
userError = 'userError',
|
|
22
|
+
unknownError = 'unknownError',
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export enum ElementsErrorType {
|
|
26
|
+
noInternetConnection = 'noInternetConnection',
|
|
27
|
+
initializationFailed = 'initializationFailed',
|
|
28
|
+
errorWhileLoadingTheURL = 'errorWhileLoadingTheURL',
|
|
29
|
+
userError = 'userError',
|
|
30
|
+
invalidUserToken = 'invalidUserToken',
|
|
31
|
+
unknownError = 'unknownError',
|
|
32
|
+
vaultSaveError = 'vaultSaveError',
|
|
33
|
+
vaultFailed = 'vaultFailed',
|
|
34
|
+
}
|