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.
 
 
 
 

554 lines
22 KiB

//
// SetupRecipientViewController.swift
// GME Remit
//
// Created by InKwon James Kim on 09/08/2019.
//Copyright © 2019 Gobal Money Express Co. Ltd. All rights reserved.
//
import UIKit
import RxSwift
import RxCocoa
enum DynamicFieldRequire: String {
case mandatory = "M"
case optional = "O"
case hidden = "H"
}
class SetupRecipientViewController: UIViewController {
// MARK: Properties
var viewModel: SetupRecipientViewModel!
weak var delegate: SetupRecipientDelegate?
private var dynamicFieldDic: [String: ValidationTextField]?
private let disposeBag = DisposeBag()
// MARK: Computed Properties
// MARK: IBOutlets
@IBOutlet private weak var countryTextField: ValidationTextField!
@IBOutlet private weak var paymentModeTextField: ValidationTextField!
@IBOutlet private weak var countryContainerView: ShadowView!
@IBOutlet private weak var recipientBankInfomationContainerView: UIView!
@IBOutlet private weak var recipientInformationContainerView: UIStackView!
@IBOutlet private weak var idContainerView: ShadowView!
@IBOutlet private weak var addressContainerView: ShadowView!
@IBOutlet private weak var otherContainerView: ShadowView!
@IBOutlet private weak var bankTextField: ValidationTextField!
@IBOutlet private weak var branchTextField: ValidationTextField!
@IBOutlet private weak var accountTextField: ValidationTextField!
@IBOutlet private weak var idTextField: ValidationTextField!
@IBOutlet private weak var idNumberTextField: ValidationTextField!
@IBOutlet private weak var firstNameTextField: ValidationTextField!
@IBOutlet private weak var middleNameTextField: ValidationTextField!
@IBOutlet private weak var lastNameTextField: ValidationTextField!
@IBOutlet private weak var fullNameTextField: ValidationTextField!
@IBOutlet private weak var firstNameLocalTextField: ValidationTextField!
@IBOutlet private weak var middleNameLocalTextField: ValidationTextField!
@IBOutlet private weak var lastNameLocalTextField: ValidationTextField!
@IBOutlet private weak var fullNameLocalTextField: ValidationTextField!
@IBOutlet private weak var nativeCountryTextField: ValidationTextField!
@IBOutlet private weak var mobileTextField: ValidationTextField!
@IBOutlet private weak var emailTextField: ValidationTextField!
@IBOutlet private weak var stateProvinceTextField: ValidationTextField!
@IBOutlet private weak var districtTextField: ValidationTextField!
@IBOutlet private weak var cityTextField: ValidationTextField!
@IBOutlet private weak var addressTextField: ValidationTextField!
@IBOutlet private weak var relationTextField: ValidationTextField!
@IBOutlet private weak var reasonTextField: ValidationTextField!
@IBOutlet private weak var saveButton: UIButton!
// MARK: VC's Life cycle
override func viewDidLoad() {
super.viewDidLoad()
setup()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
title = "recipient_text".localized()
setupNormalNavigation()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
view.endEditing(true)
}
// MARK: IBActions
@IBAction func touchCloseButton(_ sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}
}
// MARK: Other Functions
extension SetupRecipientViewController {
private func setup() {
// all setup should be done here
countryContainerView.hero.id = "setupRecipient"
countryContainerView.hero.modifiers = [.fade, .scale(0.2)]
setUI()
setMultiLanguage()
setBinding()
}
private func setMultiLanguage() {
countryTextField.titleText = "country_text".localized()
nativeCountryTextField.titleText = "native_country_text".localized()
paymentModeTextField.titleText = "payment_mode_text".localized()
bankTextField.titleText = "bank_text".localized()
branchTextField.titleText = "branch_text".localized()
accountTextField.titleText = "account_text".localized()
firstNameTextField.titleText = "first_name_text".localized()
middleNameTextField.titleText = "middle_name_text".localized()
lastNameTextField.titleText = "last_name_text".localized()
fullNameTextField.titleText = "full_name_text".localized()
firstNameLocalTextField.titleText = "first_name_local_text".localized()
middleNameLocalTextField.titleText = "middle_name_local_text".localized()
lastNameLocalTextField.titleText = "last_name_local_text".localized()
fullNameLocalTextField.titleText = "full_name_local_text".localized()
idTextField.titleText = "id_type_text".localized()
idNumberTextField.titleText = "id_number_text".localized()
mobileTextField.titleText = "mobile_text".localized()
emailTextField.titleText = "email_text".localized()
stateProvinceTextField.titleText = "state_province_text".localized()
districtTextField.titleText = "district_text".localized()
cityTextField.titleText = "city_text".localized()
addressTextField.titleText = "address_text".localized()
relationTextField.titleText = "relation_text".localized()
reasonTextField.titleText = "reason_text".localized()
countryTextField.placeholder = "country_placeholder_text".localized()
nativeCountryTextField.placeholder = "native_country_placeholder_text".localized()
paymentModeTextField.placeholder = "payment_mode_placeholder_text".localized()
bankTextField.placeholder = "bank_placeholder_text".localized()
branchTextField.placeholder = "branch_placeholder_text".localized()
accountTextField.placeholder = "account_placeholder_text".localized()
firstNameTextField.placeholder = "first_name_placeholder_text".localized()
middleNameTextField.placeholder = "middle_name_placeholder_text".localized()
lastNameTextField.placeholder = "last_name_placeholder_text".localized()
fullNameTextField.placeholder = "full_name_placeholder_text".localized()
firstNameLocalTextField.placeholder = "first_name_local_placeholder_text".localized()
middleNameLocalTextField.placeholder = "middle_name_local_placeholder_text".localized()
lastNameLocalTextField.placeholder = "last_name_local_placeholder_text".localized()
fullNameLocalTextField.placeholder = "full_name_local_placeholder_text".localized()
idTextField.placeholder = "id_type_placeholder_text".localized()
idNumberTextField.placeholder = "id_number_placeholder_text".localized()
mobileTextField.placeholder = "mobile_placeholder_text".localized()
emailTextField.placeholder = "email_placeholder_text".localized()
stateProvinceTextField.placeholder = "stateProvince_placeholder_text".localized()
districtTextField.placeholder = "district_placeholder_text".localized()
cityTextField.placeholder = "city_placeholder_text".localized()
addressTextField.placeholder = "address_placeholder_text".localized()
relationTextField.placeholder = "relation_placeholder_text".localized()
reasonTextField.placeholder = "reason_placeholder_text".localized()
saveButton.setTitle("save_text".localized(), for: .normal)
}
private func setSelectTextFields(of textFields: [UITextField]) {
textFields.forEach {
$0.inputView = UIView()
$0.keyboardToolbar.isHidden = true
}
}
private func setUI() {
saveButton.layer.cornerRadius = 5
countryTextField.statusImageView.isHidden = true
paymentModeTextField.statusImageView.isHidden = true
paymentModeTextField.isHidden = true
paymentModeTextField.alpha = 0
setSelectTextFields(of:[
countryTextField, paymentModeTextField, bankTextField, branchTextField,
idTextField, stateProvinceTextField, districtTextField, relationTextField, reasonTextField,
nativeCountryTextField
]
)
recipientBankInfomationContainerView.isHidden = true
recipientBankInfomationContainerView.alpha = 0
recipientInformationContainerView.isHidden = true
recipientInformationContainerView.alpha = 0
recipientBankInfomationContainerView.travelSubView { (view, _) in
if let textField = view as? ValidationTextField {
textField.statusImageView.isHidden = true
textField.isHidden = true
}
}
recipientInformationContainerView.travelSubView { (view, _) in
if let textField = view as? ValidationTextField {
textField.statusImageView.isHidden = true
textField.isHidden = true
}
}
dynamicFieldDic = [
"Bank Name": bankTextField,
"Branch Name": branchTextField,
"Account No.": accountTextField,
"First Name": firstNameTextField,
"Middle Name": middleNameTextField,
"Last Name": lastNameTextField,
"Full Name": fullNameTextField,
"First Name in Local": firstNameLocalTextField,
"Middle Name in Local": middleNameLocalTextField,
"Last Name in Local": lastNameLocalTextField,
"Local Name": fullNameLocalTextField,
"Native Country": nativeCountryTextField,
"Id Type": idTextField,
"ID Number": idNumberTextField,
"Mobile Number": mobileTextField,
"Email": emailTextField,
"Province": stateProvinceTextField,
"District": districtTextField,
"City": cityTextField,
"Address": addressTextField,
"Realation Group": relationTextField,
"Transfer Reason": reasonTextField
]
}
private func setBinding() {
let viewWillAppear = rx.sentMessage(#selector(UIViewController.viewWillAppear(_:)))
.mapToVoid()
.asDriverOnErrorJustComplete()
let saveTrigger = saveButton.rx.tap.flatMap { [weak self] _ -> Observable<Recipient> in
var recipient = Recipient()
recipient.firstName = self?.firstNameTextField.text
recipient.middleName = self?.middleNameTextField.text
recipient.lastName = self?.lastNameTextField.text
recipient.localFirstName = self?.firstNameLocalTextField.text
recipient.localMiddleName = self?.middleNameLocalTextField.text
recipient.localLastName = self?.lastNameLocalTextField.text
recipient.fullName = self?.fullNameTextField.text
recipient.localFullName = self?.fullNameLocalTextField.text
recipient.address = self?.addressTextField.text
recipient.city = self?.cityTextField.text
recipient.email = self?.emailTextField.text
recipient.mobile = self?.mobileTextField.mobileNumberText
recipient.idNumber = self?.idNumberTextField.text
recipient.agent?.accountNumber = self?.accountTextField.text
return Observable.just(recipient)
}.asDriverOnErrorJustComplete()
let input = SetupRecipientViewModel.Input(
initialTrigger: viewWillAppear,
openCountryTrigger: countryTextField.rx.controlEvent(.editingDidBegin).asDriver(),
openPaymentTrigger: paymentModeTextField.rx.controlEvent(.editingDidBegin).asDriver(),
openBankTrigger: bankTextField.rx.controlEvent(.editingDidBegin).asDriver(),
openBranchTrigger: branchTextField.rx.controlEvent(.editingDidBegin).asDriver(),
openIDTypeTrigger: idTextField.rx.controlEvent(.editingDidBegin).asDriver(),
openStateProvinceTrigger: stateProvinceTextField.rx.controlEvent(.editingDidBegin).asDriver(),
openDistrictTrigger: districtTextField.rx.controlEvent(.editingDidBegin).asDriver(),
openRelationTrigger: relationTextField.rx.controlEvent(.editingDidBegin).asDriver(),
openReasonTrigger: reasonTextField.rx.controlEvent(.editingDidBegin).asDriver(),
openNativeCountryTrigger: nativeCountryTextField.rx.controlEvent(.editingDidBegin).asDriver(),
saveTrigger: saveTrigger
)
let output = viewModel.transform(input: input)
output.isError
.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.alert(type: .error, message: $0.localizedDescription)
})
.disposed(by: disposeBag)
output.isProgress
.drive(onNext: { [weak self] in guard let `self` = self else { return }
$0 ? self.showProgressHud() : self.hideProgressHud()
})
.disposed(by: disposeBag)
output.success
.drive(onNext: { successObject in
let message = "recipient_add_success_message_text".localized().replacingOccurrences(
of: "xxx",
with: successObject.data?.fullName ?? ""
)
self.alertWithOkCancel(
type: .normal,
message: "\(successObject.message ?? "")\n\(message)",
title: "success_text".localized(),
okTitle: "yes_text".localized(),
cancelTitle: "no_text".localized(),
okAction: { [weak self] in guard let `self` = self else { return }
self.dismiss(animated: true) { [weak self] in guard let `self` = self else { return }
self.delegate?.setupRecieient(
self,
didSelectRecipientID: successObject.data?.receiverID ?? ""
)
}
},
cancelAction: { [weak self] in guard let `self` = self else { return }
self.dismiss(animated: true) { [weak self] in guard let `self` = self else { return }
self.delegate?.setupRecieient(
self,
didSelectRecipientID: nil
)
}
})
}).disposed(by: disposeBag)
bindUI(output: output)
}
private func bindUI(output: SetupRecipientViewModel.Output) {
output.selectedRecipient
.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.setText(with: $0)
}).disposed(by: disposeBag)
output.selectedCountry
.drive(onNext: { [weak self] in guard let `self` = self else { return }
guard let country = $0 else { return }
self.countryTextField.text = country.countryName
self.countryTextField.setCountry(with: country.countryCode, isShowCode: false)
self.countryTextField.sendActions(for: .editingChanged)
self.mobileTextField.setCountry(with: country.countryCode)
self.paymentModeTextField.animateHidden(isHidden: false, duration: 0.5)
self.recipientBankInfomationContainerView.animateHidden(isHidden: true, duration: 0.5)
self.recipientInformationContainerView.animateHidden(isHidden: true, duration: 0.5)
}).disposed(by: disposeBag)
output.selectedPaymentMode.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.paymentModeTextField.text = $0?.subtitle
self.paymentModeTextField.sendActions(for: .editingChanged)
}).disposed(by: disposeBag)
output.selectedBank.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.bankTextField.text = $0?.name
self.bankTextField.sendActions(for: .editingChanged)
if $0?.branchRequired?.lowercased() == "false" {
self.branchTextField.isHidden = true
self.branchTextField.text = ""
self.branchTextField.valid.onNext(true)
} else {
self.branchTextField.isHidden = false
self.branchTextField.valid.onNext(false)
}
if $0?.accountRequired?.lowercased() == "false" {
self.accountTextField.isHidden = true
self.accountTextField.text = ""
self.accountTextField.valid.onNext(true)
} else {
self.accountTextField.isHidden = false
if self.accountTextField.text != "" {
self.accountTextField.valid.onNext(true)
} else {
self.accountTextField.valid.onNext(false)
}
}
}).disposed(by: disposeBag)
output.selectedBranch.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.branchTextField.text = $0?.name
self.branchTextField.sendActions(for: .editingChanged)
}).disposed(by: disposeBag)
output.selectedIDType.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.idTextField.text = $0?.text
self.idTextField.sendActions(for: .editingChanged)
}).disposed(by: disposeBag)
output.selectedStateProvince.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.stateProvinceTextField.text = $0?.name
self.stateProvinceTextField.sendActions(for: .editingChanged)
let count = $0?.districts?.count ?? 0
if count == 0 {
self.districtTextField.isHidden = true
self.districtTextField.valid.onNext(true)
} else {
self.districtTextField.isHidden = false
self.districtTextField.valid.onNext(false)
}
}).disposed(by: disposeBag)
output.selectedDistrict.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.districtTextField.text = $0?.name
self.districtTextField.sendActions(for: .editingChanged)
}).disposed(by: disposeBag)
output.selectedRelation.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.relationTextField.text = $0?.title
self.relationTextField.sendActions(for: .editingChanged)
}).disposed(by: disposeBag)
output.selectedReason.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.reasonTextField.text = $0?.title
self.reasonTextField.sendActions(for: .editingChanged)
}).disposed(by: disposeBag)
output.selectedNativeCountry.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.nativeCountryTextField.text = $0?.text
self.nativeCountryTextField.sendActions(for: .editingChanged)
}).disposed(by: disposeBag)
output.models.dynamicFieldsModel.drive(onNext: { [weak self] in guard let `self` = self else { return }
self.setDynamicFields(dynamicFieldInfo: $0)
self.recipientBankInfomationContainerView.animateHidden(isHidden: false, duration: 0.5)
self.recipientInformationContainerView.animateHidden(isHidden: false, duration: 0.5)
}).disposed(by: disposeBag)
}
private func setDynamicFields(dynamicFieldInfo: [FieldModel]?) {
dynamicFieldInfo?.forEach { [weak self] property in
guard let `self` = self else { return }
guard
let key = property.fieldName,
let textField = self.dynamicFieldDic?[key],
let isRequire = DynamicFieldRequire(rawValue: property.required ?? ""),
let min = property.minLength,
let max = property.maxLength,
let keyboardType = property.keyBoardType else { return }
textField.errorMessage = "general_length_error_text".localized().replacingOccurrences(
of: "xxx",
with: "\(min)"
).replacingOccurrences(of: "ooo", with: "\(max)")
switch isRequire {
case .mandatory:
textField.isHidden = false
if max == min && min == -1 {
textField.validCondition = { !$0.isEmpty }
textField.errorMessage = nil
} else {
textField.validCondition = { ($0.count >= min && $0.count <= max) && !$0.isEmpty }
}
case .optional:
textField.isHidden = false
if max == min && min == -1 {
textField.validCondition = nil
textField.errorMessage = nil
} else {
textField.validCondition = { ($0.count >= min && $0.count <= max) }
}
if !textField.titleText.contains("optional_hint_text".localized()) {
textField.titleText += "optional_hint_text".localized()
textField.placeholder = "\(textField.placeholder ?? "") \("optional_hint_text".localized())"
}
case .hidden:
textField.isHidden = true
textField.text = ""
}
if key.contains("Local") {
textField.keyboardType = .default
} else {
let keyType = GMEKeyboardType(rawValue: keyboardType) ?? GMEKeyboardType.alphabetNumbericSpecial
switch keyType {
case .numberic: textField.keyboardType = .numberPad
default: textField.keyboardType = .asciiCapable
}
textField.rx.controlEvent(.editingChanged).asDriver()
.drive(onNext: { _ in
switch keyType {
case .numberic: textField.fitlerBy(type: .alphabetNumberic, isSendAction: false)
default: textField.fitlerBy(type: keyType, isSendAction: false)
}
}).disposed(by: disposeBag)
}
}
guard let isValids = self.dynamicFieldDic?.values.filter({!$0.isHidden}).compactMap({$0.valid})
else {return}
Observable
.combineLatest(isValids).flatMap {
Observable.just($0.allSatisfy {$0})
}
.bind { [weak self] in guard let `self` = self else { return }
self.saveButton.isEnabled = $0
self.saveButton.backgroundColor = $0 ? .themeRed : .lightGray
}
.disposed(by: disposeBag)
idContainerView.isHidden = idTextField.isHidden && idNumberTextField.isHidden
addressContainerView.isHidden = stateProvinceTextField.isHidden &&
districtTextField.isHidden &&
cityTextField.isHidden &&
addressTextField.isHidden
otherContainerView.isHidden = mobileTextField.isHidden &&
emailTextField.isHidden &&
relationTextField.isHidden &&
reasonTextField.isHidden
}
private func setText(with recipient: Recipient?) {
fullNameTextField.text = recipient?.fullName
fullNameTextField.sendActions(for: .editingChanged)
firstNameTextField.text = recipient?.firstName
firstNameTextField.sendActions(for: .editingChanged)
middleNameTextField.text = recipient?.middleName
middleNameTextField.sendActions(for: .editingChanged)
lastNameTextField.text = recipient?.lastName
lastNameTextField.sendActions(for: .editingChanged)
fullNameLocalTextField.text = recipient?.localFullName
fullNameLocalTextField.sendActions(for: .editingChanged)
firstNameLocalTextField.text = recipient?.localFirstName
firstNameLocalTextField.sendActions(for: .editingChanged)
middleNameLocalTextField.text = recipient?.localMiddleName
middleNameLocalTextField.sendActions(for: .editingChanged)
lastNameLocalTextField.text = recipient?.localLastName
lastNameLocalTextField.sendActions(for: .editingChanged)
accountTextField.text = recipient?.agent?.accountNumber
accountTextField.sendActions(for: .editingChanged)
idNumberTextField.text = recipient?.idNumber
idNumberTextField.sendActions(for: .editingChanged)
emailTextField.text = recipient?.email
emailTextField.sendActions(for: .editingChanged)
mobileTextField.setCoutryFlag(with: recipient?.countryCode)
mobileTextField.mobileNumberText = recipient?.mobile
mobileTextField.sendActions(for: .editingChanged)
addressTextField.text = recipient?.address
addressTextField.sendActions(for: .editingChanged)
cityTextField.text = recipient?.city
cityTextField.sendActions(for: .editingChanged)
}
}