@jimrising/easymerchantsdk-react-native 1.2.0 → 1.2.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/.idea/caches/deviceStreaming.xml +209 -0
- package/.idea/workspace.xml +193 -0
- package/README.md +1 -1
- package/ios/Classes/EasyMerchantSdk.m +4 -4
- package/ios/Pods/UserDefaults/UserStoreSingleton.swift +233 -0
- package/ios/Pods/ViewControllers/AdditionalInfoVC.swift +1137 -0
- package/ios/Pods/ViewControllers/BaseVC.swift +126 -0
- package/ios/Pods/ViewControllers/BillingInfoVC/BillingInfoVC.swift +803 -0
- package/ios/Pods/ViewControllers/BillingInfoVC/Cells/CityListTVC.swift +46 -0
- package/ios/Pods/ViewControllers/BillingInfoVC/Cells/CountryListTVC.swift +47 -0
- package/ios/Pods/ViewControllers/BillingInfoVC/Cells/StateListTVC.swift +46 -0
- package/ios/Pods/ViewControllers/CountryListVC.swift +404 -0
- package/ios/Pods/ViewControllers/EmailVerificationVC.swift +239 -0
- package/ios/Pods/ViewControllers/OTPVerificationVC.swift +1134 -0
- package/ios/Pods/ViewControllers/PaymentDoneVC.swift +159 -0
- package/ios/Pods/ViewControllers/PaymentErrorVC.swift +90 -0
- package/ios/Pods/ViewControllers/PaymentInformation/AccountTypeTVC.swift +41 -0
- package/ios/Pods/ViewControllers/PaymentInformation/PaymentInfoVC.swift +5160 -0
- package/ios/Pods/ViewControllers/PaymentInformation/PaymentInformationCVC.swift +35 -0
- package/ios/Pods/ViewControllers/PaymentInformation/SavedAccountsTVC/SavedAccountTVC.swift +77 -0
- package/ios/Pods/ViewControllers/PaymentInformation/SavedAccountsTVC/SavedAccountTVC.xib +163 -0
- package/ios/Pods/ViewControllers/PaymentInformation/SavedCardsTVC/SavedCardsTVC.swift +76 -0
- package/ios/Pods/ViewControllers/PaymentInformation/SavedCardsTVC/SavedCardsTVC.xib +184 -0
- package/ios/Pods/ViewControllers/TermAndConditionsVC.swift +63 -0
- package/ios/easymerchantsdk.podspec +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,803 @@
|
|
|
1
|
+
//
|
|
2
|
+
// BillingInfoVC.swift
|
|
3
|
+
// EasyPay
|
|
4
|
+
//
|
|
5
|
+
// Created by Mony's Mac on 12/08/24.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import UIKit
|
|
9
|
+
|
|
10
|
+
// @available(iOS 16.0, *)
|
|
11
|
+
|
|
12
|
+
protocol BillingInfoVCDelegate: AnyObject {
|
|
13
|
+
func didPassTextBack(_ text: String)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class BillingInfoVC: BaseVC {
|
|
17
|
+
|
|
18
|
+
@IBOutlet weak var viewBillingInfo: UIView!
|
|
19
|
+
@IBOutlet weak var btnPrevious: UIButton!
|
|
20
|
+
@IBOutlet weak var viewCountryList: UIView!
|
|
21
|
+
@IBOutlet weak var tblViewCountryList: UITableView!
|
|
22
|
+
@IBOutlet weak var txtFieldAddress: UITextField!
|
|
23
|
+
@IBOutlet weak var txtFieldCountry: UITextField!
|
|
24
|
+
@IBOutlet weak var viewStateList: UIView!
|
|
25
|
+
@IBOutlet weak var tblViewStateList: UITableView!
|
|
26
|
+
@IBOutlet weak var txtFieldState: UITextField!
|
|
27
|
+
@IBOutlet weak var viewCityList: UIView!
|
|
28
|
+
@IBOutlet weak var tblViewCityList: UITableView!
|
|
29
|
+
@IBOutlet weak var txtFieldCity: UITextField!
|
|
30
|
+
@IBOutlet weak var txtFieldPostalCode: UITextField!
|
|
31
|
+
|
|
32
|
+
@IBOutlet weak var buttonBottomConstraint: NSLayoutConstraint!
|
|
33
|
+
|
|
34
|
+
@IBOutlet weak var lblBillingInfo: UILabel!
|
|
35
|
+
@IBOutlet weak var lblEasyMerchant: UILabel!
|
|
36
|
+
@IBOutlet weak var btnNext: UIButton!
|
|
37
|
+
|
|
38
|
+
// Variable to store the auth token
|
|
39
|
+
var authToken: String?
|
|
40
|
+
|
|
41
|
+
var countryList: [[String: Any]] = []
|
|
42
|
+
var stateList: [[String: Any]] = []
|
|
43
|
+
var cityList: [[String: Any]] = []
|
|
44
|
+
|
|
45
|
+
var billingInfoData: [String: Any]?
|
|
46
|
+
|
|
47
|
+
var cardNumber: String?
|
|
48
|
+
var expiryDate: String?
|
|
49
|
+
var cvv: String?
|
|
50
|
+
var nameOnCard: String?
|
|
51
|
+
|
|
52
|
+
//Banking Params
|
|
53
|
+
var accountName: String?
|
|
54
|
+
var routingNumber: String?
|
|
55
|
+
var accountType: String?
|
|
56
|
+
var accountNumber: String?
|
|
57
|
+
|
|
58
|
+
var selectedPaymentMethod: String?
|
|
59
|
+
|
|
60
|
+
private let keyboardObserver = KeyboardObserver()
|
|
61
|
+
|
|
62
|
+
var isSavedForFuture: Bool = false
|
|
63
|
+
var isSavedNewCard: Bool = false
|
|
64
|
+
|
|
65
|
+
private var request: Request!
|
|
66
|
+
var selectedCard: CardModel?
|
|
67
|
+
var amount: Int?
|
|
68
|
+
var cvvText: String?
|
|
69
|
+
|
|
70
|
+
var isFrom = String()
|
|
71
|
+
|
|
72
|
+
//From Regular Saved Bank Accounts
|
|
73
|
+
var customerID: String?
|
|
74
|
+
var accountID: String?
|
|
75
|
+
|
|
76
|
+
var isSavedNewAccount: Bool?
|
|
77
|
+
|
|
78
|
+
weak var delegate: BillingInfoVCDelegate?
|
|
79
|
+
|
|
80
|
+
override func viewDidLoad() {
|
|
81
|
+
super.viewDidLoad()
|
|
82
|
+
|
|
83
|
+
uiFinishingTouchElements()
|
|
84
|
+
|
|
85
|
+
setupShadowForListViews()
|
|
86
|
+
|
|
87
|
+
tblViewCountryList.delegate = self
|
|
88
|
+
tblViewCountryList.dataSource = self
|
|
89
|
+
viewCountryList.isHidden = true
|
|
90
|
+
|
|
91
|
+
tblViewStateList.delegate = self
|
|
92
|
+
tblViewStateList.dataSource = self
|
|
93
|
+
viewStateList.isHidden = true
|
|
94
|
+
|
|
95
|
+
tblViewCityList.delegate = self
|
|
96
|
+
tblViewCityList.dataSource = self
|
|
97
|
+
viewCityList.isHidden = true
|
|
98
|
+
|
|
99
|
+
txtFieldCity.delegate = self
|
|
100
|
+
txtFieldState.delegate = self
|
|
101
|
+
txtFieldAddress.delegate = self
|
|
102
|
+
txtFieldCountry.delegate = self
|
|
103
|
+
txtFieldPostalCode.delegate = self
|
|
104
|
+
|
|
105
|
+
getCountryListApi()
|
|
106
|
+
|
|
107
|
+
// Add tap gesture to hide the views and dismiss the keyboard
|
|
108
|
+
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapOutside))
|
|
109
|
+
tapGesture.cancelsTouchesInView = false
|
|
110
|
+
self.view.addGestureRecognizer(tapGesture)
|
|
111
|
+
|
|
112
|
+
// Print data for verification
|
|
113
|
+
if let billingInfoData = billingInfoData {
|
|
114
|
+
print("Billing Info Data: \(billingInfoData)")
|
|
115
|
+
|
|
116
|
+
if let address = billingInfoData["address"] as? String {
|
|
117
|
+
txtFieldAddress.text = address
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if let country = billingInfoData["country"] as? String {
|
|
121
|
+
txtFieldCountry.text = country
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if let state = billingInfoData["state"] as? String {
|
|
125
|
+
txtFieldState.text = state
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if let city = billingInfoData["city"] as? String {
|
|
129
|
+
txtFieldCity.text = city
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if let postalCode = billingInfoData["postal_code"] as? String {
|
|
133
|
+
txtFieldPostalCode.text = postalCode
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
override func viewWillAppear(_ animated: Bool) {
|
|
140
|
+
super.viewWillAppear(animated)
|
|
141
|
+
|
|
142
|
+
uiFinishingTouchElements()
|
|
143
|
+
|
|
144
|
+
keyboardObserver.animateChanges({ [self] height in
|
|
145
|
+
let newConstant = CGFloat.maximum(height - self.view.safeAreaInsets.bottom + 8, 8)
|
|
146
|
+
buttonBottomConstraint.constant = newConstant
|
|
147
|
+
self.view.setNeedsLayout()
|
|
148
|
+
self.view.layoutIfNeeded()
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
override func viewWillDisappear(_ animated: Bool) {
|
|
153
|
+
super.viewWillDisappear(animated)
|
|
154
|
+
keyboardObserver.invalidate()
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
func uiFinishingTouchElements() {
|
|
158
|
+
// Set background color for the main view
|
|
159
|
+
if let containerBGcolor = UserStoreSingleton.shared.container_bg_col,
|
|
160
|
+
let uiColor = UIColor(hex: containerBGcolor) {
|
|
161
|
+
self.view.backgroundColor = uiColor
|
|
162
|
+
viewCountryList.backgroundColor = uiColor
|
|
163
|
+
viewStateList.backgroundColor = uiColor
|
|
164
|
+
viewCityList.backgroundColor = uiColor
|
|
165
|
+
tblViewCountryList.backgroundColor = uiColor
|
|
166
|
+
tblViewStateList.backgroundColor = uiColor
|
|
167
|
+
tblViewCityList.backgroundColor = uiColor
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if let primaryBtnBackGroundColor = UserStoreSingleton.shared.primary_btn_bg_col,
|
|
171
|
+
let uiColor = UIColor(hex: primaryBtnBackGroundColor) {
|
|
172
|
+
btnNext.backgroundColor = uiColor
|
|
173
|
+
btnPrevious.setTitleColor(uiColor, for: .normal)
|
|
174
|
+
btnPrevious.layer.borderColor = uiColor.cgColor
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if let primaryBtnFontColor = UserStoreSingleton.shared.primary_btn_font_col,
|
|
178
|
+
let secondaryUIColor = UIColor(hex: primaryBtnFontColor) {
|
|
179
|
+
btnNext.setTitleColor(secondaryUIColor, for: .normal)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if let secondaryFontColor = UserStoreSingleton.shared.secondary_font_col,
|
|
183
|
+
let placeholderColor = UIColor(hex: secondaryFontColor) {
|
|
184
|
+
lblEasyMerchant.textColor = placeholderColor
|
|
185
|
+
viewBillingInfo.layer.borderColor = placeholderColor.cgColor
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
viewBillingInfo.layer.borderColor = UIColor.systemGray.cgColor
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if let borderRadiusString = UserStoreSingleton.shared.border_radious,
|
|
192
|
+
let borderRadius = Double(borderRadiusString) { // Convert String to Double
|
|
193
|
+
btnNext.layer.cornerRadius = CGFloat(borderRadius) // Set corner radius
|
|
194
|
+
btnPrevious.layer.cornerRadius = CGFloat(borderRadius)
|
|
195
|
+
btnPrevious.layer.borderWidth = 1
|
|
196
|
+
viewBillingInfo.layer.cornerRadius = CGFloat(borderRadius)
|
|
197
|
+
viewBillingInfo.layer.borderWidth = 1
|
|
198
|
+
} else {
|
|
199
|
+
btnNext.layer.cornerRadius = 8 // Default value
|
|
200
|
+
btnPrevious.layer.cornerRadius = 8
|
|
201
|
+
viewBillingInfo.layer.borderWidth = 1
|
|
202
|
+
viewBillingInfo.layer.cornerRadius = 8
|
|
203
|
+
}
|
|
204
|
+
btnNext.layer.masksToBounds = true // Ensure the corners are clipped properly
|
|
205
|
+
btnPrevious.layer.masksToBounds = true
|
|
206
|
+
viewBillingInfo.layer.masksToBounds = true
|
|
207
|
+
|
|
208
|
+
if let primaryFontColor = UserStoreSingleton.shared.primary_font_col,
|
|
209
|
+
let uiColor = UIColor(hex: primaryFontColor) {
|
|
210
|
+
lblBillingInfo.textColor = uiColor
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if let fontSizeString = UserStoreSingleton.shared.fontSize,
|
|
214
|
+
let fontSizeDouble = Double(fontSizeString) { // Convert String to Double
|
|
215
|
+
let fontSize = CGFloat(fontSizeDouble) // Convert Double to CGFloat
|
|
216
|
+
lblEasyMerchant.font = UIFont.systemFont(ofSize: fontSize)
|
|
217
|
+
btnNext.titleLabel?.font = UIFont.systemFont(ofSize: fontSize)
|
|
218
|
+
btnPrevious.titleLabel?.font = UIFont.systemFont(ofSize: fontSize)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
@objc func didTapOutside() {
|
|
224
|
+
// Dismiss the keyboard
|
|
225
|
+
self.view.endEditing(true)
|
|
226
|
+
|
|
227
|
+
// Hide the country list view if it is visible
|
|
228
|
+
if !viewCountryList.isHidden {
|
|
229
|
+
viewCountryList.isHidden = true
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Hide the state list view if it is visible
|
|
233
|
+
if !viewStateList.isHidden {
|
|
234
|
+
viewStateList.isHidden = true
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Hide the city list view if it is visible
|
|
238
|
+
if !viewCityList.isHidden {
|
|
239
|
+
viewCityList.isHidden = true
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
func setupShadowForListViews() {
|
|
244
|
+
// Ensure the view does not clip its content or shadows
|
|
245
|
+
viewCountryList.clipsToBounds = false
|
|
246
|
+
// Apply shadow properties
|
|
247
|
+
viewCountryList.layer.shadowColor = UIColor.black.cgColor
|
|
248
|
+
viewCountryList.layer.shadowOpacity = 0.3
|
|
249
|
+
viewCountryList.layer.shadowOffset = CGSize(width: 0, height: 2)
|
|
250
|
+
viewCountryList.layer.shadowRadius = 4
|
|
251
|
+
// Optionally, you might want to set a corner radius to the view as well
|
|
252
|
+
viewCountryList.layer.cornerRadius = 8
|
|
253
|
+
tblViewCountryList.layer.cornerRadius = 8
|
|
254
|
+
|
|
255
|
+
// Ensure the view does not clip its content or shadows
|
|
256
|
+
viewStateList.clipsToBounds = false
|
|
257
|
+
// Apply shadow properties
|
|
258
|
+
viewStateList.layer.shadowColor = UIColor.black.cgColor
|
|
259
|
+
viewStateList.layer.shadowOpacity = 0.3
|
|
260
|
+
viewStateList.layer.shadowOffset = CGSize(width: 0, height: 2)
|
|
261
|
+
viewStateList.layer.shadowRadius = 4
|
|
262
|
+
// Optionally, you might want to set a corner radius to the view as well
|
|
263
|
+
viewStateList.layer.cornerRadius = 8
|
|
264
|
+
tblViewStateList.layer.cornerRadius = 8
|
|
265
|
+
|
|
266
|
+
// Ensure the view does not clip its content or shadows
|
|
267
|
+
viewCityList.clipsToBounds = false
|
|
268
|
+
// Apply shadow properties
|
|
269
|
+
viewCityList.layer.shadowColor = UIColor.black.cgColor
|
|
270
|
+
viewCityList.layer.shadowOpacity = 0.3
|
|
271
|
+
viewCityList.layer.shadowOffset = CGSize(width: 0, height: 2)
|
|
272
|
+
viewCityList.layer.shadowRadius = 4
|
|
273
|
+
// Optionally, you might want to set a corner radius to the view as well
|
|
274
|
+
viewCityList.layer.cornerRadius = 8
|
|
275
|
+
tblViewCityList.layer.cornerRadius = 8
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
//MARK: Get Country List
|
|
279
|
+
func getCountryListApi() {
|
|
280
|
+
let session = URLSession.shared
|
|
281
|
+
let serviceURL = URL(string: "https://countriesnow.space/api/v0.1/countries/iso")!
|
|
282
|
+
|
|
283
|
+
var request = URLRequest(url: serviceURL)
|
|
284
|
+
request.httpMethod = "GET"
|
|
285
|
+
|
|
286
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
287
|
+
if let error = error {
|
|
288
|
+
self.hideLoadingIndicator()
|
|
289
|
+
print("Error: \(error.localizedDescription)")
|
|
290
|
+
return
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse, httpResponse.statusCode == 200 else {
|
|
294
|
+
self.hideLoadingIndicator()
|
|
295
|
+
print("Error: HTTP Status Code \(String(describing: (serviceResponse as? HTTPURLResponse)?.statusCode))")
|
|
296
|
+
return
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
guard let data = serviceData else {
|
|
300
|
+
self.hideLoadingIndicator()
|
|
301
|
+
print("Error: No data received")
|
|
302
|
+
return
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
do {
|
|
306
|
+
if let jsonResponse = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any],
|
|
307
|
+
let countryData = jsonResponse["data"] as? [[String: Any]] {
|
|
308
|
+
|
|
309
|
+
self.countryList = countryData // Store the list of countries
|
|
310
|
+
|
|
311
|
+
DispatchQueue.main.async {
|
|
312
|
+
self.tblViewCountryList.reloadData() // Reload the table view
|
|
313
|
+
}
|
|
314
|
+
} else {
|
|
315
|
+
self.hideLoadingIndicator()
|
|
316
|
+
print("Error: Unable to parse JSON or find country data")
|
|
317
|
+
}
|
|
318
|
+
} catch {
|
|
319
|
+
self.hideLoadingIndicator()
|
|
320
|
+
print("Error parsing JSON: \(error.localizedDescription)")
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
task.resume()
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
///** Normal Case
|
|
327
|
+
// //MARK: Get State List
|
|
328
|
+
// func getStateListApi(for country: String) {
|
|
329
|
+
// let urlString = "https://countriesnow.space/api/v0.1/countries/states"
|
|
330
|
+
// guard let serviceURL = URL(string: urlString) else {
|
|
331
|
+
// print("Invalid URL")
|
|
332
|
+
// hideLoadingIndicator()
|
|
333
|
+
// return
|
|
334
|
+
// }
|
|
335
|
+
//
|
|
336
|
+
// var request = URLRequest(url: serviceURL)
|
|
337
|
+
// request.httpMethod = "POST"
|
|
338
|
+
// request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
339
|
+
//
|
|
340
|
+
// let params: [String: Any] = [
|
|
341
|
+
// "country": country
|
|
342
|
+
// ]
|
|
343
|
+
//
|
|
344
|
+
// do {
|
|
345
|
+
// let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
346
|
+
// request.httpBody = jsonData
|
|
347
|
+
// } catch {
|
|
348
|
+
// print("Error creating JSON data: \(error)")
|
|
349
|
+
// return
|
|
350
|
+
// }
|
|
351
|
+
//
|
|
352
|
+
// let session = URLSession.shared
|
|
353
|
+
// let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
354
|
+
// if let error = error {
|
|
355
|
+
// print("Error: \(error.localizedDescription)")
|
|
356
|
+
// return
|
|
357
|
+
// }
|
|
358
|
+
//
|
|
359
|
+
// guard let httpResponse = serviceResponse as? HTTPURLResponse, httpResponse.statusCode == 200 else {
|
|
360
|
+
// print("Invalid response or status code")
|
|
361
|
+
// return
|
|
362
|
+
// }
|
|
363
|
+
//
|
|
364
|
+
// if let data = serviceData {
|
|
365
|
+
// do {
|
|
366
|
+
// if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
|
367
|
+
// let dataObject = responseObject["data"] as? [String: Any],
|
|
368
|
+
// let statesArray = dataObject["states"] as? [[String: Any]] {
|
|
369
|
+
//
|
|
370
|
+
// DispatchQueue.main.async {
|
|
371
|
+
// self.stateList = statesArray
|
|
372
|
+
// self.tblViewStateList.reloadData()
|
|
373
|
+
//
|
|
374
|
+
// // Pick a random state and set it in txtFieldState
|
|
375
|
+
// if let randomState = statesArray.randomElement(),
|
|
376
|
+
// let stateName = randomState["name"] as? String {
|
|
377
|
+
// self.txtFieldState.text = stateName
|
|
378
|
+
//
|
|
379
|
+
// // Fetch cities for the randomly selected state and country
|
|
380
|
+
// if let country = self.txtFieldCountry.text {
|
|
381
|
+
// self.getCityListListApi(for: country, state: stateName)
|
|
382
|
+
// }
|
|
383
|
+
// } else {
|
|
384
|
+
// self.txtFieldState.text = "" // No state available
|
|
385
|
+
// }
|
|
386
|
+
// }
|
|
387
|
+
// } else {
|
|
388
|
+
// print("Error: Invalid JSON structure")
|
|
389
|
+
// }
|
|
390
|
+
// } catch {
|
|
391
|
+
// print("Error parsing JSON: \(error)")
|
|
392
|
+
// }
|
|
393
|
+
// } else {
|
|
394
|
+
// print("No data received")
|
|
395
|
+
// }
|
|
396
|
+
// }
|
|
397
|
+
// task.resume()
|
|
398
|
+
// }
|
|
399
|
+
//
|
|
400
|
+
|
|
401
|
+
///** Normal Case
|
|
402
|
+
// //MARK: Get City List
|
|
403
|
+
// func getCityListListApi(for country: String, state: String) {
|
|
404
|
+
// let urlString = "https://countriesnow.space/api/v0.1/countries/state/cities"
|
|
405
|
+
// guard let serviceURL = URL(string: urlString) else {
|
|
406
|
+
// print("Invalid URL")
|
|
407
|
+
// hideLoadingIndicator()
|
|
408
|
+
// return
|
|
409
|
+
// }
|
|
410
|
+
//
|
|
411
|
+
// var request = URLRequest(url: serviceURL)
|
|
412
|
+
// request.httpMethod = "POST"
|
|
413
|
+
// request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
414
|
+
//
|
|
415
|
+
// let params: [String: Any] = [
|
|
416
|
+
// "country": country,
|
|
417
|
+
// "state": state
|
|
418
|
+
// ]
|
|
419
|
+
//
|
|
420
|
+
// do {
|
|
421
|
+
// let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
422
|
+
// request.httpBody = jsonData
|
|
423
|
+
// } catch {
|
|
424
|
+
// print("Error creating JSON data: \(error)")
|
|
425
|
+
// return
|
|
426
|
+
// }
|
|
427
|
+
//
|
|
428
|
+
// let session = URLSession.shared
|
|
429
|
+
// let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
430
|
+
// if let error = error {
|
|
431
|
+
// print("Error: \(error.localizedDescription)")
|
|
432
|
+
// return
|
|
433
|
+
// }
|
|
434
|
+
//
|
|
435
|
+
// guard let httpResponse = serviceResponse as? HTTPURLResponse, httpResponse.statusCode == 200 else {
|
|
436
|
+
// print("Invalid response or status code")
|
|
437
|
+
// return
|
|
438
|
+
// }
|
|
439
|
+
//
|
|
440
|
+
// if let data = serviceData {
|
|
441
|
+
// do {
|
|
442
|
+
// if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
|
443
|
+
// let citiesArray = responseObject["data"] as? [String] { // Directly accessing city list array
|
|
444
|
+
//
|
|
445
|
+
// DispatchQueue.main.async {
|
|
446
|
+
// self.cityList = citiesArray.map { ["city_name": $0] } // Converting to expected format
|
|
447
|
+
// self.tblViewCityList.reloadData()
|
|
448
|
+
//
|
|
449
|
+
// // Pick a random city and set it in txtFieldCity
|
|
450
|
+
// if let randomCity = citiesArray.randomElement() {
|
|
451
|
+
// self.txtFieldCity.text = randomCity
|
|
452
|
+
// } else {
|
|
453
|
+
// self.txtFieldCity.text = "" // No city available
|
|
454
|
+
// }
|
|
455
|
+
// }
|
|
456
|
+
// } else {
|
|
457
|
+
// print("Error: Invalid JSON structure")
|
|
458
|
+
// }
|
|
459
|
+
// } catch {
|
|
460
|
+
// print("Error parsing JSON: \(error)")
|
|
461
|
+
// }
|
|
462
|
+
// } else {
|
|
463
|
+
// print("No data received")
|
|
464
|
+
// }
|
|
465
|
+
// }
|
|
466
|
+
// task.resume()
|
|
467
|
+
// }
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
///**In case of state and city name not found
|
|
471
|
+
func getStateListApi(for country: String) {
|
|
472
|
+
let urlString = "https://countriesnow.space/api/v0.1/countries/states"
|
|
473
|
+
guard let serviceURL = URL(string: urlString) else {
|
|
474
|
+
print("Invalid URL")
|
|
475
|
+
hideLoadingIndicator()
|
|
476
|
+
return
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
var request = URLRequest(url: serviceURL)
|
|
480
|
+
request.httpMethod = "POST"
|
|
481
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
482
|
+
|
|
483
|
+
let params: [String: Any] = [
|
|
484
|
+
"country": country
|
|
485
|
+
]
|
|
486
|
+
|
|
487
|
+
do {
|
|
488
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
489
|
+
request.httpBody = jsonData
|
|
490
|
+
} catch {
|
|
491
|
+
print("Error creating JSON data: \(error)")
|
|
492
|
+
return
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
let session = URLSession.shared
|
|
496
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
497
|
+
if let error = error {
|
|
498
|
+
print("Error: \(error.localizedDescription)")
|
|
499
|
+
return
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse, httpResponse.statusCode == 200 else {
|
|
503
|
+
print("Invalid response or status code")
|
|
504
|
+
return
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
if let data = serviceData {
|
|
508
|
+
do {
|
|
509
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
|
510
|
+
let dataObject = responseObject["data"] as? [String: Any],
|
|
511
|
+
let statesArray = dataObject["states"] as? [[String: Any]] {
|
|
512
|
+
|
|
513
|
+
DispatchQueue.main.async {
|
|
514
|
+
self.stateList = statesArray
|
|
515
|
+
self.tblViewStateList.reloadData()
|
|
516
|
+
|
|
517
|
+
// If no state is found, clear the state and city fields and fill country in both
|
|
518
|
+
if statesArray.isEmpty {
|
|
519
|
+
self.txtFieldState.text = country
|
|
520
|
+
self.txtFieldCity.text = country
|
|
521
|
+
} else {
|
|
522
|
+
// Pick a random state and set it in txtFieldState
|
|
523
|
+
if let randomState = statesArray.randomElement(),
|
|
524
|
+
let stateName = randomState["name"] as? String {
|
|
525
|
+
self.txtFieldState.text = stateName
|
|
526
|
+
|
|
527
|
+
// Fetch cities for the randomly selected state and country
|
|
528
|
+
self.getCityListListApi(for: country, state: stateName)
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
} else {
|
|
533
|
+
print("Error: Invalid JSON structure")
|
|
534
|
+
}
|
|
535
|
+
} catch {
|
|
536
|
+
print("Error parsing JSON: \(error)")
|
|
537
|
+
}
|
|
538
|
+
} else {
|
|
539
|
+
print("No data received")
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
task.resume()
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
///**In case of state and city name not found
|
|
546
|
+
func getCityListListApi(for country: String, state: String) {
|
|
547
|
+
let urlString = "https://countriesnow.space/api/v0.1/countries/state/cities"
|
|
548
|
+
guard let serviceURL = URL(string: urlString) else {
|
|
549
|
+
print("Invalid URL")
|
|
550
|
+
hideLoadingIndicator()
|
|
551
|
+
return
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
var request = URLRequest(url: serviceURL)
|
|
555
|
+
request.httpMethod = "POST"
|
|
556
|
+
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
557
|
+
|
|
558
|
+
let params: [String: Any] = [
|
|
559
|
+
"country": country,
|
|
560
|
+
"state": state
|
|
561
|
+
]
|
|
562
|
+
|
|
563
|
+
do {
|
|
564
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
565
|
+
request.httpBody = jsonData
|
|
566
|
+
} catch {
|
|
567
|
+
print("Error creating JSON data: \(error)")
|
|
568
|
+
return
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
let session = URLSession.shared
|
|
572
|
+
let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
|
|
573
|
+
if let error = error {
|
|
574
|
+
print("Error: \(error.localizedDescription)")
|
|
575
|
+
return
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse, httpResponse.statusCode == 200 else {
|
|
579
|
+
print("Invalid response or status code")
|
|
580
|
+
return
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
if let data = serviceData {
|
|
584
|
+
do {
|
|
585
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
|
586
|
+
let citiesArray = responseObject["data"] as? [String] { // Directly accessing city list array
|
|
587
|
+
|
|
588
|
+
DispatchQueue.main.async {
|
|
589
|
+
self.cityList = citiesArray.map { ["city_name": $0] } // Converting to expected format
|
|
590
|
+
self.tblViewCityList.reloadData()
|
|
591
|
+
|
|
592
|
+
// If no cities found, set state name in city field
|
|
593
|
+
if citiesArray.isEmpty {
|
|
594
|
+
self.txtFieldCity.text = self.txtFieldState.text
|
|
595
|
+
} else {
|
|
596
|
+
// Pick a random city and set it in txtFieldCity
|
|
597
|
+
if let randomCity = citiesArray.randomElement() {
|
|
598
|
+
self.txtFieldCity.text = randomCity
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
} else {
|
|
603
|
+
print("Error: Invalid JSON structure")
|
|
604
|
+
}
|
|
605
|
+
} catch {
|
|
606
|
+
print("Error parsing JSON: \(error)")
|
|
607
|
+
}
|
|
608
|
+
} else {
|
|
609
|
+
print("No data received")
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
task.resume()
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
func updateBillingInfoData() {
|
|
616
|
+
billingInfoData?["address"] = txtFieldAddress.text
|
|
617
|
+
billingInfoData?["country"] = txtFieldCountry.text
|
|
618
|
+
billingInfoData?["state"] = txtFieldState.text
|
|
619
|
+
billingInfoData?["city"] = txtFieldCity.text
|
|
620
|
+
billingInfoData?["postal_code"] = txtFieldPostalCode.text
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
@IBAction func actionBtnSelectCountry(_ sender: UIButton) {
|
|
624
|
+
UIView.animate(withDuration: 0.3) {
|
|
625
|
+
self.viewCountryList.isHidden.toggle()
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
@IBAction func actionBtnSelectState(_ sender: UIButton) {
|
|
630
|
+
UIView.animate(withDuration: 0.3) {
|
|
631
|
+
self.viewStateList.isHidden.toggle()
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
@IBAction func actionBtnSelectCity(_ sender: UIButton) {
|
|
636
|
+
UIView.animate(withDuration: 0.3) {
|
|
637
|
+
self.viewCityList.isHidden.toggle()
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
@IBAction func actionBtnPrevious(_ sender: UIButton) {
|
|
642
|
+
// Pass the text back to the previous screen
|
|
643
|
+
delegate?.didPassTextBack("NewAccount")
|
|
644
|
+
self.navigationController?.popViewController(animated: true)
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
@IBAction func actionBtnNext(_ sender: UIButton) {
|
|
648
|
+
let vc = EasyPaySdk.instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
|
|
649
|
+
// Set properties on AdditionalInfoVC
|
|
650
|
+
vc.cardNumber = cardNumber
|
|
651
|
+
vc.expiryDate = expiryDate
|
|
652
|
+
vc.cvv = cvv
|
|
653
|
+
vc.nameOnCard = nameOnCard
|
|
654
|
+
updateBillingInfoData()
|
|
655
|
+
vc.billingInfoData = billingInfoData
|
|
656
|
+
// Pass the selected payment method
|
|
657
|
+
vc.selectedPaymentMethod = selectedPaymentMethod
|
|
658
|
+
vc.isSavedForFuture = isSavedForFuture
|
|
659
|
+
|
|
660
|
+
//Banking Case
|
|
661
|
+
vc.accountName = accountName
|
|
662
|
+
vc.routingNumber = routingNumber
|
|
663
|
+
vc.accountType = accountType
|
|
664
|
+
vc.accountNumber = accountNumber
|
|
665
|
+
|
|
666
|
+
vc.customerID = customerID
|
|
667
|
+
vc.accountID = accountID
|
|
668
|
+
vc.isFrom = isFrom
|
|
669
|
+
|
|
670
|
+
vc.isSavedNewAccount = isSavedNewAccount
|
|
671
|
+
vc.amount = amount
|
|
672
|
+
|
|
673
|
+
if isFrom == "SavedCards" {
|
|
674
|
+
vc.isFrom = "SavedCards"
|
|
675
|
+
vc.selectedCard = selectedCard // Passing the selected card data
|
|
676
|
+
vc.cvvText = cvvText // Passing the CVV text
|
|
677
|
+
vc.amount = amount
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
if isFrom == "AddNewCard" {
|
|
681
|
+
vc.isFrom = "AddNewCard"
|
|
682
|
+
vc.amount = amount
|
|
683
|
+
vc.isSavedNewCard = isSavedNewCard
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
self.navigationController?.pushViewController(vc, animated: true)
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
//MARK: - Table View
|
|
692
|
+
// @available(iOS 16.0, *)
|
|
693
|
+
extension BillingInfoVC: UITableViewDelegate, UITableViewDataSource {
|
|
694
|
+
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
|
695
|
+
if tableView == tblViewCountryList {
|
|
696
|
+
return countryList.count
|
|
697
|
+
}
|
|
698
|
+
else if tableView == tblViewStateList {
|
|
699
|
+
return stateList.count
|
|
700
|
+
}
|
|
701
|
+
else if tableView == tblViewCityList {
|
|
702
|
+
return cityList.count
|
|
703
|
+
}
|
|
704
|
+
else {
|
|
705
|
+
return 0
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
|
710
|
+
if tableView == tblViewCountryList {
|
|
711
|
+
let cell = tableView.dequeueReusableCell(withIdentifier: "CountryListTVC") as! CountryListTVC
|
|
712
|
+
let country = countryList[indexPath.row]
|
|
713
|
+
cell.lblCountryName.text = country["name"] as? String
|
|
714
|
+
return cell
|
|
715
|
+
} else if tableView == tblViewStateList {
|
|
716
|
+
let cell = tableView.dequeueReusableCell(withIdentifier: "StateListTVC") as! StateListTVC
|
|
717
|
+
let state = stateList[indexPath.row]
|
|
718
|
+
cell.lblStateName.text = state["name"] as? String
|
|
719
|
+
return cell
|
|
720
|
+
} else if tableView == tblViewCityList {
|
|
721
|
+
let cell = tableView.dequeueReusableCell(withIdentifier: "CityListTVC") as! CityListTVC
|
|
722
|
+
let city = cityList[indexPath.row]
|
|
723
|
+
cell.lblCityName.text = city["city_name"] as? String
|
|
724
|
+
return cell
|
|
725
|
+
} else {
|
|
726
|
+
return UITableViewCell()
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
|
731
|
+
if tableView == tblViewCountryList {
|
|
732
|
+
let selectedCountry = countryList[indexPath.row]["name"] as? String
|
|
733
|
+
txtFieldCountry.text = selectedCountry
|
|
734
|
+
viewCountryList.isHidden = true
|
|
735
|
+
|
|
736
|
+
// Fetch states for the selected country
|
|
737
|
+
if let country = selectedCountry {
|
|
738
|
+
getStateListApi(for: country)
|
|
739
|
+
}
|
|
740
|
+
} else if tableView == tblViewStateList {
|
|
741
|
+
let selectedState = stateList[indexPath.row]["name"] as? String
|
|
742
|
+
txtFieldState.text = selectedState
|
|
743
|
+
viewStateList.isHidden = true
|
|
744
|
+
|
|
745
|
+
// Fetch cities for the selected state and country
|
|
746
|
+
if let state = selectedState, let country = txtFieldCountry.text {
|
|
747
|
+
getCityListListApi(for: country, state: state)
|
|
748
|
+
}
|
|
749
|
+
} else if tableView == tblViewCityList {
|
|
750
|
+
let selectedCity = cityList[indexPath.row]["city_name"] as? String
|
|
751
|
+
txtFieldCity.text = selectedCity
|
|
752
|
+
viewCityList.isHidden = true
|
|
753
|
+
|
|
754
|
+
// Fetch the city list again based on selected state & country
|
|
755
|
+
if let state = txtFieldState.text, let country = txtFieldCountry.text {
|
|
756
|
+
getCityListListApi(for: country, state: state)
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
updateBillingInfoData()
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
|
764
|
+
return 50
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// @available(iOS 16.0, *)
|
|
770
|
+
extension BillingInfoVC: UITextFieldDelegate {
|
|
771
|
+
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
|
772
|
+
textField.resignFirstResponder() // Dismiss the keyboard
|
|
773
|
+
return true
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// Update billingInfoData when user finishes editing a field
|
|
777
|
+
func textFieldDidEndEditing(_ textField: UITextField) {
|
|
778
|
+
switch textField {
|
|
779
|
+
case txtFieldAddress:
|
|
780
|
+
billingInfoData?["address"] = textField.text
|
|
781
|
+
case txtFieldCountry:
|
|
782
|
+
billingInfoData?["country"] = textField.text
|
|
783
|
+
case txtFieldState:
|
|
784
|
+
billingInfoData?["state"] = textField.text
|
|
785
|
+
case txtFieldCity:
|
|
786
|
+
billingInfoData?["city"] = textField.text
|
|
787
|
+
case txtFieldPostalCode:
|
|
788
|
+
billingInfoData?["postal_code"] = textField.text
|
|
789
|
+
default:
|
|
790
|
+
break
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
|