@jimrising/easymerchantsdk-react-native 1.3.2 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,71 @@
1
+ //
2
+ // DatePickerHandler.swift
3
+ // EasyPay
4
+ //
5
+ // Created by Mony's Mac on 14/05/25.
6
+ //
7
+
8
+ import UIKit
9
+
10
+ class DatePickerHandler: NSObject {
11
+
12
+ private let datePicker = UIDatePicker()
13
+ private var targetTextField: UITextField?
14
+
15
+ var onDateSelected: ((Date) -> Void)?
16
+
17
+ init(textField: UITextField, initialDate: Date? = nil) {
18
+ super.init()
19
+
20
+ self.targetTextField = textField
21
+ configureDatePicker()
22
+
23
+ if let date = initialDate {
24
+ datePicker.date = date
25
+ }
26
+
27
+ setupInputView(for: textField)
28
+ }
29
+
30
+ private func configureDatePicker() {
31
+ if #available(iOS 14.0, *) {
32
+ datePicker.preferredDatePickerStyle = .inline
33
+ }
34
+ datePicker.datePickerMode = .date
35
+ datePicker.minimumDate = Date()
36
+ datePicker.addTarget(self, action: #selector(dateChanged(_:)), for: .valueChanged)
37
+ }
38
+
39
+ private func setupInputView(for textField: UITextField) {
40
+ textField.inputView = datePicker
41
+
42
+ let toolbar = UIToolbar()
43
+ toolbar.sizeToFit()
44
+
45
+ let doneButton = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(doneDateSelection))
46
+ let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
47
+
48
+ toolbar.setItems([space, doneButton], animated: false)
49
+ textField.inputAccessoryView = toolbar
50
+ }
51
+
52
+ @objc private func dateChanged(_ sender: UIDatePicker) {
53
+ let formatter = DateFormatter()
54
+ formatter.dateFormat = "dd/MM/yyyy"
55
+ targetTextField?.text = formatter.string(from: sender.date)
56
+ onDateSelected?(sender.date)
57
+ }
58
+
59
+ @objc private func doneDateSelection() {
60
+ if targetTextField?.text?.isEmpty ?? true {
61
+ let formatter = DateFormatter()
62
+ formatter.dateFormat = "dd/MM/yyyy"
63
+ let dateText = formatter.string(from: datePicker.date)
64
+ targetTextField?.text = dateText
65
+ onDateSelected?(datePicker.date)
66
+ }
67
+ targetTextField?.resignFirstResponder()
68
+ }
69
+
70
+ }
71
+
@@ -0,0 +1,58 @@
1
+ //
2
+ // PlanSelector.swift
3
+ // EasyPay
4
+ //
5
+ // Created by Mony's Mac on 14/05/25.
6
+ //
7
+
8
+ import UIKit
9
+
10
+ class PlanSelector {
11
+
12
+ static func presentPlanOptions(from viewController: UIViewController, sourceView: UIView, onSelection: @escaping (String) -> Void) {
13
+
14
+ let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
15
+
16
+ // Create actions
17
+ let weeklyAction = UIAlertAction(title: "Weekly", style: .default) { _ in
18
+ onSelection("Weekly")
19
+ }
20
+
21
+ let monthlyAction = UIAlertAction(title: "Monthly", style: .default) { _ in
22
+ onSelection("Monthly")
23
+ }
24
+
25
+ let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
26
+
27
+ alertController.addAction(weeklyAction)
28
+ alertController.addAction(monthlyAction)
29
+ alertController.addAction(cancelAction)
30
+
31
+ // Set attributed title with secondary font color
32
+ if let secondaryColorHex = UserStoreSingleton.shared.secondary_font_col,
33
+ let secondaryColor = UIColor(hex: secondaryColorHex) {
34
+ let titleAttrString = NSAttributedString(string: "Select Plan", attributes: [
35
+ .foregroundColor: secondaryColor,
36
+ .font: UIFont.systemFont(ofSize: 16, weight: .medium)
37
+ ])
38
+ alertController.setValue(titleAttrString, forKey: "attributedTitle")
39
+ }
40
+
41
+ // Set title colors for actions using primary font color
42
+ if let buttonColorHex = UserStoreSingleton.shared.primary_btn_bg_col,
43
+ let buttonColor = UIColor(hex: buttonColorHex) {
44
+ weeklyAction.setValue(buttonColor, forKey: "titleTextColor")
45
+ monthlyAction.setValue(buttonColor, forKey: "titleTextColor")
46
+ cancelAction.setValue(UIColor.red, forKey: "titleTextColor")
47
+ }
48
+
49
+ // iPad Support
50
+ if let popoverController = alertController.popoverPresentationController {
51
+ popoverController.sourceView = sourceView
52
+ popoverController.sourceRect = sourceView.bounds
53
+ }
54
+
55
+ viewController.present(alertController, animated: true)
56
+ }
57
+ }
58
+
@@ -57,7 +57,8 @@ public class EnvironmentConfig {
57
57
  case .hostedCheckouts: return "/api/v1/hostedcheckouts"
58
58
  case .emailVerification: return "/api/v1/customer/send_otp"
59
59
  case .verifyOtp: return "/api/v1/customer/verify_otp"
60
- case .getCards: return "/api/v1/customer/card"
60
+ // case .getCards: return "/api/v1/customer/card"
61
+ case .getCards: return "/api/v1/card"
61
62
  case .creditCharges: return "/api/v1/customer/charges"
62
63
  case .account: return "/api/v1/ach/account"
63
64
  case .achCharge: return "/api/v1/ach/charge"
@@ -87,7 +87,7 @@ public final class Request: NSObject {
87
87
  public let billingInfoData: Data?
88
88
  let themeConfiguration: ThemeConfiguration?
89
89
  let selectedPaymentMethods: [PaymentMethod]
90
-
90
+
91
91
  // New parameters
92
92
  public let tokenOnly: Bool?
93
93
  public let saveCard: Bool?
@@ -95,10 +95,11 @@ public final class Request: NSObject {
95
95
  public let submitButtonText: String?
96
96
  public let authenticatedACH: Bool?
97
97
  public let grailPayParams: GrailPayRequest?
98
-
98
+ public let enableRecurring: Bool?
99
+
99
100
  public init(
100
101
  amount: Double,
101
- billingInfoData: Data,
102
+ billingInfoData: Data? = nil,
102
103
  paymentMethods: [PaymentMethod]? = nil,
103
104
  themeConfiguration: ThemeConfiguration? = nil,
104
105
  tokenOnly: Bool = false,
@@ -106,7 +107,8 @@ public final class Request: NSObject {
106
107
  saveAccount: Bool = false,
107
108
  submitButtonText: String? = nil,
108
109
  authenticatedACH: Bool = false,
109
- grailPayParams: GrailPayRequest? = nil
110
+ grailPayParams: GrailPayRequest? = nil,
111
+ enableRecurring: Bool = false
110
112
  ) {
111
113
  self.amount = amount
112
114
  self.billingInfoData = billingInfoData
@@ -117,7 +119,8 @@ public final class Request: NSObject {
117
119
  self.submitButtonText = submitButtonText
118
120
  self.authenticatedACH = authenticatedACH
119
121
  self.grailPayParams = authenticatedACH ? grailPayParams : nil
120
-
122
+ self.enableRecurring = enableRecurring
123
+
121
124
  if let paymentMethods = paymentMethods {
122
125
  self.selectedPaymentMethods = paymentMethods
123
126
  UserStoreSingleton.shared.paymentMethods = paymentMethods.map { $0.rawValue }
@@ -140,9 +143,9 @@ public final class Request: NSObject {
140
143
  UserStoreSingleton.shared.border_radious = themeConfig.borderRadius
141
144
  UserStoreSingleton.shared.fontSize = themeConfig.fontSize
142
145
  }
143
-
146
+
144
147
  super.init()
145
-
148
+
146
149
  // If tokenOnly is true, fetch only the clientToken and do not open the SDK
147
150
  if tokenOnly {
148
151
  self.paymentIntentApi { success in
@@ -163,29 +166,29 @@ public final class Request: NSObject {
163
166
  }
164
167
  }
165
168
  }
166
-
169
+
167
170
  }
168
-
171
+
169
172
  //MARK: - Payment Intent Api
170
173
  func paymentIntentApi(completion: @escaping (Bool) -> Void) {
171
174
  // Start loader when API call starts
172
-
175
+
173
176
  guard let serviceURL = URL(string: EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.paymentIntent.path()) else {
174
177
  print("Invalid URL")
175
178
  completion(false)
176
179
  return
177
180
  }
178
-
181
+
179
182
  var request = URLRequest(url: serviceURL)
180
183
  request.httpMethod = "POST"
181
184
  request.addValue("application/json", forHTTPHeaderField: "Content-Type")
182
185
  request.addValue(EnvironmentConfig.apiKey ?? "", forHTTPHeaderField: "X-Api-Key")
183
186
  request.addValue(EnvironmentConfig.apiSecret ?? "", forHTTPHeaderField: "X-Api-Secret")
184
-
187
+
185
188
  let params: [String: Any] = [
186
189
  "amount": amount,
187
190
  ]
188
-
191
+
189
192
  do {
190
193
  request.httpBody = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
191
194
  } catch {
@@ -193,34 +196,34 @@ public final class Request: NSObject {
193
196
  completion(false)
194
197
  return
195
198
  }
196
-
199
+
197
200
  let task = URLSession.shared.dataTask(with: request) { data, response, error in
198
201
  DispatchQueue.main.async {
199
202
  // Stop loader when response is received
200
203
  }
201
-
204
+
202
205
  guard let httpResponse = response as? HTTPURLResponse, error == nil else {
203
206
  print("Error: \(error?.localizedDescription ?? "Unknown error")")
204
207
  completion(false)
205
208
  return
206
209
  }
207
-
210
+
208
211
  if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
209
212
  if let data = data {
210
213
  do {
211
214
  if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
212
215
  print("Response Data: \(responseObject)")
213
-
216
+
214
217
  // Save tokens
215
218
  if let clientToken = responseObject["client_token"] as? String {
216
219
  UserStoreSingleton.shared.clientToken = clientToken
217
220
  print("Client Token successfully saved: \(UserStoreSingleton.shared.clientToken ?? "None")")
218
221
  }
219
-
222
+
220
223
  if let paymentIntent = responseObject["payment_intent"] as? String {
221
224
  UserStoreSingleton.shared.paymentIntent = paymentIntent
222
225
  }
223
-
226
+
224
227
  self.hostedCheckoutsApi { success in
225
228
  completion(success)
226
229
  }
@@ -243,29 +246,29 @@ public final class Request: NSObject {
243
246
  }
244
247
  task.resume()
245
248
  }
246
-
249
+
247
250
  // MARK: - Hosted Checkout API
248
251
  func hostedCheckoutsApi(completion: @escaping (Bool) -> Void) {
249
-
252
+
250
253
  // Build the URL using EnvironmentConfig
251
254
  guard let baseURL = URL(string: EnvironmentConfig.baseURL) else {
252
255
  print("Invalid base URL")
253
256
  completion(false)
254
257
  return
255
258
  }
256
-
259
+
257
260
  let endpointPath = EnvironmentConfig.Endpoints.hostedCheckouts.path()
258
261
  let serviceURL = baseURL.appendingPathComponent(endpointPath)
259
-
262
+
260
263
  var request = URLRequest(url: serviceURL)
261
264
  request.httpMethod = "POST"
262
265
  request.addValue("application/json", forHTTPHeaderField: "Content-Type")
263
266
  request.addValue(UserStoreSingleton.shared.clientToken ?? "", forHTTPHeaderField: "clientToken")
264
-
267
+
265
268
  let params: [String: Any] = [
266
269
  "amount": amount,
267
270
  ]
268
-
271
+
269
272
  do {
270
273
  request.httpBody = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
271
274
  } catch {
@@ -273,33 +276,33 @@ public final class Request: NSObject {
273
276
  completion(false)
274
277
  return
275
278
  }
276
-
279
+
277
280
  let task = URLSession.shared.dataTask(with: request) { data, response, error in
278
-
281
+
279
282
  guard let httpResponse = response as? HTTPURLResponse, error == nil else {
280
283
  print("Error: \(error?.localizedDescription ?? "Unknown error")")
281
284
  completion(false)
282
285
  return
283
286
  }
284
-
287
+
285
288
  if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
286
289
  if let data = data {
287
290
  do {
288
291
  if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
289
292
  let dataObject = responseObject["data"] as? [String: Any] {
290
293
  print(dataObject)
291
-
294
+
292
295
  // Save merchant details
293
296
  if let merchantEmail = dataObject["merchant_email"] as? String {
294
297
  UserStoreSingleton.shared.merchantEmail = merchantEmail
295
298
  print("Saved merchantEmail: \(merchantEmail)")
296
299
  }
297
-
300
+
298
301
  if let merchantName = dataObject["merchant_name"] as? String {
299
302
  UserStoreSingleton.shared.merchantName = merchantName
300
303
  print("Saved merchantName: \(merchantName)")
301
304
  }
302
-
305
+
303
306
  // Save payment methods (crypto payment account)
304
307
  if let paymentMethods = dataObject["payment_methods"] as? [String: Any],
305
308
  let cryptoSection = paymentMethods["crypto"] as? [String: Any],
@@ -307,31 +310,31 @@ public final class Request: NSObject {
307
310
  UserStoreSingleton.shared.paymentAccount = paymentAccount
308
311
  print("Saved paymentAccount (Crypto): \(paymentAccount)")
309
312
  }
310
-
313
+
311
314
  // Save payment methods
312
315
  if let paymentMethods = dataObject["payment_methods"] as? [String: Any] {
313
316
  var paymentMethodNames: [String] = []
314
-
317
+
315
318
  if paymentMethods["card"] is [String: Any] {
316
319
  paymentMethodNames.append("Card")
317
320
  }
318
-
321
+
319
322
  if paymentMethods["ach"] is [String: Any] {
320
323
  paymentMethodNames.append("Bank")
321
324
  }
322
-
325
+
323
326
  if paymentMethods["crypto"] is [String: Any] {
324
327
  paymentMethodNames.append("Crypto")
325
328
  }
326
-
329
+
327
330
  if paymentMethods["wallet"] is [String: Any] {
328
331
  paymentMethodNames.append("Wallet")
329
332
  }
330
-
333
+
331
334
  UserStoreSingleton.shared.paymentMethods = paymentMethodNames
332
335
  print("Saved payment methods: \(paymentMethodNames)")
333
336
  }
334
-
337
+
335
338
  if self.themeConfiguration == nil, let appearanceSettings = dataObject["apperance_settings"] as? [String: Any] {
336
339
  UserStoreSingleton.shared.body_bg_col = appearanceSettings["body_bg_col"] as? String
337
340
  UserStoreSingleton.shared.border_radious = appearanceSettings["border_radious"] as? String
@@ -344,13 +347,13 @@ public final class Request: NSObject {
344
347
  UserStoreSingleton.shared.secondary_btn_font_col = appearanceSettings["secondary_font_col"] as? String
345
348
  UserStoreSingleton.shared.secondary_btn_hover_col = appearanceSettings["secondary_btn_hover_col"] as? String
346
349
  UserStoreSingleton.shared.secondary_font_col = appearanceSettings["secondary_font_col"] as? String
347
-
350
+
348
351
  // Clearing the font size value
349
352
  UserStoreSingleton.shared.fontSize = nil
350
353
  }
351
-
354
+
352
355
  completion(true)
353
-
356
+
354
357
  } else {
355
358
  print("Invalid JSON format or 'data' key is missing")
356
359
  completion(false)
@@ -370,6 +373,5 @@ public final class Request: NSObject {
370
373
  }
371
374
  task.resume()
372
375
  }
373
-
376
+
374
377
  }
375
-