@jimrising/easymerchantsdk-react-native 1.2.8 → 1.3.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.
@@ -207,12 +207,28 @@ class UserStoreSingleton: NSObject {
207
207
  }
208
208
  }
209
209
 
210
- func updateThemeConfiguration(with json: [String: Any]) {
211
- json.forEach { key, value in
212
- UserDefaults.standard.set(value, forKey: key)
210
+ // func updateThemeConfiguration(with json: [String: Any]) {
211
+ // json.forEach { key, value in
212
+ // UserDefaults.standard.set(value, forKey: key)
213
+ // }
214
+ // }
215
+
216
+
217
+ func updateThemeConfiguration(with themeConfiguration: ThemeConfiguration) {
218
+ self.body_bg_col = themeConfiguration.bodyBackgroundColor
219
+ self.container_bg_col = themeConfiguration.containerBackgroundColor
220
+ self.primary_font_col = themeConfiguration.primaryFontColor
221
+ self.secondary_font_col = themeConfiguration.secondaryFontColor
222
+ self.primary_btn_bg_col = themeConfiguration.primaryButtonBackgroundColor
223
+ self.primary_btn_hover_col = themeConfiguration.primaryButtonHoverColor
224
+ self.primary_btn_font_col = themeConfiguration.primaryButtonFontColor
225
+ self.secondary_btn_bg_col = themeConfiguration.secondaryButtonBackgroundColor
226
+ self.secondary_btn_hover_col = themeConfiguration.secondaryButtonHoverColor
227
+ self.secondary_btn_font_col = themeConfiguration.secondaryFontColor
228
+ self.border_radious = themeConfiguration.borderRadius
229
+ self.fontSize = themeConfiguration.fontSize
213
230
  }
214
- }
215
-
231
+
216
232
  // Method to clear user data from UserDefaults
217
233
  func clearUserData() {
218
234
  UserDefaults.standard.removeObject(forKey: "customer_id")
@@ -0,0 +1,220 @@
1
+ //
2
+ // GrailPayVC.swift
3
+ // EasyPay
4
+ //
5
+ // Created by Mony's Mac on 02/05/25.
6
+ //
7
+
8
+ import UIKit
9
+ import WebKit
10
+
11
+ public class GrailPayVC: UIViewController {
12
+
13
+ private var webView: WKWebView!
14
+ private var loadingIndicator: UIActivityIndicatorView!
15
+ private var request: GrailPayRequest
16
+
17
+ public var onCompletion: ((Result) -> Void)?
18
+
19
+ public init(request: GrailPayRequest) {
20
+ self.request = request
21
+ super.init(nibName: nil, bundle: nil)
22
+ }
23
+
24
+ required init?(coder: NSCoder) {
25
+ fatalError("init(coder:) has not been implemented")
26
+ }
27
+
28
+ private var didHandleBankConnection = false
29
+
30
+ override public func viewDidLoad() {
31
+ super.viewDidLoad()
32
+ setupUI()
33
+ loadGrailPaySDK()
34
+ }
35
+
36
+ private func setupUI() {
37
+ view.backgroundColor = .white
38
+
39
+ let webConfig = WKWebViewConfiguration()
40
+ webConfig.userContentController.add(self, name: "grailpayHandler")
41
+ webConfig.allowsInlineMediaPlayback = true
42
+ webConfig.mediaTypesRequiringUserActionForPlayback = []
43
+
44
+ webView = WKWebView(frame: view.bounds, configuration: webConfig)
45
+ webView.navigationDelegate = self
46
+ webView.uiDelegate = self
47
+ webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
48
+ view.addSubview(webView)
49
+
50
+ loadingIndicator = UIActivityIndicatorView(style: .large)
51
+ loadingIndicator.center = view.center
52
+ loadingIndicator.hidesWhenStopped = true
53
+ view.addSubview(loadingIndicator)
54
+ }
55
+
56
+ private func loadGrailPaySDK() {
57
+ loadingIndicator.startAnimating()
58
+
59
+ WKWebsiteDataStore.default().removeData(ofTypes: [WKWebsiteDataTypeCookies], modifiedSince: Date(timeIntervalSince1970: 0)) { [weak self] in
60
+ guard let self = self else { return }
61
+
62
+ let sdkURL = self.request.isSandbox ?
63
+ "https://bank-link-widget-sandbox.grailpay.com/sdk.js" :
64
+ "https://bank-link-widget.grailpay.com/sdk.js"
65
+
66
+ let html = """
67
+ <!DOCTYPE html>
68
+ <html>
69
+ <head>
70
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
71
+ <script>
72
+ window.sdkInitialized = false;
73
+
74
+ function initializeSDK() {
75
+ if (window.sdkInitialized) return;
76
+
77
+ if (typeof window.grailpay === 'undefined') {
78
+ window.webkit.messageHandlers.grailpayHandler.postMessage({ type: 'error', data: 'SDK not loaded' });
79
+ return;
80
+ }
81
+
82
+ window.grailpay.init({
83
+ token: '\(self.request.accessToken)',
84
+ vendorId: '\(self.request.vendorId)',
85
+ role: '\(self.request.role)',
86
+ timeout: \(self.request.timeout),
87
+ theme: {
88
+ branding_name: '\(self.request.brandingName)',
89
+ screens: {
90
+ finder: {
91
+ subtitle: '\(self.request.finderSubtitle)',
92
+ searchPlaceholder: '\(self.request.searchPlaceholder)'
93
+ }
94
+ }
95
+ },
96
+ onError: function(error) {
97
+ console.log("JS onError:", error);
98
+ window.webkit.messageHandlers.grailpayHandler.postMessage({ type: 'error', data: error });
99
+ },
100
+ onBankConnected: function(data) {
101
+ console.log("✅ Bank connected:", data);
102
+ window.webkit.messageHandlers.grailpayHandler.postMessage({ type: 'bankConnected', data: data });
103
+ },
104
+ onLinkExit: function(data) {
105
+ console.log("⚠️ User exited:", data);
106
+ window.webkit.messageHandlers.grailpayHandler.postMessage({ type: 'linkExit', data: data });
107
+ }
108
+ }).then(function() {
109
+ window.sdkInitialized = true;
110
+ window.grailpay.open();
111
+ }).catch(function(error) {
112
+ console.log("❌ SDK init failed:", error);
113
+ window.webkit.messageHandlers.grailpayHandler.postMessage({ type: 'error', data: error });
114
+ });
115
+ }
116
+
117
+ function loadSDK() {
118
+ const script = document.createElement('script');
119
+ script.src = '\(sdkURL)';
120
+ script.onload = function() {
121
+ setTimeout(initializeSDK, 1000);
122
+ };
123
+ script.onerror = function(error) {
124
+ console.log("❌ Failed to load SDK script");
125
+ window.webkit.messageHandlers.grailpayHandler.postMessage({ type: 'error', data: 'Failed to load SDK script' });
126
+ };
127
+ document.head.appendChild(script);
128
+ }
129
+
130
+ document.addEventListener('DOMContentLoaded', loadSDK);
131
+ </script>
132
+ </head>
133
+ <body style="margin: 0; padding: 0;"></body>
134
+ </html>
135
+ """
136
+
137
+ let baseURL = URL(string: self.request.isSandbox ? "https://bank-link-widget-sandbox.grailpay.com" : "https://bank-link-widget.grailpay.com")
138
+ self.webView.loadHTMLString(html, baseURL: baseURL)
139
+ }
140
+ }
141
+
142
+ private func handleError(_ error: Error) {
143
+ DispatchQueue.main.async {
144
+ self.loadingIndicator.stopAnimating()
145
+ let nsError = error as NSError
146
+ self.onCompletion?(Result(error: nsError))
147
+ self.dismiss(animated: true)
148
+ }
149
+ }
150
+ }
151
+
152
+ extension GrailPayVC: WKNavigationDelegate {
153
+ public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
154
+ loadingIndicator.stopAnimating()
155
+ }
156
+
157
+ public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
158
+ handleError(error)
159
+ }
160
+ }
161
+
162
+ extension GrailPayVC: WKScriptMessageHandler {
163
+ public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
164
+ print("📩 JS Message received: \(message.body)")
165
+
166
+ guard let body = message.body as? [String: Any],
167
+ let type = body["type"] as? String else {
168
+ print("⚠️ Malformed message")
169
+ return
170
+ }
171
+
172
+ switch type {
173
+ case "bankConnected":
174
+ guard let dataArray = body["data"] as? [[String: Any]], let firstAccount = dataArray.first else {
175
+ print("⚠️ No valid accounts in bankConnected")
176
+ return
177
+ }
178
+
179
+ if !didHandleBankConnection {
180
+ didHandleBankConnection = true // ✅ Prevent duplicate triggers
181
+ print("✅ Received bankConnected: \(firstAccount)")
182
+
183
+ DispatchQueue.main.async {
184
+ self.onCompletion?(Result(type: .success, chargeData: ["data": dataArray]))
185
+ self.dismiss(animated: true)
186
+ }
187
+ }
188
+
189
+ case "linkExit":
190
+ if didHandleBankConnection {
191
+ print("ℹ️ linkExit ignored because success already handled")
192
+ return
193
+ }
194
+ print("⚠️ Received linkExit")
195
+ DispatchQueue.main.async {
196
+ self.onCompletion?(Result(type: .cancelled))
197
+ self.dismiss(animated: true)
198
+ }
199
+
200
+ case "error":
201
+ let errorMessage = (body["data"] as? String) ?? "Unknown error"
202
+ let error = NSError(domain: "GrailPayError", code: 0, userInfo: [NSLocalizedDescriptionKey: errorMessage])
203
+ print("❌ GrailPay JS error: \(errorMessage)")
204
+ handleError(error)
205
+
206
+ default:
207
+ print("ℹ️ Unknown JS message type: \(type)")
208
+ }
209
+ }
210
+ }
211
+
212
+
213
+ extension GrailPayVC: WKUIDelegate {
214
+ public func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
215
+ if navigationAction.targetFrame == nil {
216
+ webView.load(navigationAction.request)
217
+ }
218
+ return nil
219
+ }
220
+ }