skipcash-reactnative 0.0.2
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 +334 -0
- package/android/build.gradle +183 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/AndroidManifestNew.xml +2 -0
- package/android/src/main/java/com/skipcashreactnative/ModalActivity.java +128 -0
- package/android/src/main/java/com/skipcashreactnative/SkipcashReactnativeModule.java +361 -0
- package/android/src/main/java/com/skipcashreactnative/SkipcashReactnativePackage.kt +18 -0
- package/android/src/main/res/layout/activity_modal.xml +59 -0
- package/ios/Resource/main.storyboard +45 -0
- package/ios/SkipcashReactnative-Bridging-Header.h +2 -0
- package/ios/SkipcashReactnative.mm +18 -0
- package/ios/SkipcashReactnative.swift +994 -0
- package/lib/commonjs/index.js +367 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/module/index.js +355 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/commonjs/package.json +1 -0
- package/lib/typescript/commonjs/src/index.d.ts +142 -0
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
- package/lib/typescript/module/package.json +1 -0
- package/lib/typescript/module/src/index.d.ts +142 -0
- package/lib/typescript/module/src/index.d.ts.map +1 -0
- package/package.json +187 -0
- package/skipcash-reactnative.podspec +43 -0
- package/src/index.tsx +445 -0
|
@@ -0,0 +1,994 @@
|
|
|
1
|
+
// SetupVC.swift
|
|
2
|
+
// SkipCashSDK
|
|
3
|
+
//
|
|
4
|
+
// By Ahmed Mustafa on 3/04/24.
|
|
5
|
+
|
|
6
|
+
import React
|
|
7
|
+
import Foundation
|
|
8
|
+
import UIKit
|
|
9
|
+
import CryptoKit
|
|
10
|
+
import CommonCrypto
|
|
11
|
+
import PassKit
|
|
12
|
+
import WebKit
|
|
13
|
+
|
|
14
|
+
public struct ResultObject: Codable {
|
|
15
|
+
public var isSuccess: Bool
|
|
16
|
+
var data: String
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public class ResponseData: NSObject, Codable {
|
|
20
|
+
public var transactionId: String?
|
|
21
|
+
public var paymentId: String?
|
|
22
|
+
public var resultObj: ResultObject
|
|
23
|
+
public var returnCode: Int
|
|
24
|
+
public var errorCode: Int
|
|
25
|
+
public var errorMessage: String?
|
|
26
|
+
public var error: String?
|
|
27
|
+
public var validationErrors: String?
|
|
28
|
+
public var hasError: Bool
|
|
29
|
+
public var hasValidationError: Bool
|
|
30
|
+
|
|
31
|
+
// Initializer
|
|
32
|
+
public init(transactionId: String?, paymentId: String?, resultObj: ResultObject, returnCode: Int, errorCode: Int, errorMessage: String?, error: String?, validationErrors: String?, hasError: Bool, hasValidationError: Bool) {
|
|
33
|
+
self.transactionId = transactionId
|
|
34
|
+
self.paymentId = paymentId
|
|
35
|
+
self.resultObj = resultObj
|
|
36
|
+
self.returnCode = returnCode
|
|
37
|
+
self.errorCode = errorCode
|
|
38
|
+
self.errorMessage = errorMessage
|
|
39
|
+
self.error = error
|
|
40
|
+
self.validationErrors = validationErrors
|
|
41
|
+
self.hasError = hasError
|
|
42
|
+
self.hasValidationError = hasValidationError
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
public func getResultObjIsSuccess() -> Bool {
|
|
47
|
+
return resultObj.isSuccess;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public func getPaymentId() -> String {
|
|
51
|
+
return paymentId ?? "No Payment ID";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public func getTransactionId() -> String {
|
|
55
|
+
return transactionId ?? "No Transaction ID";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public func getErrorMessage() -> String {
|
|
59
|
+
return errorMessage ?? "Nothing to show";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@objc public protocol ApplePayReponseDelegate{
|
|
64
|
+
func applePayResponseData(transactionID: String, paymentID: String, isSuccess: Bool, token: String, returnCode: Int, errorMessage: String, completion: ((PKPaymentAuthorizationResult) -> Void)?)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public class SetupVC: UIViewController {
|
|
68
|
+
let production = "https://api.skipcash.app"
|
|
69
|
+
let sandboxUrl = "https://skipcashtest.azurewebsites.net"
|
|
70
|
+
|
|
71
|
+
public var paymentToken: String = ""
|
|
72
|
+
public var paymentID: String = ""
|
|
73
|
+
public var transactionID: String = ""
|
|
74
|
+
public var delegate:ApplePayReponseDelegate?
|
|
75
|
+
public var completion: ((PKPaymentAuthorizationResult) -> Void)?
|
|
76
|
+
|
|
77
|
+
override public func viewDidLoad() {
|
|
78
|
+
self.callApplePay(paymentId: self.paymentID, applePaymentToken: self.paymentToken)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
func callApplePay(paymentId: String, applePaymentToken: String) {
|
|
82
|
+
|
|
83
|
+
let request = "{\"token\": {\"paymentData\":\(applePaymentToken)}}"
|
|
84
|
+
let postData = request.data(using: .utf8)
|
|
85
|
+
let url = URL(string: production + "/api/v1/payments/apple/" + paymentId + "/pay-mc")!
|
|
86
|
+
var urlRequest = URLRequest(url: url)
|
|
87
|
+
urlRequest.httpMethod = "POST"
|
|
88
|
+
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
89
|
+
urlRequest.httpBody = postData
|
|
90
|
+
|
|
91
|
+
let task: URLSessionDataTask
|
|
92
|
+
|
|
93
|
+
task = URLSession.shared.dataTask(with: urlRequest) { data, response, error in
|
|
94
|
+
|
|
95
|
+
guard let data = data else {
|
|
96
|
+
debugPrint(data ?? "NO DATA RECEIVED")
|
|
97
|
+
let responseData = ResponseData(
|
|
98
|
+
transactionId: self.transactionID,
|
|
99
|
+
paymentId: self.paymentID,
|
|
100
|
+
resultObj: ResultObject(isSuccess: false, data: "\(applePaymentToken)"),
|
|
101
|
+
returnCode: 400,
|
|
102
|
+
errorCode: 1001,
|
|
103
|
+
errorMessage: "Sample error message",
|
|
104
|
+
error: "No data received",
|
|
105
|
+
validationErrors: "Sample validation errors",
|
|
106
|
+
hasError: true,
|
|
107
|
+
hasValidationError: true
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
DispatchQueue.main.async{
|
|
111
|
+
self.dismiss(animated: true, completion: nil)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
DispatchQueue.main.asyncAfter(deadline: .now()){
|
|
115
|
+
self.delegate?.applePayResponseData(transactionID: self.transactionID, paymentID: self.paymentID, isSuccess: responseData.resultObj.isSuccess, token: responseData.resultObj.data, returnCode: responseData.returnCode, errorMessage: responseData.getErrorMessage(), completion: self.completion)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if let text = String(data: data, encoding: .utf8) {
|
|
122
|
+
if let jsonData = text.data(using: .utf8) {
|
|
123
|
+
do {
|
|
124
|
+
let decoder = JSONDecoder()
|
|
125
|
+
var responseData = try decoder.decode(ResponseData.self, from: jsonData)
|
|
126
|
+
|
|
127
|
+
responseData.paymentId = paymentId
|
|
128
|
+
|
|
129
|
+
DispatchQueue.main.async{
|
|
130
|
+
self.dismiss(animated: true, completion: nil)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
DispatchQueue.main.asyncAfter(deadline: .now()){
|
|
134
|
+
self.delegate?.applePayResponseData(transactionID: self.transactionID, paymentID: self.paymentID, isSuccess: responseData.resultObj.isSuccess, token: responseData.resultObj.data, returnCode: responseData.returnCode, errorMessage: responseData.getErrorMessage(), completion: self.completion)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
} catch {
|
|
138
|
+
let responseData = ResponseData(
|
|
139
|
+
transactionId: self.transactionID,
|
|
140
|
+
paymentId: self.paymentID,
|
|
141
|
+
resultObj: ResultObject(isSuccess: false, data: "\(applePaymentToken)"),
|
|
142
|
+
returnCode: 400,
|
|
143
|
+
errorCode: 1001,
|
|
144
|
+
errorMessage: "Payment Failed!",
|
|
145
|
+
error: "\(error)",
|
|
146
|
+
validationErrors: "failed to decode json response for the payment",
|
|
147
|
+
hasError: true,
|
|
148
|
+
hasValidationError: true
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
DispatchQueue.main.async{
|
|
153
|
+
self.dismiss(animated: true, completion: nil)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
DispatchQueue.main.asyncAfter(deadline: .now()){
|
|
157
|
+
|
|
158
|
+
self.delegate?.applePayResponseData(transactionID: self.transactionID, paymentID: self.paymentID, isSuccess: responseData.resultObj.isSuccess, token: responseData.resultObj.data, returnCode: responseData.returnCode, errorMessage: responseData.getErrorMessage(), completion: self.completion)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
let responseData = ResponseData(
|
|
166
|
+
transactionId: self.transactionID,
|
|
167
|
+
paymentId: self.paymentID,
|
|
168
|
+
resultObj: ResultObject(isSuccess: false, data: "\(applePaymentToken)"),
|
|
169
|
+
returnCode: 400,
|
|
170
|
+
errorCode: 1001,
|
|
171
|
+
errorMessage: "Sample error message",
|
|
172
|
+
error: "Failed to convert JSON text to data",
|
|
173
|
+
validationErrors: "Sample validation errors",
|
|
174
|
+
hasError: true,
|
|
175
|
+
hasValidationError: true
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
DispatchQueue.main.async{
|
|
179
|
+
self.dismiss(animated: true, completion: nil)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
DispatchQueue.main.asyncAfter(deadline: .now()){
|
|
183
|
+
self.delegate?.applePayResponseData(transactionID: self.transactionID, paymentID: self.paymentID, isSuccess: responseData.resultObj.isSuccess, token: responseData.resultObj.data, returnCode: responseData.returnCode, errorMessage: responseData.getErrorMessage(), completion: self.completion)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
let responseData = ResponseData(
|
|
189
|
+
transactionId: self.transactionID,
|
|
190
|
+
paymentId: self.paymentID,
|
|
191
|
+
resultObj: ResultObject(isSuccess: false, data: "\(applePaymentToken)"),
|
|
192
|
+
returnCode: 400,
|
|
193
|
+
errorCode: 1001,
|
|
194
|
+
errorMessage: "Sample error message",
|
|
195
|
+
error: "Failed to decode data as UTF-8 string",
|
|
196
|
+
validationErrors: "Sample validation errors",
|
|
197
|
+
hasError: true,
|
|
198
|
+
hasValidationError: true
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
DispatchQueue.main.async{
|
|
202
|
+
self.dismiss(animated: true, completion: nil)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
DispatchQueue.main.asyncAfter(deadline: .now()){
|
|
206
|
+
self.delegate?.applePayResponseData(transactionID: self.transactionID, paymentID: self.paymentID, isSuccess: responseData.resultObj.isSuccess, token: responseData.resultObj.data, returnCode: responseData.returnCode, errorMessage: responseData.getErrorMessage(), completion: self.completion)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
task.resume()
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
public class PaymentData: NSObject, Codable{
|
|
215
|
+
let merchantIdentifier: String
|
|
216
|
+
let countryCode: String
|
|
217
|
+
let currencyCode: String
|
|
218
|
+
let createPaymentLinkEndPoint: String
|
|
219
|
+
let authorizationHeader: String
|
|
220
|
+
let amount: String
|
|
221
|
+
let firstName: String
|
|
222
|
+
let lastName: String
|
|
223
|
+
let phone: String
|
|
224
|
+
let email: String
|
|
225
|
+
let summaryItems: [String: String]
|
|
226
|
+
|
|
227
|
+
let returnUrl: String
|
|
228
|
+
let transactionId: String
|
|
229
|
+
let webhookUrl: String
|
|
230
|
+
|
|
231
|
+
let custom1: String
|
|
232
|
+
let custom2: String
|
|
233
|
+
let custom3: String
|
|
234
|
+
let custom4: String
|
|
235
|
+
let custom5: String
|
|
236
|
+
let custom6: String
|
|
237
|
+
let custom7: String
|
|
238
|
+
let custom8: String
|
|
239
|
+
let custom9: String
|
|
240
|
+
let custom10: String
|
|
241
|
+
|
|
242
|
+
let Description: String
|
|
243
|
+
let Subject: String
|
|
244
|
+
let paymentModalTitle: String
|
|
245
|
+
|
|
246
|
+
let merchantName: String
|
|
247
|
+
|
|
248
|
+
init?(data: [String: Any]) {
|
|
249
|
+
guard
|
|
250
|
+
let merchantIdentifier = data["merchantIdentifier"] as? String,
|
|
251
|
+
let countryCode = data["countryCode"] as? String,
|
|
252
|
+
let currencyCode = data["currencyCode"] as? String,
|
|
253
|
+
let createPaymentLinkEndPoint = data["createPaymentLinkEndPoint"] as? String,
|
|
254
|
+
let authorizationHeader = data["authorizationHeader"] as? String,
|
|
255
|
+
let amount = data["amount"] as? String,
|
|
256
|
+
let firstName = data["firstName"] as? String,
|
|
257
|
+
let lastName = data["lastName"] as? String,
|
|
258
|
+
let phone = data["phone"] as? String,
|
|
259
|
+
let email = data["email"] as? String,
|
|
260
|
+
let summaryItems = data["summaryItems"] as? [String: String],
|
|
261
|
+
|
|
262
|
+
let returnURL = data["returnUrl"] as? String, //
|
|
263
|
+
let transactionId = data["transactionId"] as? String,
|
|
264
|
+
let webhookUrl = data["webhookUrl"] as? String,
|
|
265
|
+
let returnUrl = data["returnUrl"] as? String,
|
|
266
|
+
let custom1 = data["custom1"] as? String, let custom2 = data["custom2"] as? String,
|
|
267
|
+
let custom3 = data["custom3"] as? String, let custom4 = data["custom4"] as? String,
|
|
268
|
+
let custom5 = data["custom5"] as? String, let custom6 = data["custom6"] as? String,
|
|
269
|
+
let custom7 = data["custom7"] as? String, let custom8 = data["custom8"] as? String,
|
|
270
|
+
let custom9 = data["custom9"] as? String, let custom10 = data["custom10"] as? String,
|
|
271
|
+
let Description = data["description"] as? String,
|
|
272
|
+
let Subject = data["subject"] as? String,
|
|
273
|
+
let paymentModalTitle = data["paymentModalTitle"] as? String,
|
|
274
|
+
|
|
275
|
+
let merchantName = data["merchantName"] as? String
|
|
276
|
+
else {
|
|
277
|
+
return nil
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
self.merchantIdentifier = merchantIdentifier
|
|
281
|
+
self.countryCode = countryCode
|
|
282
|
+
self.currencyCode = currencyCode
|
|
283
|
+
self.createPaymentLinkEndPoint = createPaymentLinkEndPoint
|
|
284
|
+
self.authorizationHeader = authorizationHeader
|
|
285
|
+
self.amount = amount
|
|
286
|
+
self.firstName = firstName
|
|
287
|
+
self.lastName = lastName
|
|
288
|
+
self.phone = phone
|
|
289
|
+
self.email = email
|
|
290
|
+
self.summaryItems = summaryItems
|
|
291
|
+
|
|
292
|
+
self.returnUrl = returnUrl
|
|
293
|
+
self.transactionId = transactionId
|
|
294
|
+
self.webhookUrl = webhookUrl
|
|
295
|
+
self.custom1 = custom1
|
|
296
|
+
self.custom2 = custom2
|
|
297
|
+
self.custom3 = custom3
|
|
298
|
+
self.custom4 = custom4
|
|
299
|
+
self.custom5 = custom5
|
|
300
|
+
self.custom6 = custom6
|
|
301
|
+
self.custom7 = custom7
|
|
302
|
+
self.custom8 = custom8
|
|
303
|
+
self.custom9 = custom9
|
|
304
|
+
self.custom10 = custom10
|
|
305
|
+
|
|
306
|
+
self.Subject = Subject
|
|
307
|
+
self.Description = Description
|
|
308
|
+
self.paymentModalTitle = paymentModalTitle
|
|
309
|
+
|
|
310
|
+
self.merchantName = merchantName
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
@objc(SkipcashReactnative)
|
|
315
|
+
class SkipcashReactnative: RCTEventEmitter, ApplePayReponseDelegate {
|
|
316
|
+
private var paymentID: String = ""
|
|
317
|
+
private var transactionID: String = ""
|
|
318
|
+
|
|
319
|
+
var webView: WKWebView!
|
|
320
|
+
var navigationController: UINavigationController?
|
|
321
|
+
var activityIndicator: UIActivityIndicatorView!
|
|
322
|
+
var returnURL: String?
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
override func supportedEvents() -> [String]! {
|
|
326
|
+
return ["applepay_response", "responseScPaymentData"]
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
public func applePayResponseData(transactionID: String, paymentID: String, isSuccess: Bool, token: String, returnCode: Int, errorMessage: String, completion: ((PKPaymentAuthorizationResult) -> Void)?) {
|
|
331
|
+
let responseData: [String: Any] = [
|
|
332
|
+
"transactionId": transactionID,
|
|
333
|
+
"paymentId": paymentID,
|
|
334
|
+
"isSuccess": isSuccess,
|
|
335
|
+
"token": token,
|
|
336
|
+
"returnCode": returnCode,
|
|
337
|
+
"errorMessage": errorMessage
|
|
338
|
+
]
|
|
339
|
+
|
|
340
|
+
if (isSuccess) {
|
|
341
|
+
let errors = [Error]()
|
|
342
|
+
let status = PKPaymentAuthorizationStatus.success
|
|
343
|
+
self.paymentStatus = status
|
|
344
|
+
completion?(PKPaymentAuthorizationResult(status: status, errors: errors))
|
|
345
|
+
}else{
|
|
346
|
+
let errors = [Error]()
|
|
347
|
+
let status = PKPaymentAuthorizationStatus.failure
|
|
348
|
+
self.paymentStatus = status
|
|
349
|
+
completion?(PKPaymentAuthorizationResult(status: status, errors: errors))
|
|
350
|
+
}
|
|
351
|
+
sendEvent(withName: "applepay_response", body: responseData)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
@IBOutlet weak var applePayView: UIView!
|
|
355
|
+
var paymentController: PKPaymentAuthorizationController?
|
|
356
|
+
var paymentSummaryItems = [PKPaymentSummaryItem]()
|
|
357
|
+
var paymentStatus = PKPaymentAuthorizationStatus.failure
|
|
358
|
+
typealias PaymentCompletionHandler = (Bool) -> Void
|
|
359
|
+
var completionHandler: PaymentCompletionHandler!
|
|
360
|
+
|
|
361
|
+
static let supportedNetworks: [PKPaymentNetwork] = [
|
|
362
|
+
.amex,
|
|
363
|
+
.discover,
|
|
364
|
+
.masterCard,
|
|
365
|
+
.visa
|
|
366
|
+
]
|
|
367
|
+
|
|
368
|
+
@objc(isWalletHasCards:rejecter:)
|
|
369
|
+
func isWalletHasCards (resolve:RCTPromiseResolveBlock,rejecter:RCTPromiseRejectBlock) -> Void {
|
|
370
|
+
let result = SkipcashReactnative.applePayStatus();
|
|
371
|
+
|
|
372
|
+
resolve(result.canMakePayments);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
@objc(setupNewCard)
|
|
376
|
+
func setupNewCard() {
|
|
377
|
+
let passLibrary = PKPassLibrary()
|
|
378
|
+
passLibrary.openPaymentSetup()
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
class func applePayStatus() -> (canMakePayments: Bool, canSetupCards: Bool) {
|
|
382
|
+
return (PKPaymentAuthorizationController.canMakePayments(),
|
|
383
|
+
PKPaymentAuthorizationController.canMakePayments(usingNetworks: supportedNetworks))
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
func convertToDecimal(with string: String) -> NSDecimalNumber {
|
|
387
|
+
let formatter = NumberFormatter()
|
|
388
|
+
formatter.decimalSeparator = "."
|
|
389
|
+
formatter.generatesDecimalNumbers = true
|
|
390
|
+
formatter.maximumFractionDigits = 2
|
|
391
|
+
|
|
392
|
+
if let number = formatter.number(from: string) as? NSDecimalNumber {
|
|
393
|
+
return number
|
|
394
|
+
} else {
|
|
395
|
+
return NSDecimalNumber.zero
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
func getPaymentID(authorizationHeader: String, data: PaymentData, createPaymentApi: String, returnURL: String, completion: @escaping ([String: Any]?) -> Void) {
|
|
400
|
+
|
|
401
|
+
var convertedData: [String: Any] = [:]
|
|
402
|
+
|
|
403
|
+
convertedData["Amount"] = data.amount
|
|
404
|
+
convertedData["FirstName"] = data.firstName
|
|
405
|
+
convertedData["LastName"] = data.lastName
|
|
406
|
+
convertedData["Phone"] = data.phone
|
|
407
|
+
convertedData["Email"] = data.email
|
|
408
|
+
|
|
409
|
+
convertedData["ReturnUrl"] = returnURL
|
|
410
|
+
convertedData["TransactionId"] = data.transactionId
|
|
411
|
+
convertedData["WebhookUrl"] = data.webhookUrl
|
|
412
|
+
|
|
413
|
+
convertedData["Custom1"] = data.custom1
|
|
414
|
+
convertedData["Custom2"] = data.custom2
|
|
415
|
+
convertedData["Custom3"] = data.custom3
|
|
416
|
+
convertedData["Custom4"] = data.custom4
|
|
417
|
+
convertedData["Custom5"] = data.custom5
|
|
418
|
+
convertedData["Custom6"] = data.custom6
|
|
419
|
+
convertedData["Custom7"] = data.custom7
|
|
420
|
+
convertedData["Custom8"] = data.custom8
|
|
421
|
+
convertedData["Custom9"] = data.custom9
|
|
422
|
+
convertedData["Custom10"] = data.custom10
|
|
423
|
+
|
|
424
|
+
convertedData["Description"] = data.Description
|
|
425
|
+
convertedData["Subject"] = data.Subject
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
guard let jsonData = try? JSONSerialization.data(withJSONObject: convertedData) else {
|
|
429
|
+
completion(nil)
|
|
430
|
+
return
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
var request = URLRequest(url: URL(string: createPaymentApi)!, timeoutInterval: 30)
|
|
434
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
435
|
+
|
|
436
|
+
if authorizationHeader.count > 0 {
|
|
437
|
+
request.addValue(authorizationHeader, forHTTPHeaderField: "Authorization")
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
request.httpMethod = "POST"
|
|
441
|
+
request.httpBody = jsonData
|
|
442
|
+
|
|
443
|
+
let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
|
444
|
+
guard let data = data else {
|
|
445
|
+
if let error = error {
|
|
446
|
+
debugPrint("Error: \(error.localizedDescription)")
|
|
447
|
+
let responseData: [String: Any] = [
|
|
448
|
+
"transactionId": self.transactionID,
|
|
449
|
+
"paymentId": self.paymentID,
|
|
450
|
+
"isSuccess": false,
|
|
451
|
+
"token": "",
|
|
452
|
+
"returnCode": 400,
|
|
453
|
+
"errorMessage": "\(error.localizedDescription)"
|
|
454
|
+
]
|
|
455
|
+
|
|
456
|
+
DispatchQueue.main.async {
|
|
457
|
+
self.sendEvent(withName: "applepay_response", body: responseData)
|
|
458
|
+
completion(nil)
|
|
459
|
+
}
|
|
460
|
+
return
|
|
461
|
+
}
|
|
462
|
+
return
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
do {
|
|
466
|
+
let json = try JSONSerialization.jsonObject(with: data, options: [])
|
|
467
|
+
if let tempResponse = json as? [String: Any],
|
|
468
|
+
let responseObj = tempResponse["resultObj"] as? [String: Any],
|
|
469
|
+
let paymentID = responseObj["id"] as? String, let payUrl = responseObj["payUrl"] as? String, let transactionId = responseObj["transactionId"] as? String{
|
|
470
|
+
DispatchQueue.main.async {
|
|
471
|
+
completion(["paymentID": paymentID, "payUrl": payUrl, "transactionId": transactionId])
|
|
472
|
+
}
|
|
473
|
+
return
|
|
474
|
+
}else{
|
|
475
|
+
if let tempResponse = json as? [String: Any],
|
|
476
|
+
let errorMessage = tempResponse["errorMessage"] as? String {
|
|
477
|
+
|
|
478
|
+
let responseData: [String: Any] = [
|
|
479
|
+
"transactionId": self.transactionID,
|
|
480
|
+
"paymentId": self.paymentID,
|
|
481
|
+
"isSuccess": false,
|
|
482
|
+
"token": "",
|
|
483
|
+
"returnCode": 400,
|
|
484
|
+
"errorMessage": errorMessage
|
|
485
|
+
]
|
|
486
|
+
|
|
487
|
+
DispatchQueue.main.async {
|
|
488
|
+
self.sendEvent(withName: "applepay_response", body: responseData)
|
|
489
|
+
completion(nil)
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
} catch {
|
|
494
|
+
debugPrint("Error: \(error.localizedDescription) - endpoint response")
|
|
495
|
+
let responseData: [String: Any] = [
|
|
496
|
+
"transactionId": self.transactionID,
|
|
497
|
+
"paymentId": self.paymentID,
|
|
498
|
+
"isSuccess": false,
|
|
499
|
+
"token": "",
|
|
500
|
+
"returnCode": 400,
|
|
501
|
+
"errorMessage": "\(error.localizedDescription)"
|
|
502
|
+
]
|
|
503
|
+
|
|
504
|
+
self.sendEvent(withName: "applepay_response", body: responseData)
|
|
505
|
+
completion(nil)
|
|
506
|
+
return
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
task.resume()
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
@objc(initiateApplePay:)
|
|
514
|
+
func initiateApplePay(jsonString: String){
|
|
515
|
+
if let jsonData = jsonString.data(using: .utf8) {
|
|
516
|
+
do {
|
|
517
|
+
// Convert JSON data to a dictionary
|
|
518
|
+
if let paymentDictionary = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
|
|
519
|
+
if let paymentData = PaymentData(data: paymentDictionary) {
|
|
520
|
+
getPaymentID(authorizationHeader: paymentData.authorizationHeader, data: paymentData, createPaymentApi: paymentData.createPaymentLinkEndPoint, returnURL: paymentData.returnUrl) { result in
|
|
521
|
+
if let result = result {
|
|
522
|
+
let paymentID = result["paymentID"] as? String ?? ""
|
|
523
|
+
|
|
524
|
+
if(paymentID.count == 0){
|
|
525
|
+
debugPrint("new payment request failed!")
|
|
526
|
+
return
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
self.startPayment(data: paymentData, paymentID: paymentID) { success in
|
|
530
|
+
if success {} else {
|
|
531
|
+
let responseData: [String: Any] = [
|
|
532
|
+
"transactionId": self.transactionID,
|
|
533
|
+
"paymentId": self.paymentID,
|
|
534
|
+
"isSuccess": false,
|
|
535
|
+
"token": "",
|
|
536
|
+
"returnCode": 400,
|
|
537
|
+
"errorMessage": "Payment failed!"
|
|
538
|
+
]
|
|
539
|
+
|
|
540
|
+
self.sendEvent(withName: "applepay_response", body: responseData)
|
|
541
|
+
return
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
} else {
|
|
547
|
+
debugPrint("Unable to convert jsonData(cross-platform passed data) to paymentDictionary")
|
|
548
|
+
let responseData: [String: Any] = [
|
|
549
|
+
"transactionId": self.transactionID,
|
|
550
|
+
"paymentId": self.paymentID,
|
|
551
|
+
"isSuccess": false,
|
|
552
|
+
"token": "",
|
|
553
|
+
"returnCode": 400,
|
|
554
|
+
"errorMessage": ""
|
|
555
|
+
]
|
|
556
|
+
|
|
557
|
+
self.sendEvent(withName: "applepay_response", body: responseData)
|
|
558
|
+
return
|
|
559
|
+
}
|
|
560
|
+
} else {
|
|
561
|
+
debugPrint("Error: Unable to convert JSON string to data")
|
|
562
|
+
let responseData: [String: Any] = [
|
|
563
|
+
"transactionId": self.transactionID,
|
|
564
|
+
"paymentId": self.paymentID,
|
|
565
|
+
"isSuccess": false,
|
|
566
|
+
"token": "",
|
|
567
|
+
"returnCode": 400,
|
|
568
|
+
"errorMessage": ""
|
|
569
|
+
]
|
|
570
|
+
self.sendEvent(withName: "applepay_response", body: responseData)
|
|
571
|
+
return
|
|
572
|
+
}
|
|
573
|
+
} catch {
|
|
574
|
+
debugPrint("Error: \(error)")
|
|
575
|
+
let responseData: [String: Any] = [
|
|
576
|
+
"transactionId": self.transactionID,
|
|
577
|
+
"paymentId": self.paymentID,
|
|
578
|
+
"isSuccess": false,
|
|
579
|
+
"token": "",
|
|
580
|
+
"returnCode": 400,
|
|
581
|
+
"errorMessage": "Error: \(error)"
|
|
582
|
+
]
|
|
583
|
+
|
|
584
|
+
self.sendEvent(withName: "applepay_response", body: responseData)
|
|
585
|
+
return
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// else {
|
|
590
|
+
// debugPrint("Error: Unable to convert JSON string to data")
|
|
591
|
+
// let responseData: [String: Any] = [
|
|
592
|
+
// "transactionId": self.transactionID,
|
|
593
|
+
// "paymentId": self.paymentID,
|
|
594
|
+
// "isSuccess": false,
|
|
595
|
+
// "token": "",
|
|
596
|
+
// "returnCode": 400,
|
|
597
|
+
// "errorMessage": "Unable to convert JSON string to data"
|
|
598
|
+
// ]
|
|
599
|
+
|
|
600
|
+
// self.sendEvent(withName: "applepay_response", body: responseData)
|
|
601
|
+
// }
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
func startPayment(data: PaymentData, paymentID: String, completion: @escaping PaymentCompletionHandler) {
|
|
605
|
+
|
|
606
|
+
completionHandler = completion
|
|
607
|
+
self.paymentID = paymentID
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
var paymentSummaryItems = [PKPaymentSummaryItem]()
|
|
611
|
+
|
|
612
|
+
for (label, amountString) in data.summaryItems {
|
|
613
|
+
guard let amount = Decimal(string: amountString) else {
|
|
614
|
+
// Handle invalid amount string
|
|
615
|
+
debugPrint("Invalid amount string: \(amountString)")
|
|
616
|
+
continue
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// Successfully converted, create a PKPaymentSummaryItem and append it
|
|
620
|
+
let paymentItem = PKPaymentSummaryItem(label: label, amount: NSDecimalNumber(decimal: amount))
|
|
621
|
+
paymentSummaryItems.append(paymentItem)
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
let totalAmount = convertToDecimal(with: data.amount)
|
|
626
|
+
|
|
627
|
+
let totalAmountItem = PKPaymentSummaryItem(label: data.merchantName, amount: totalAmount)
|
|
628
|
+
paymentSummaryItems.append(totalAmountItem)
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
let paymentRequest = PKPaymentRequest()
|
|
632
|
+
|
|
633
|
+
paymentRequest.paymentSummaryItems = paymentSummaryItems
|
|
634
|
+
paymentRequest.merchantIdentifier = data.merchantIdentifier
|
|
635
|
+
paymentRequest.merchantCapabilities = .threeDSecure
|
|
636
|
+
paymentRequest.countryCode = data.countryCode
|
|
637
|
+
paymentRequest.currencyCode = data.currencyCode
|
|
638
|
+
paymentRequest.supportedNetworks = SkipcashReactnative.supportedNetworks
|
|
639
|
+
|
|
640
|
+
let paymentController = PKPaymentAuthorizationController(paymentRequest: paymentRequest)
|
|
641
|
+
|
|
642
|
+
paymentController.delegate = self
|
|
643
|
+
|
|
644
|
+
paymentController.present(completion: { (presented: Bool) in
|
|
645
|
+
if presented {
|
|
646
|
+
debugPrint("Presented payment controller")
|
|
647
|
+
} else {
|
|
648
|
+
debugPrint("Failed to present payment controller")
|
|
649
|
+
self.completionHandler(false)
|
|
650
|
+
}
|
|
651
|
+
})
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
@objc(initiatePaymentModel:)
|
|
655
|
+
func initiatePaymentModel(jsonString: String){
|
|
656
|
+
if let jsonData = jsonString.data(using: .utf8) {
|
|
657
|
+
do {
|
|
658
|
+
if let paymentDictionary = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
|
|
659
|
+
if let paymentData = PaymentData(data: paymentDictionary) {
|
|
660
|
+
self.getPaymentID(authorizationHeader: paymentData.authorizationHeader, data: paymentData, createPaymentApi: paymentData.createPaymentLinkEndPoint, returnURL: paymentData.returnUrl) { result in
|
|
661
|
+
if let result = result {
|
|
662
|
+
let paymentID = result["paymentID"] as? String ?? ""
|
|
663
|
+
let payUrl = result["payUrl"] as? String ?? ""
|
|
664
|
+
let transactionID = result["transactionId"] as? String ?? ""
|
|
665
|
+
|
|
666
|
+
if(paymentID.count == 0){
|
|
667
|
+
debugPrint("new payment request failed!")
|
|
668
|
+
return
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
self.showPaymentModal(url: payUrl, paymentTitle: paymentData.paymentModalTitle, returnURL: paymentData.returnUrl, paymentId: paymentID, transactionId: transactionID)
|
|
672
|
+
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
} else {
|
|
676
|
+
debugPrint("Unable to convert jsonData(cross-platform passed data) to paymentDictionary")
|
|
677
|
+
let responseData: [String: Any] = [
|
|
678
|
+
"transactionId": self.transactionID,
|
|
679
|
+
"paymentId": self.paymentID,
|
|
680
|
+
"isSuccess": false,
|
|
681
|
+
"token": "",
|
|
682
|
+
"returnCode": 400,
|
|
683
|
+
"errorMessage": ""
|
|
684
|
+
]
|
|
685
|
+
|
|
686
|
+
self.sendEvent(withName: "responseScPaymentData", body: responseData)
|
|
687
|
+
return
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
} else {
|
|
691
|
+
debugPrint("Error: Unable to convert JSON string to data")
|
|
692
|
+
let responseData: [String: Any] = [
|
|
693
|
+
"transactionId": self.transactionID,
|
|
694
|
+
"paymentId": self.paymentID,
|
|
695
|
+
"isSuccess": false,
|
|
696
|
+
"token": "",
|
|
697
|
+
"returnCode": 400,
|
|
698
|
+
"errorMessage": ""
|
|
699
|
+
]
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
self.sendEvent(withName: "responseScPaymentData", body: responseData)
|
|
703
|
+
return
|
|
704
|
+
}
|
|
705
|
+
} catch {
|
|
706
|
+
debugPrint("Error: \(error)")
|
|
707
|
+
let responseData: [String: Any] = [
|
|
708
|
+
"transactionId": self.transactionID,
|
|
709
|
+
"paymentId": self.paymentID,
|
|
710
|
+
"isSuccess": false,
|
|
711
|
+
"token": "",
|
|
712
|
+
"returnCode": 400,
|
|
713
|
+
"errorMessage": "\(error.localizedDescription)"
|
|
714
|
+
]
|
|
715
|
+
|
|
716
|
+
self.sendEvent(withName: "responseScPaymentData", body: responseData)
|
|
717
|
+
return
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
|
|
724
|
+
extension SkipcashReactnative: PKPaymentAuthorizationControllerDelegate {
|
|
725
|
+
|
|
726
|
+
public func paymentAuthorizationController(_ controller: PKPaymentAuthorizationController, didAuthorizePayment payment: PKPayment, handler completion: @escaping (PKPaymentAuthorizationResult) -> Void) {
|
|
727
|
+
|
|
728
|
+
let errors = [Error]()
|
|
729
|
+
let status = PKPaymentAuthorizationStatus.success
|
|
730
|
+
|
|
731
|
+
var token = ""
|
|
732
|
+
|
|
733
|
+
do {
|
|
734
|
+
if let jsonResponse = try JSONSerialization.jsonObject(with: payment.token.paymentData, options: []) as? [String: Any] {
|
|
735
|
+
token = String(decoding: payment.token.paymentData, as: UTF8.self)
|
|
736
|
+
} else {
|
|
737
|
+
debugPrint("Failed to get applepay token")
|
|
738
|
+
|
|
739
|
+
let errors = [Error]()
|
|
740
|
+
let status = PKPaymentAuthorizationStatus.failure
|
|
741
|
+
|
|
742
|
+
self.paymentStatus = status
|
|
743
|
+
completion(PKPaymentAuthorizationResult(status: status, errors: errors))
|
|
744
|
+
return
|
|
745
|
+
}
|
|
746
|
+
} catch {
|
|
747
|
+
debugPrint("error converting payment token")
|
|
748
|
+
|
|
749
|
+
let errors = [Error]()
|
|
750
|
+
let status = PKPaymentAuthorizationStatus.failure
|
|
751
|
+
|
|
752
|
+
self.paymentStatus = status
|
|
753
|
+
completion(PKPaymentAuthorizationResult(status: status, errors: errors))
|
|
754
|
+
return
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
//
|
|
758
|
+
let vc = SetupVC()
|
|
759
|
+
|
|
760
|
+
vc.modalPresentationStyle = .overCurrentContext
|
|
761
|
+
vc.delegate = self
|
|
762
|
+
vc.transactionID = self.transactionID
|
|
763
|
+
vc.paymentID = self.paymentID
|
|
764
|
+
vc.completion = completion
|
|
765
|
+
vc.paymentToken = token
|
|
766
|
+
|
|
767
|
+
if let topViewController = UIApplication.shared.keyWindow?.rootViewController?.topMostViewController() {
|
|
768
|
+
topViewController.modalPresentationStyle = .overCurrentContext
|
|
769
|
+
topViewController.present(vc, animated: true, completion: nil)
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
public func paymentAuthorizationControllerDidFinish(_ controller: PKPaymentAuthorizationController) {
|
|
774
|
+
controller.dismiss {
|
|
775
|
+
DispatchQueue.main.async {
|
|
776
|
+
if self.paymentStatus == .success {
|
|
777
|
+
self.completionHandler!(true)
|
|
778
|
+
} else {
|
|
779
|
+
self.completionHandler!(false)
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
|
|
787
|
+
extension SkipcashReactnative: WKNavigationDelegate {
|
|
788
|
+
|
|
789
|
+
@objc func showPaymentModal(url: String, paymentTitle: String, returnURL: String, paymentId: String, transactionId: String){
|
|
790
|
+
DispatchQueue.main.async {
|
|
791
|
+
self.returnURL = returnURL
|
|
792
|
+
self.transactionID = transactionId
|
|
793
|
+
self.paymentID = paymentId
|
|
794
|
+
let webViewController = UIViewController()
|
|
795
|
+
let webConfiguration = WKWebViewConfiguration()
|
|
796
|
+
|
|
797
|
+
if let topViewController = UIApplication.shared.keyWindow?.rootViewController?.topMostViewController() {
|
|
798
|
+
|
|
799
|
+
self.webView = WKWebView(frame: webViewController.view.bounds, configuration: webConfiguration)
|
|
800
|
+
self.webView.navigationDelegate = self
|
|
801
|
+
|
|
802
|
+
self.clearWebViewCache()
|
|
803
|
+
|
|
804
|
+
self.setupActivityIndicator()
|
|
805
|
+
|
|
806
|
+
if let myURL = URL(string: url) {
|
|
807
|
+
let myRequest = URLRequest(url: myURL)
|
|
808
|
+
self.webView.load(myRequest)
|
|
809
|
+
} else {
|
|
810
|
+
debugPrint("Invalid URL: \(url)")
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
|
|
815
|
+
webViewController.view.addSubview(self.webView)
|
|
816
|
+
self.webView.frame = webViewController.view.bounds
|
|
817
|
+
self.webView.scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 50,right:0)
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
webViewController.title = paymentTitle
|
|
821
|
+
|
|
822
|
+
let backButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action:#selector(self.goBackBtn))
|
|
823
|
+
|
|
824
|
+
webViewController.navigationItem.setLeftBarButton(backButton, animated: true)
|
|
825
|
+
|
|
826
|
+
if let navigationController = topViewController.navigationController {
|
|
827
|
+
navigationController.modalPresentationStyle = .pageSheet
|
|
828
|
+
navigationController.isModalInPresentation = true
|
|
829
|
+
navigationController.pushViewController(webViewController, animated: true)
|
|
830
|
+
} else {
|
|
831
|
+
let navigationController = UINavigationController(rootViewController: webViewController)
|
|
832
|
+
navigationController.modalPresentationStyle = .pageSheet
|
|
833
|
+
navigationController.isModalInPresentation = true
|
|
834
|
+
topViewController.present(navigationController, animated: true, completion: nil)
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
} else {
|
|
838
|
+
debugPrint("Unable to find top view controller")
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
private func configureWebView() {
|
|
844
|
+
// Inject viewport meta tag for scaling and zooming
|
|
845
|
+
let viewportMetaTag = """
|
|
846
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
|
847
|
+
"""
|
|
848
|
+
let injectViewportJS = "document.head.insertAdjacentHTML('beforeend', '\(viewportMetaTag)');"
|
|
849
|
+
webView.evaluateJavaScript(injectViewportJS, completionHandler: nil)
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
private func clearWebViewCache() {
|
|
853
|
+
let dataStore = webView.configuration.websiteDataStore
|
|
854
|
+
dataStore.httpCookieStore.getAllCookies { cookies in
|
|
855
|
+
cookies.forEach { cookie in
|
|
856
|
+
dataStore.httpCookieStore.delete(cookie)
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
dataStore.fetchDataRecords(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes()) { records in
|
|
861
|
+
for record in records {
|
|
862
|
+
dataStore.removeData(ofTypes: record.dataTypes, for: [record]) {
|
|
863
|
+
debugPrint("Cleared data for \(record)")
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
private func setupActivityIndicator() {
|
|
870
|
+
self.activityIndicator = UIActivityIndicatorView(style: .large)
|
|
871
|
+
self.activityIndicator.translatesAutoresizingMaskIntoConstraints = false
|
|
872
|
+
self.activityIndicator.hidesWhenStopped = true
|
|
873
|
+
self.webView.addSubview(self.activityIndicator)
|
|
874
|
+
|
|
875
|
+
NSLayoutConstraint.activate([
|
|
876
|
+
self.activityIndicator.centerXAnchor.constraint(equalTo: self.webView.centerXAnchor),
|
|
877
|
+
self.activityIndicator.centerYAnchor.constraint(equalTo: self.webView.centerYAnchor)
|
|
878
|
+
])
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
|
|
882
|
+
self.activityIndicator.startAnimating()
|
|
883
|
+
self.configureWebView()
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
|
887
|
+
DispatchQueue.main.async {
|
|
888
|
+
self.activityIndicator.stopAnimating()
|
|
889
|
+
// scroll to web view bottom to show the payment buttons clearly
|
|
890
|
+
let bottomOffset = CGPoint(x: 0, y: webView.scrollView.contentSize.height - webView.scrollView.bounds.height)
|
|
891
|
+
if bottomOffset.y > 0 {
|
|
892
|
+
webView.scrollView.setContentOffset(bottomOffset, animated: true)
|
|
893
|
+
}
|
|
894
|
+
self.configureWebView()
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
public func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
|
|
899
|
+
self.configureWebView()
|
|
900
|
+
if let currentURL = webView.url {
|
|
901
|
+
if currentURL.absoluteString.range(of: self.returnURL!, options: .caseInsensitive) != nil {
|
|
902
|
+
if let queryItems = URLComponents(url: currentURL, resolvingAgainstBaseURL: false)?.queryItems {
|
|
903
|
+
|
|
904
|
+
var queryParameters = [String: String]()
|
|
905
|
+
for item in queryItems {
|
|
906
|
+
queryParameters[item.name] = item.value
|
|
907
|
+
}
|
|
908
|
+
goBack(data: queryParameters)
|
|
909
|
+
return
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
var queryParameters = [String: String]()
|
|
913
|
+
|
|
914
|
+
queryParameters["id"] = self.paymentID
|
|
915
|
+
queryParameters["statusId"] = "4"
|
|
916
|
+
queryParameters["status"] = "Failed"
|
|
917
|
+
queryParameters["transId"] = self.transactionID
|
|
918
|
+
queryParameters["custom1"] = ""
|
|
919
|
+
|
|
920
|
+
goBack(data: queryParameters)
|
|
921
|
+
return
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
|
|
927
|
+
@objc func goBackBtn(){ // cancel the payment by user
|
|
928
|
+
DispatchQueue.main.async {
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
if let topViewController = UIApplication.shared.keyWindow?.rootViewController?.topMostViewController() {
|
|
932
|
+
|
|
933
|
+
var data = [String: String]()
|
|
934
|
+
|
|
935
|
+
data["id"] = self.paymentID
|
|
936
|
+
data["statusId"] = "4"
|
|
937
|
+
data["status"] = "Failed"
|
|
938
|
+
data["transId"] = self.transactionID
|
|
939
|
+
data["custom1"] = ""
|
|
940
|
+
|
|
941
|
+
if let navigationController = topViewController.navigationController {
|
|
942
|
+
} else {
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
self.navigationController?.popViewController(animated: true)
|
|
946
|
+
topViewController.dismiss(animated: true) {
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
self.sendEvent(withName: "responseScPaymentData", body: data)
|
|
950
|
+
|
|
951
|
+
|
|
952
|
+
} else {
|
|
953
|
+
debugPrint("Unable to find top view controller")
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
@objc func goBack(data: [String: String]) {
|
|
959
|
+
DispatchQueue.main.async {
|
|
960
|
+
if let topViewController = UIApplication.shared.keyWindow?.rootViewController?.topMostViewController() {
|
|
961
|
+
if let navigationController = topViewController.navigationController {
|
|
962
|
+
} else {
|
|
963
|
+
}
|
|
964
|
+
self.navigationController?.popViewController(animated: true)
|
|
965
|
+
topViewController.dismiss(animated: true) {
|
|
966
|
+
|
|
967
|
+
}
|
|
968
|
+
self.sendEvent(withName: "responseScPaymentData", body: data)
|
|
969
|
+
} else {
|
|
970
|
+
debugPrint("Unable to find top view controller")
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
extension UIViewController {
|
|
978
|
+
func topMostViewController() -> UIViewController {
|
|
979
|
+
if let presentedViewController = presentedViewController {
|
|
980
|
+
presentedViewController.modalPresentationStyle = .overCurrentContext
|
|
981
|
+
return presentedViewController.topMostViewController()
|
|
982
|
+
}
|
|
983
|
+
if let navigationController = self as? UINavigationController {
|
|
984
|
+
navigationController.modalPresentationStyle = .overCurrentContext
|
|
985
|
+
return navigationController.visibleViewController?.topMostViewController() ?? navigationController
|
|
986
|
+
}
|
|
987
|
+
if let tabBarController = self as? UITabBarController {
|
|
988
|
+
tabBarController.modalPresentationStyle = .overCurrentContext
|
|
989
|
+
return tabBarController.selectedViewController?.topMostViewController() ?? tabBarController
|
|
990
|
+
}
|
|
991
|
+
self.modalPresentationStyle = .overCurrentContext
|
|
992
|
+
return self
|
|
993
|
+
}
|
|
994
|
+
}
|