You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

526 lines
18 KiB

6 years ago
  1. //
  2. // KycForm2ViewController.swift
  3. // GMERemittance
  4. //
  5. // Created by gme_2 on 12/09/2018.
  6. //Copyright © 2018 Gobal Money Express Co. Ltd. All rights reserved.
  7. //
  8. import UIKit
  9. import XLPagerTabStrip
  10. class KycForm2Model {
  11. var bank = ""
  12. var accountNumber = ""
  13. var verificationId = ""
  14. var verificationIdNumber = ""
  15. var expiryDate = ""
  16. var sourceOfFund = ""
  17. var issueDate = ""
  18. var checkIssueDate = false
  19. var checkExpiryDate = false
  20. }
  21. struct KycForm2FieldKeys {
  22. static let bank = "bank"
  23. static let accountNumber = "account number"
  24. static let verificationId = "verification id"
  25. static let verificationIdNumber = "verification id number"
  26. static let expiryDate = "expiry date"
  27. static let sourceOfFund = "source of fund"
  28. static let issueDate = "issue date"
  29. static let shouldValidateIssueDate = "issue date validation"
  30. static let shouldValidateExpiryDate = "expiry date validation"
  31. }
  32. enum KycVerificationIdType: String {
  33. case alieanCard = "Alien Registration Card"
  34. case nationalIdCard = "National ID"
  35. case passport = "Passport"
  36. }
  37. class KycForm2ViewController: UIViewController {
  38. struct Constants {
  39. static let stateRedColor = UIColor.init(hex: "#EC1C24")
  40. static let clearColor = UIColor.clear
  41. static let issueDateText = "docIssueDate"
  42. static let expiryDateText = "docExpiryDate"
  43. static let issueDateTag = 30001
  44. static let expiryDateTag = 30002
  45. static let errorFont = Fonts.Error.font
  46. static let errorBorderSize = AppConstants.errorBorderWidth
  47. }
  48. // MARK: IBOutlets
  49. // labels
  50. @IBOutlet weak var bankErrorLabel: UILabel!
  51. @IBOutlet weak var accountNumberErrorLabel: UILabel!
  52. @IBOutlet weak var verificationIdErrorLabel: UILabel!
  53. @IBOutlet weak var verificationIdNumberErrorLabel: UILabel!
  54. @IBOutlet weak var expiryDateErrorLabel: UILabel!
  55. @IBOutlet weak var sourceOfFundErrorLabel: UILabel!
  56. @IBOutlet weak var issueDateErrorLabel: UILabel!
  57. // textfields
  58. @IBOutlet weak var bankTextField: UITextField!
  59. @IBOutlet weak var accountNumberTextField: UITextField!
  60. @IBOutlet weak var verificationIdTextField: UITextField!
  61. @IBOutlet weak var verificationIdNumberTextField: UITextField!
  62. @IBOutlet weak var expiryDateTextField: UITextField!
  63. @IBOutlet weak var sourceOfFundTextField: UITextField!
  64. @IBOutlet weak var issueDateTextField: UITextField!
  65. // stackViews
  66. @IBOutlet weak var expiryDateStackView: UIStackView!
  67. @IBOutlet weak var issueDateStackView: UIStackView!
  68. // MARK: Properties
  69. var errorLabels: [UILabel] = []
  70. var textfields: [UITextField] = []
  71. var errorTextFieldDict: [String: UITextField] = [:]
  72. var errorLabelsDict: [String: UILabel] = [:]
  73. var hiddenFieldsDict: [String: UIStackView]?
  74. var hiddenFields: [UIStackView]?
  75. var kycModel: KycModel? {
  76. didSet {
  77. self.banks = kycModel?.bank
  78. self.verificationIdTypes = kycModel?.idType
  79. self.sourceOfFunds = kycModel?.sourceOfFund
  80. }
  81. }
  82. var verificationIdSelectedCardType: KycVerificationIdType = .passport {
  83. didSet {
  84. switch verificationIdSelectedCardType {
  85. case .alieanCard, .nationalIdCard:
  86. self.verificationIdNumberTextField.keyboardType = .numberPad
  87. self.verificationIdNumberTextField.addTarget(self, action: #selector(self.verificationIdTextChanged(sender:)
  88. ), for: UIControlEvents.editingChanged)
  89. break
  90. case .passport:
  91. self.verificationIdNumberTextField.keyboardType = .default
  92. self.verificationIdNumberTextField.removeTarget(self, action: #selector(self.verificationIdTextChanged(sender:)
  93. ), for: UIControlEvents.editingChanged)
  94. break
  95. }
  96. }
  97. }
  98. var banks: [KeyValueModel]?
  99. var verificationIdTypes: [VerificationIdType]? {
  100. didSet {
  101. }
  102. }
  103. var sourceOfFunds:[KeyValueModel]?
  104. var selectedBank: KeyValueModel? {
  105. didSet {
  106. self.bankTextField.text = selectedBank?.text
  107. self.kycForm2Model.bank = selectedBank?.id ?? ""
  108. }
  109. }
  110. var selectedVerificationIdType: VerificationIdType? {
  111. didSet {
  112. self.verificationIdTextField.text = self.selectedVerificationIdType?.text
  113. self.kycForm2Model.verificationId = self.selectedVerificationIdType?.id ?? ""
  114. var _views: [UIStackView] = []
  115. _views = (self.selectedVerificationIdType?.dependent ?? []).compactMap({
  116. print($0)
  117. return self.hiddenFieldsDict?[$0]
  118. })
  119. self.hiddenFields?.forEach({
  120. if _views.contains($0) {
  121. self.kycForm2Model.checkIssueDate = $0.tag == Constants.issueDateTag
  122. self.kycForm2Model.checkExpiryDate = $0.tag == Constants.expiryDateTag
  123. $0.isHidden = false
  124. }else {
  125. $0.isHidden = true
  126. }
  127. })
  128. if selectedVerificationIdType?.text != oldValue?.text {
  129. self.verificationIdNumberTextField.text = ""
  130. }
  131. if let type = KycVerificationIdType.init(rawValue: selectedVerificationIdType?.text ?? "") {
  132. self.verificationIdSelectedCardType = type
  133. }
  134. }
  135. }
  136. var selectedSourceOfFund : KeyValueModel? {
  137. didSet {
  138. self.sourceOfFundTextField.text = selectedSourceOfFund?.text
  139. self.kycForm2Model.sourceOfFund = selectedSourceOfFund?.id ?? ""
  140. }
  141. }
  142. var delegate: KYCForm2Delegate?
  143. var presenter: KycForm2ModuleInterface?
  144. var continueActionInitiated = false
  145. var kycForm2Model: KycForm2Model = KycForm2Model()
  146. let expiaryDatePicker = UIDatePicker()
  147. let issueDatePicker = UIDatePicker()
  148. // MARK: VC's Life cycle
  149. override func viewDidLoad() {
  150. super.viewDidLoad()
  151. self.setup()
  152. }
  153. override func viewWillDisappear(_ animated: Bool) {
  154. super.viewWillDisappear(animated)
  155. continueActionInitiated = false
  156. validate()
  157. }
  158. // MARK: IBActions
  159. @IBAction func _continue(_ sender: UIButton) {
  160. continueActionInitiated = true
  161. self.delegate?._continue(model: self.kycForm2Model)
  162. }
  163. // MARK: Other Functions
  164. private func createModel() {
  165. self.kycForm2Model.accountNumber = self.accountNumberTextField.text!
  166. self.kycForm2Model.verificationIdNumber = self.verificationIdNumberTextField.text!
  167. self.kycForm2Model.expiryDate = self.expiryDateTextField.text!
  168. self.kycForm2Model.issueDate = self.issueDateTextField.text!
  169. }
  170. private func setup() {
  171. // all setup should be done here
  172. hideErrorLabels()
  173. setupErrorLabels()
  174. setupErrorTextFields()
  175. setupDatePicker()
  176. setupDelegates()
  177. setupHiddenFields()
  178. }
  179. private func setupHiddenFields() {
  180. self.hiddenFields = [issueDateStackView, expiryDateStackView]
  181. issueDateStackView.tag = Constants.issueDateTag
  182. expiryDateStackView.tag = Constants.expiryDateTag
  183. self.hiddenFieldsDict = [
  184. Constants.issueDateText : issueDateStackView,
  185. Constants.expiryDateText: expiryDateStackView
  186. ]
  187. self.hiddenFieldsDict?.forEach({
  188. $0.value.isHidden = true
  189. })
  190. }
  191. private func validate() {
  192. createModel()
  193. self.delegate?.addModel(model: self.kycForm2Model)
  194. }
  195. @objc private func verificationIdTextChanged(sender: UITextField) {
  196. }
  197. private func setupDelegates() {
  198. self.bankTextField.delegate = self
  199. self.accountNumberTextField.delegate = self
  200. self.verificationIdTextField.delegate = self
  201. self.verificationIdNumberTextField.delegate = self
  202. self.expiryDateTextField.delegate = self
  203. self.issueDateTextField.delegate = self
  204. self.sourceOfFundTextField.delegate = self
  205. }
  206. private func setupDatePicker() {
  207. self.expiaryDatePicker.datePickerMode = .date
  208. self.expiryDateTextField.inputView = expiaryDatePicker
  209. self.expiaryDatePicker.addTarget(self, action: #selector(handleExpiryDatePicker), for: .valueChanged)
  210. self.issueDatePicker.datePickerMode = .date
  211. self.issueDateTextField.inputView = issueDatePicker
  212. issueDatePicker.maximumDate = Date()
  213. self.issueDatePicker.addTarget(self, action: #selector(handleIssueDatePicker), for: .valueChanged)
  214. }
  215. @objc private func handleIssueDatePicker(sender: UIDatePicker) {
  216. let dateFormatter = DateFormatter()
  217. let date = sender.date
  218. expiaryDatePicker.minimumDate = date
  219. dateFormatter.dateFormat = AppConstants.dateFormat
  220. // test ccr
  221. self.issueDateTextField.text = dateFormatter.string(from: sender.date)
  222. }
  223. @objc private func handleExpiryDatePicker(sender: UIDatePicker) {
  224. let dateFormatter = DateFormatter()
  225. // test ccr
  226. dateFormatter.dateFormat = AppConstants.dateFormat
  227. self.expiryDateTextField.text = dateFormatter.string(from: sender.date)
  228. }
  229. private func hideErrorLabels() {
  230. [bankErrorLabel, accountNumberErrorLabel, verificationIdErrorLabel, verificationIdNumberErrorLabel, expiryDateErrorLabel, issueDateErrorLabel, sourceOfFundErrorLabel].forEach({
  231. $0?.isHidden = true
  232. })
  233. }
  234. private func setupErrorLabels() {
  235. self.errorLabels = [bankErrorLabel, accountNumberErrorLabel, verificationIdErrorLabel, verificationIdNumberErrorLabel, expiryDateErrorLabel,issueDateErrorLabel, sourceOfFundErrorLabel]
  236. self.errorLabels.forEach({
  237. $0.font = Constants.errorFont
  238. })
  239. self.errorLabelsDict =
  240. [
  241. KycForm2FieldKeys.bank: self.bankErrorLabel,
  242. KycForm2FieldKeys.accountNumber: self.accountNumberErrorLabel,
  243. KycForm2FieldKeys.verificationId: self.verificationIdErrorLabel,
  244. KycForm2FieldKeys.verificationIdNumber: self.verificationIdNumberErrorLabel,
  245. KycForm2FieldKeys.expiryDate: self.expiryDateErrorLabel,
  246. KycForm2FieldKeys.sourceOfFund: self.sourceOfFundErrorLabel,
  247. KycForm2FieldKeys.issueDate: self.issueDateErrorLabel
  248. ]
  249. }
  250. private func setupErrorTextFields() {
  251. self.textfields = [bankTextField, accountNumberTextField, verificationIdTextField, verificationIdNumberTextField, expiryDateTextField, sourceOfFundTextField]
  252. bankTextField.tag = 12
  253. accountNumberTextField.tag = 13
  254. verificationIdNumberTextField.tag = 14
  255. expiryDateTextField.tag = 15
  256. issueDateTextField.tag = 16
  257. sourceOfFundTextField.tag = 17
  258. self.errorTextFieldDict =
  259. [
  260. KycForm2FieldKeys.bank: self.bankTextField,
  261. KycForm2FieldKeys.accountNumber: self.accountNumberTextField,
  262. KycForm2FieldKeys.verificationId: self.verificationIdTextField,
  263. KycForm2FieldKeys.verificationIdNumber: self.verificationIdNumberTextField,
  264. KycForm2FieldKeys.expiryDate: self.expiryDateTextField,
  265. KycForm2FieldKeys.sourceOfFund: self.sourceOfFundTextField
  266. ]
  267. }
  268. private func showBorder(textfield :UITextField?) {
  269. guard let textfield = textfield else {return}
  270. textfield.layer.borderColor = Constants.stateRedColor.cgColor
  271. textfield.layer.borderWidth = Constants.errorBorderSize
  272. textfield.layer.addShadow(with: Constants.stateRedColor)
  273. }
  274. private func show( error: String, label: UILabel?) {
  275. // scroll to the top of the view
  276. guard let label = label else {return}
  277. label.textColor = Constants.stateRedColor
  278. label.isHidden = false
  279. label.text = error
  280. }
  281. }
  282. // MARK: KycForm2ViewInterface
  283. extension KycForm2ViewController: KycForm2ViewInterface {
  284. func show(resut2: (isValid: Bool, errorsDick: [String : String])) {
  285. var position = 15
  286. if resut2.isValid { // if isValid
  287. // its is not valid, lets go to security page
  288. if self.continueActionInitiated {
  289. self.delegate?._continue(model: self.kycForm2Model)
  290. }
  291. }else {
  292. resut2.errorsDick.forEach({
  293. let label = errorLabelsDict[$0.key]
  294. self.show(error: $0.value, label: label)
  295. let textfield = errorTextFieldDict[$0.key]
  296. self.showBorder(textfield: textfield)
  297. let tag = (textfield?.tag ?? position)
  298. position = tag < position ? tag : position
  299. if let topMostTextField = self.textfields.filter({
  300. $0.tag == tag
  301. }).first {
  302. // Todo
  303. // scroll to view here
  304. }
  305. })
  306. }
  307. }
  308. func show(error: String) {
  309. self.alert(message: error)
  310. }
  311. func showLoading() {
  312. self.showProgressHud()
  313. }
  314. func hideLoading() {
  315. self.hideProgressHud()
  316. }
  317. }
  318. extension KycForm2ViewController: IndicatorInfoProvider {
  319. func indicatorInfo(for pagerTabStripController: PagerTabStripViewController) -> IndicatorInfo {
  320. return IndicatorInfo.init(title: "Security")
  321. }
  322. }
  323. extension KycForm2ViewController: UITextFieldDelegate {
  324. func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
  325. if textField == verificationIdNumberTextField && self.verificationIdSelectedCardType != .passport {
  326. let text = textField.text!
  327. if (range.length > 0)
  328. {
  329. // We're deleting
  330. if text.count < 7 {
  331. let newText = text.replacingOccurrences(of: "-", with: "")
  332. textField.text = newText
  333. }
  334. }
  335. else
  336. {
  337. var _text = text.replacingOccurrences(of: "-", with: "")
  338. if _text.count >= 6 {
  339. _text.insert("-", at: String.Index.init(encodedOffset: 6))
  340. textField.text = _text
  341. }
  342. // We're adding
  343. }
  344. }
  345. return true
  346. }
  347. func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
  348. textField.layer.addShadow(with: Constants.clearColor)
  349. textField.layer.borderWidth = 0
  350. switch textField {
  351. case bankTextField:
  352. // show bank picker
  353. showBankPickerView()
  354. self.bankErrorLabel.isHidden = true
  355. return false
  356. case verificationIdTextField:
  357. self.verificationIdErrorLabel.isHidden = true
  358. showVerificationIdTypePicker()
  359. // show list of verificationId type
  360. return false
  361. case sourceOfFundTextField:
  362. // show source of fund picker
  363. self.sourceOfFundErrorLabel.isHidden = true
  364. self.showSourceOfFundPicker()
  365. return false
  366. default:
  367. return true
  368. }
  369. }
  370. func textFieldDidBeginEditing(_ textField: UITextField) {
  371. textField.layer.addShadow(with: Constants.clearColor)
  372. textField.layer.borderWidth = 0
  373. switch textField {
  374. case accountNumberTextField:
  375. accountNumberErrorLabel.isHidden = true
  376. case verificationIdNumberTextField:
  377. verificationIdNumberErrorLabel.isHidden = true
  378. case expiryDateTextField:
  379. expiryDateErrorLabel.isHidden = true
  380. case issueDateTextField:
  381. issueDateErrorLabel.isHidden = true
  382. default:
  383. break
  384. }
  385. }
  386. }
  387. extension KycForm2ViewController {
  388. private func showBankPickerView() {
  389. let viewcontroller = self.getPickerViewController()
  390. let banks = self.banks ?? []
  391. let names = banks.compactMap({$0.text})
  392. viewcontroller.data = names
  393. viewcontroller.type = PickerTitle.bank
  394. viewcontroller.doneAction = self.bankSelected
  395. self.present(viewcontroller, animated: true, completion: nil)
  396. }
  397. private func getPickerViewController()-> ItemsPickerViewController {
  398. return UIStoryboard.init(name: "ItemsPicker", bundle: nil).instantiateViewController(withIdentifier: "ItemsPickerViewController") as! ItemsPickerViewController
  399. }
  400. func bankSelected(banks: [String]) {
  401. let _bank = self.banks?.filter({($0.text ?? "") == (banks.first ?? "") }).first
  402. self.selectedBank = _bank
  403. }
  404. private func showVerificationIdTypePicker() {
  405. let viewcontroller = self.getPickerViewController()
  406. let models = self.verificationIdTypes ?? []
  407. let names = models.compactMap({$0.text})
  408. viewcontroller.data = names
  409. viewcontroller.type = PickerTitle.verificationIdTypes
  410. viewcontroller.doneAction = self.cardTypeSelected
  411. self.present(viewcontroller, animated: true, completion: nil)
  412. }
  413. func cardTypeSelected(models: [String]) {
  414. let _model = self.verificationIdTypes?.filter({($0.text ?? "") == (models.first ?? "") }).first
  415. self.selectedVerificationIdType = _model
  416. }
  417. private func showSourceOfFundPicker() {
  418. let viewcontroller = self.getPickerViewController()
  419. let models = self.sourceOfFunds ?? []
  420. let names = models.compactMap({$0.text})
  421. viewcontroller.data = names
  422. viewcontroller.type = PickerTitle.sourceOfFund
  423. viewcontroller.doneAction = self.sourceOfFundSelected
  424. self.present(viewcontroller, animated: true, completion: nil)
  425. }
  426. func sourceOfFundSelected(models: [String]) {
  427. let _model = self.sourceOfFunds?.filter({($0.text ?? "") == (models.first ?? "") }).first
  428. self.selectedSourceOfFund = _model
  429. }
  430. }