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.

583 lines
21 KiB

6 years ago
6 years ago
6 years ago
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. struct StringConstants {
  49. let headerTitle = "security_subtitle_text".localized()
  50. let primaryBankTitle = "primary_bank_text".localized()
  51. let primaryBankPlaceholder = "primary_bank_placeholder_text".localized()
  52. let accountTitle = "primary_account_number_text".localized()
  53. let accountPlaceholder = "privary_account_number_placeholder".localized()
  54. let verificationIdTitle = "verification_id_type_text".localized()
  55. let verificationIdPlaceholder = "verification_id_placeholder_text".localized()
  56. let verificationNumberTitle = "verification_id_no_text".localized()
  57. let verificationNumberPlaceholder = "verification_id_no_placeholder_text".localized()
  58. let issueDateTittle = "Issue Date".localized()
  59. let issueDatePlaceholder = "select_issue_date_text".localized()
  60. let expiryDateTitle = "expiry_date_title".localized()
  61. let expiryDatePlaceholder = "select_expiry_date_text".localized()
  62. let sourceOfFundTitle = "source_of_fund_text".localized()
  63. let sourceOfFundPlaceholder = "source_of_fund_placeholder_text".localized()
  64. let saveAndContinue = "save_and_continue_text".localized()
  65. }
  66. // MARK: IBOutlets
  67. // labels
  68. @IBOutlet weak var bankErrorLabel: UILabel!
  69. @IBOutlet weak var accountNumberErrorLabel: UILabel!
  70. @IBOutlet weak var verificationIdErrorLabel: UILabel!
  71. @IBOutlet weak var verificationIdNumberErrorLabel: UILabel!
  72. @IBOutlet weak var expiryDateErrorLabel: UILabel!
  73. @IBOutlet weak var sourceOfFundErrorLabel: UILabel!
  74. @IBOutlet weak var issueDateErrorLabel: UILabel!
  75. // title labels
  76. @IBOutlet weak var bankTitleLabel: UILabel!
  77. @IBOutlet weak var accountNumberTitleLabel: UILabel!
  78. @IBOutlet weak var verificationIdTitleLabel: UILabel!
  79. @IBOutlet weak var verificationIdNumberTitleLabel: UILabel!
  80. @IBOutlet weak var expiryDateTitleLabel: UILabel!
  81. @IBOutlet weak var sourceOfFundTitleLabel: UILabel!
  82. @IBOutlet weak var issueDateTitleLabel: UILabel!
  83. @IBOutlet weak var headerTitleLabel: UILabel!
  84. // textfields
  85. @IBOutlet weak var bankTextField: UITextField!
  86. @IBOutlet weak var accountNumberTextField: UITextField!
  87. @IBOutlet weak var verificationIdTextField: UITextField!
  88. @IBOutlet weak var verificationIdNumberTextField: UITextField!
  89. @IBOutlet weak var expiryDateTextField: UITextField!
  90. @IBOutlet weak var sourceOfFundTextField: UITextField!
  91. @IBOutlet weak var issueDateTextField: UITextField!
  92. // stackViews
  93. @IBOutlet weak var expiryDateStackView: UIStackView!
  94. @IBOutlet weak var issueDateStackView: UIStackView!
  95. @IBOutlet weak var saveAndContinueButton: UIButton!
  96. // MARK: Properties
  97. var errorLabels: [UILabel] = []
  98. var textfields: [UITextField] = []
  99. var errorTextFieldDict: [String: UITextField] = [:]
  100. var errorLabelsDict: [String: UILabel] = [:]
  101. var hiddenFieldsDict: [String: UIStackView]?
  102. var hiddenFields: [UIStackView]?
  103. var kycModel: KycModel? {
  104. didSet {
  105. self.banks = kycModel?.bank
  106. self.verificationIdTypes = kycModel?.idType
  107. self.sourceOfFunds = kycModel?.sourceOfFund
  108. }
  109. }
  110. var verificationIdSelectedCardType: KycVerificationIdType = .passport {
  111. didSet {
  112. switch verificationIdSelectedCardType {
  113. case .alieanCard, .nationalIdCard:
  114. self.verificationIdNumberTextField.keyboardType = .numberPad
  115. self.verificationIdNumberTextField.addTarget(self, action: #selector(self.verificationIdTextChanged(sender:)
  116. ), for: UIControlEvents.editingChanged)
  117. break
  118. case .passport:
  119. self.verificationIdNumberTextField.keyboardType = .default
  120. self.verificationIdNumberTextField.removeTarget(self, action: #selector(self.verificationIdTextChanged(sender:)
  121. ), for: UIControlEvents.editingChanged)
  122. break
  123. }
  124. }
  125. }
  126. var banks: [KeyValueModel]?
  127. var verificationIdTypes: [VerificationIdType]? {
  128. didSet {
  129. }
  130. }
  131. var sourceOfFunds:[KeyValueModel]?
  132. var selectedBank: KeyValueModel? {
  133. didSet {
  134. self.bankTextField.text = selectedBank?.text
  135. self.kycForm2Model.bank = selectedBank?.id ?? ""
  136. }
  137. }
  138. var selectedVerificationIdType: VerificationIdType? {
  139. didSet {
  140. self.verificationIdTextField.text = self.selectedVerificationIdType?.text
  141. self.kycForm2Model.verificationId = self.selectedVerificationIdType?.id ?? ""
  142. var _views: [UIStackView] = []
  143. _views = (self.selectedVerificationIdType?.dependent ?? []).compactMap({
  144. print($0)
  145. return self.hiddenFieldsDict?[$0]
  146. })
  147. self.hiddenFields?.forEach({
  148. if _views.contains($0) {
  149. self.kycForm2Model.checkIssueDate = $0.tag == Constants.issueDateTag
  150. self.kycForm2Model.checkExpiryDate = $0.tag == Constants.expiryDateTag
  151. $0.isHidden = false
  152. }else {
  153. $0.isHidden = true
  154. }
  155. })
  156. if selectedVerificationIdType?.text != oldValue?.text {
  157. self.verificationIdNumberTextField.text = ""
  158. }
  159. if let type = KycVerificationIdType.init(rawValue: selectedVerificationIdType?.text ?? "") {
  160. self.verificationIdSelectedCardType = type
  161. }
  162. }
  163. }
  164. var selectedSourceOfFund : KeyValueModel? {
  165. didSet {
  166. self.sourceOfFundTextField.text = selectedSourceOfFund?.text
  167. self.kycForm2Model.sourceOfFund = selectedSourceOfFund?.id ?? ""
  168. }
  169. }
  170. var delegate: KYCForm2Delegate?
  171. var presenter: KycForm2ModuleInterface?
  172. var continueActionInitiated = false
  173. var kycForm2Model: KycForm2Model = KycForm2Model()
  174. let expiaryDatePicker = UIDatePicker()
  175. let issueDatePicker = UIDatePicker()
  176. // MARK: VC's Life cycle
  177. override func viewDidLoad() {
  178. super.viewDidLoad()
  179. self.setup()
  180. }
  181. override func viewWillDisappear(_ animated: Bool) {
  182. super.viewWillDisappear(animated)
  183. continueActionInitiated = false
  184. validate()
  185. }
  186. // MARK: IBActions
  187. @IBAction func _continue(_ sender: UIButton) {
  188. continueActionInitiated = true
  189. self.delegate?._continue(model: self.kycForm2Model)
  190. }
  191. // MARK: Other Functions
  192. private func createModel() {
  193. self.kycForm2Model.accountNumber = self.accountNumberTextField.text!
  194. self.kycForm2Model.verificationIdNumber = self.verificationIdNumberTextField.text!
  195. self.kycForm2Model.expiryDate = self.expiryDateTextField.text!
  196. self.kycForm2Model.issueDate = self.issueDateTextField.text!
  197. }
  198. private func setup() {
  199. // all setup should be done here
  200. hideErrorLabels()
  201. setupErrorLabels()
  202. setupErrorTextFields()
  203. setupDatePicker()
  204. setupDelegates()
  205. setupHiddenFields()
  206. configureLanugage()
  207. }
  208. private func configureLanugage() {
  209. self.bankTitleLabel.text = StringConstants().primaryBankTitle
  210. self.bankTextField.placeholder = StringConstants().primaryBankPlaceholder
  211. self.accountNumberTitleLabel.text = StringConstants().accountTitle
  212. self.accountNumberTextField.placeholder = StringConstants().accountPlaceholder
  213. self.verificationIdTitleLabel.text = StringConstants().verificationIdTitle
  214. self.verificationIdTextField.placeholder = StringConstants().verificationIdPlaceholder
  215. self.verificationIdNumberTitleLabel.text = StringConstants().verificationNumberTitle
  216. self.verificationIdNumberTextField.placeholder = StringConstants().verificationNumberPlaceholder
  217. self.issueDateTitleLabel.text = StringConstants().issueDateTittle
  218. self.issueDateTextField.placeholder = StringConstants().issueDatePlaceholder
  219. self.expiryDateTitleLabel.text = StringConstants().expiryDateTitle
  220. self.expiryDateTextField.placeholder = StringConstants().expiryDatePlaceholder
  221. self.sourceOfFundTitleLabel.text = StringConstants().sourceOfFundTitle
  222. self.sourceOfFundTextField.placeholder = StringConstants().sourceOfFundPlaceholder
  223. self.headerTitleLabel.text = StringConstants().headerTitle
  224. self.saveAndContinueButton.setTitle("save_and_continue_text".localized(), for: UIControlState.normal)
  225. }
  226. private func setupHiddenFields() {
  227. self.hiddenFields = [issueDateStackView, expiryDateStackView]
  228. issueDateStackView.tag = Constants.issueDateTag
  229. expiryDateStackView.tag = Constants.expiryDateTag
  230. self.hiddenFieldsDict = [
  231. Constants.issueDateText : issueDateStackView,
  232. Constants.expiryDateText: expiryDateStackView
  233. ]
  234. self.hiddenFieldsDict?.forEach({
  235. $0.value.isHidden = true
  236. })
  237. }
  238. private func validate() {
  239. createModel()
  240. self.delegate?.addModel(model: self.kycForm2Model)
  241. }
  242. @objc private func verificationIdTextChanged(sender: UITextField) {
  243. }
  244. private func setupDelegates() {
  245. self.bankTextField.delegate = self
  246. self.accountNumberTextField.delegate = self
  247. self.verificationIdTextField.delegate = self
  248. self.verificationIdNumberTextField.delegate = self
  249. self.expiryDateTextField.delegate = self
  250. self.issueDateTextField.delegate = self
  251. self.sourceOfFundTextField.delegate = self
  252. }
  253. private func setupDatePicker() {
  254. self.expiaryDatePicker.datePickerMode = .date
  255. self.expiryDateTextField.inputView = expiaryDatePicker
  256. self.expiaryDatePicker.addTarget(self, action: #selector(handleExpiryDatePicker), for: .valueChanged)
  257. self.issueDatePicker.datePickerMode = .date
  258. self.issueDateTextField.inputView = issueDatePicker
  259. issueDatePicker.maximumDate = Date()
  260. self.issueDatePicker.addTarget(self, action: #selector(handleIssueDatePicker), for: .valueChanged)
  261. }
  262. @objc private func handleIssueDatePicker(sender: UIDatePicker) {
  263. let dateFormatter = DateFormatter()
  264. let date = sender.date
  265. expiaryDatePicker.minimumDate = date
  266. dateFormatter.dateFormat = AppConstants.dateFormat
  267. // test ccr
  268. self.issueDateTextField.text = dateFormatter.string(from: sender.date)
  269. }
  270. @objc private func handleExpiryDatePicker(sender: UIDatePicker) {
  271. let dateFormatter = DateFormatter()
  272. // test ccr
  273. dateFormatter.dateFormat = AppConstants.dateFormat
  274. self.expiryDateTextField.text = dateFormatter.string(from: sender.date)
  275. }
  276. private func hideErrorLabels() {
  277. [bankErrorLabel, accountNumberErrorLabel, verificationIdErrorLabel, verificationIdNumberErrorLabel, expiryDateErrorLabel, issueDateErrorLabel, sourceOfFundErrorLabel].forEach({
  278. $0?.isHidden = true
  279. })
  280. }
  281. private func setupErrorLabels() {
  282. self.errorLabels = [bankErrorLabel, accountNumberErrorLabel, verificationIdErrorLabel, verificationIdNumberErrorLabel, expiryDateErrorLabel,issueDateErrorLabel, sourceOfFundErrorLabel]
  283. self.errorLabels.forEach({
  284. $0.font = Constants.errorFont
  285. })
  286. self.errorLabelsDict =
  287. [
  288. KycForm2FieldKeys.bank: self.bankErrorLabel,
  289. KycForm2FieldKeys.accountNumber: self.accountNumberErrorLabel,
  290. KycForm2FieldKeys.verificationId: self.verificationIdErrorLabel,
  291. KycForm2FieldKeys.verificationIdNumber: self.verificationIdNumberErrorLabel,
  292. KycForm2FieldKeys.expiryDate: self.expiryDateErrorLabel,
  293. KycForm2FieldKeys.sourceOfFund: self.sourceOfFundErrorLabel,
  294. KycForm2FieldKeys.issueDate: self.issueDateErrorLabel
  295. ]
  296. }
  297. private func setupErrorTextFields() {
  298. self.textfields = [bankTextField, accountNumberTextField, verificationIdTextField, verificationIdNumberTextField, expiryDateTextField, sourceOfFundTextField]
  299. bankTextField.tag = 12
  300. accountNumberTextField.tag = 13
  301. verificationIdNumberTextField.tag = 14
  302. expiryDateTextField.tag = 15
  303. issueDateTextField.tag = 16
  304. sourceOfFundTextField.tag = 17
  305. self.errorTextFieldDict =
  306. [
  307. KycForm2FieldKeys.bank: self.bankTextField,
  308. KycForm2FieldKeys.accountNumber: self.accountNumberTextField,
  309. KycForm2FieldKeys.verificationId: self.verificationIdTextField,
  310. KycForm2FieldKeys.verificationIdNumber: self.verificationIdNumberTextField,
  311. KycForm2FieldKeys.expiryDate: self.expiryDateTextField,
  312. KycForm2FieldKeys.sourceOfFund: self.sourceOfFundTextField
  313. ]
  314. }
  315. private func showBorder(textfield :UITextField?) {
  316. guard let textfield = textfield else {return}
  317. textfield.layer.borderColor = Constants.stateRedColor.cgColor
  318. textfield.layer.borderWidth = Constants.errorBorderSize
  319. textfield.layer.addShadow(with: Constants.stateRedColor)
  320. }
  321. private func show( error: String, label: UILabel?) {
  322. // scroll to the top of the view
  323. guard let label = label else {return}
  324. label.textColor = Constants.stateRedColor
  325. label.isHidden = false
  326. label.text = error
  327. }
  328. }
  329. // MARK: KycForm2ViewInterface
  330. extension KycForm2ViewController: KycForm2ViewInterface {
  331. func show(resut2: (isValid: Bool, errorsDick: [String : String])) {
  332. var position = 15
  333. if resut2.isValid { // if isValid
  334. // its is not valid, lets go to security page
  335. if self.continueActionInitiated {
  336. self.delegate?._continue(model: self.kycForm2Model)
  337. }
  338. }else {
  339. resut2.errorsDick.forEach({
  340. let label = errorLabelsDict[$0.key]
  341. self.show(error: $0.value, label: label)
  342. let textfield = errorTextFieldDict[$0.key]
  343. self.showBorder(textfield: textfield)
  344. let tag = (textfield?.tag ?? position)
  345. position = tag < position ? tag : position
  346. if self.textfields.filter({
  347. $0.tag == tag
  348. }).first != nil {
  349. // Todo
  350. // scroll to view here
  351. }
  352. })
  353. }
  354. }
  355. func show(error: String) {
  356. self.alert(message: error)
  357. }
  358. func showLoading() {
  359. self.showProgressHud()
  360. }
  361. func hideLoading() {
  362. self.hideProgressHud()
  363. }
  364. }
  365. extension KycForm2ViewController: IndicatorInfoProvider {
  366. func indicatorInfo(for pagerTabStripController: PagerTabStripViewController) -> IndicatorInfo {
  367. return IndicatorInfo.init(title: "security_titile_text".localized())
  368. }
  369. }
  370. extension KycForm2ViewController: UITextFieldDelegate {
  371. func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
  372. if textField == verificationIdNumberTextField && self.verificationIdSelectedCardType != .passport {
  373. let text = textField.text!
  374. if (range.length > 0)
  375. {
  376. // We're deleting
  377. if text.count < 7 {
  378. let newText = text.replacingOccurrences(of: "-", with: "")
  379. textField.text = newText
  380. }
  381. }
  382. else
  383. {
  384. var _text = text.replacingOccurrences(of: "-", with: "")
  385. if _text.count >= 6 {
  386. _text.insert("-", at: String.Index.init(encodedOffset: 6))
  387. textField.text = _text
  388. }
  389. // We're adding
  390. }
  391. }
  392. return true
  393. }
  394. func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
  395. textField.layer.addShadow(with: Constants.clearColor)
  396. textField.layer.borderWidth = 0
  397. switch textField {
  398. case bankTextField:
  399. // show bank picker
  400. showBankPickerView()
  401. self.bankErrorLabel.isHidden = true
  402. return false
  403. case verificationIdTextField:
  404. self.verificationIdErrorLabel.isHidden = true
  405. showVerificationIdTypePicker()
  406. // show list of verificationId type
  407. return false
  408. case sourceOfFundTextField:
  409. // show source of fund picker
  410. self.sourceOfFundErrorLabel.isHidden = true
  411. self.showSourceOfFundPicker()
  412. return false
  413. default:
  414. return true
  415. }
  416. }
  417. func textFieldDidBeginEditing(_ textField: UITextField) {
  418. textField.layer.addShadow(with: Constants.clearColor)
  419. textField.layer.borderWidth = 0
  420. switch textField {
  421. case accountNumberTextField:
  422. accountNumberErrorLabel.isHidden = true
  423. case verificationIdNumberTextField:
  424. verificationIdNumberErrorLabel.isHidden = true
  425. case expiryDateTextField:
  426. expiryDateErrorLabel.isHidden = true
  427. case issueDateTextField:
  428. issueDateErrorLabel.isHidden = true
  429. default:
  430. break
  431. }
  432. }
  433. }
  434. extension KycForm2ViewController {
  435. private func showBankPickerView() {
  436. let viewcontroller = self.getPickerViewController()
  437. let banks = self.banks ?? []
  438. let names = banks.compactMap({$0.text})
  439. viewcontroller.data = names
  440. viewcontroller.type = PickerTitle.bank
  441. viewcontroller.doneAction = self.bankSelected
  442. self.present(viewcontroller, animated: true, completion: nil)
  443. }
  444. private func getPickerViewController()-> ItemsPickerViewController {
  445. return UIStoryboard.init(name: "ItemsPicker", bundle: nil).instantiateViewController(withIdentifier: "ItemsPickerViewController") as! ItemsPickerViewController
  446. }
  447. func bankSelected(banks: [String]) {
  448. let _bank = self.banks?.filter({($0.text ?? "") == (banks.first ?? "") }).first
  449. self.selectedBank = _bank
  450. }
  451. private func showVerificationIdTypePicker() {
  452. let viewcontroller = self.getPickerViewController()
  453. let models = self.verificationIdTypes ?? []
  454. let names = models.compactMap({$0.text})
  455. viewcontroller.data = names
  456. viewcontroller.type = PickerTitle.verificationIdTypes
  457. viewcontroller.doneAction = self.cardTypeSelected
  458. self.present(viewcontroller, animated: true, completion: nil)
  459. }
  460. func cardTypeSelected(models: [String]) {
  461. let _model = self.verificationIdTypes?.filter({($0.text ?? "") == (models.first ?? "") }).first
  462. self.selectedVerificationIdType = _model
  463. }
  464. private func showSourceOfFundPicker() {
  465. let viewcontroller = self.getPickerViewController()
  466. let models = self.sourceOfFunds ?? []
  467. let names = models.compactMap({$0.text})
  468. viewcontroller.data = names
  469. viewcontroller.type = PickerTitle.sourceOfFund
  470. viewcontroller.doneAction = self.sourceOfFundSelected
  471. self.present(viewcontroller, animated: true, completion: nil)
  472. }
  473. func sourceOfFundSelected(models: [String]) {
  474. let _model = self.sourceOfFunds?.filter({($0.text ?? "") == (models.first ?? "") }).first
  475. self.selectedSourceOfFund = _model
  476. }
  477. }