// // SetupRecipientViewModel.swift // GME Remit // // Created by InKwon James Kim on 09/08/2019. //Copyright © 2019 Gobal Money Express Co. Ltd. All rights reserved. // import RxSwift import RxCocoa class SetupRecipientViewModel: ViewModelType { struct Input { let initialTrigger: Driver let openCountryTrigger: Driver let openPaymentTrigger: Driver let openBankTrigger: Driver let openBranchTrigger: Driver let openIDTypeTrigger: Driver let openStateProvinceTrigger: Driver let openDistrictTrigger: Driver let openRelationTrigger: Driver let openReasonTrigger: Driver let openNativeCountryTrigger: Driver let saveTrigger: Driver } struct Output { let isError: Driver let isProgress: Driver let success: Driver> let models: Models let selectedRecipient: Driver let selectedCountry: Driver let selectedPaymentMode: Driver let selectedBank: Driver let selectedBranch: Driver let selectedIDType: Driver let selectedStateProvince: Driver let selectedDistrict: Driver let selectedRelation: Driver let selectedReason: Driver let selectedNativeCountry: Driver } struct Models { let countryServicesModel: Driver<[CountryAndServiceModel]> let paymentModel: Driver<[PaymentServiceType]> let dynamicFieldsModel: Driver<[FieldModel]> } // Linker private let progressLinker = PublishSubject() private let errorLinker = PublishSubject() private let successLinker = PublishSubject>() private let dynamicFieldsLinker = PublishSubject<[FieldModel]>() // Models Linker private let countryServicesLinker = PublishSubject<[CountryAndServiceModel]>() private let paymentModeTypesLinker = PublishSubject<[PaymentServiceType]>() private let banksLinker = PublishSubject<[SendMoneyBank]>() private let idTypeLinker = PublishSubject<[ReceiverIdType]>() private let stateProvincesLinker = PublishSubject<[Provience]>() private let relationsLinker = PublishSubject<[Relation]>() private let reasonsLinker = PublishSubject<[TransferReason]>() private let nativeCountiresLinker = PublishSubject<[NativeCountryModel]>() // Selected Model Linker private let selectedRecipientLinker = BehaviorSubject(value: nil) private let selectedCountryServicesLinker = BehaviorSubject(value: nil) private let selectedPaymentModeTypesLinker = BehaviorSubject(value: nil) private let selectedBankLinker = BehaviorSubject(value: nil) private let selectedBranchLinker = BehaviorSubject(value: nil) private let selectedIDTypeLinker = BehaviorSubject(value: nil) private let selectedStateProvinceLinker = BehaviorSubject(value: nil) private let selectedDistrictLinker = BehaviorSubject(value: nil) private let selectedRelationLinker = BehaviorSubject(value: nil) private let selectedReasonLinker = BehaviorSubject(value: nil) private let selectedNativeCountryLinker = BehaviorSubject(value: nil) // Properties var presenter: SetupRecipientModuleInterface? var isFirst = true var payoutPartner: String? private let disposeBag = DisposeBag() func transform(input: Input) -> Output { let countryServicesModel = countryServicesLinker.asDriverOnErrorJustComplete() let paymentModeModel = paymentModeTypesLinker.asDriverOnErrorJustComplete() let dynamicModel = dynamicFieldsLinker.asDriverOnErrorJustComplete() let banksModel = banksLinker.asDriverOnErrorJustComplete() let idTypesModel = idTypeLinker.asDriverOnErrorJustComplete() let stateProvicesModel = stateProvincesLinker.asDriverOnErrorJustComplete() let relationsModel = relationsLinker.asDriverOnErrorJustComplete() let reasonsModel = reasonsLinker.asDriverOnErrorJustComplete() let branchesModel = Observable.combineLatest(selectedCountryServicesLinker, selectedBankLinker) .asDriverOnErrorJustComplete() let districtsModel = selectedStateProvinceLinker.flatMap {Observable.just($0?.districts ?? [])} .asDriverOnErrorJustComplete() let nativeCountrisModel = nativeCountiresLinker.asDriverOnErrorJustComplete() let model = Models( countryServicesModel: countryServicesModel, paymentModel: paymentModeModel, dynamicFieldsModel: dynamicModel ) // FetchCountriesAndServiceTypes input.initialTrigger.drive(onNext: { [weak self] in guard let `self` = self else { return } self.presenter?.fetchCountriesAndServiceTypes() }).disposed(by: disposeBag) // Handle open select country input.openCountryTrigger.withLatestFrom(countryServicesModel) {$1} .drive(onNext: { [weak self] in guard let `self` = self else { return } self.presenter?.openSelectMode(with: $0, type: .country) }).disposed(by: disposeBag) // Handle open select payment mode input.openPaymentTrigger.withLatestFrom(paymentModeModel) {$1} .drive(onNext: { [weak self] in guard let `self` = self else { return } self.presenter?.openSelectMode(with: $0, type: .paymentMode) }).disposed(by: disposeBag) // Handle open select bank input.openBankTrigger.withLatestFrom(banksModel) {$1} .drive(onNext: { [weak self] in guard let `self` = self else { return } self.presenter?.openSelectMode(with: $0, type: .bank) }).disposed(by: disposeBag) // Handle open select branch input.openBranchTrigger.withLatestFrom(branchesModel) { $1 } .drive(onNext: { [weak self] in guard let `self` = self else { return } self.presenter?.openBranches(countryCode: $0.0?.countryCode ?? "", bankID: $0.1?.id ?? "") }).disposed(by: disposeBag) // Handle open select id type input.openIDTypeTrigger.withLatestFrom(idTypesModel) {$1} .drive(onNext: { [weak self] in guard let `self` = self else { return } self.presenter?.openSelectMode(with: $0, type: .idType) }).disposed(by: disposeBag) // Handle open select state input.openStateProvinceTrigger.withLatestFrom(stateProvicesModel) {$1} .drive(onNext: { [weak self] in guard let `self` = self else { return } self.presenter?.openSelectMode(with: $0, type: .stateProvince) }) .disposed(by: disposeBag) // Handle open select district input.openDistrictTrigger.withLatestFrom(districtsModel) {$1} .drive(onNext: { [weak self] in guard let `self` = self else { return } self.presenter?.openSelectMode(with: $0, type: .district) }).disposed(by: disposeBag) // Handle open select relation input.openRelationTrigger.withLatestFrom(relationsModel) {$1} .drive(onNext: { [weak self] in guard let `self` = self else { return } self.presenter?.openSelectMode(with: $0, type: .relation) }).disposed(by: disposeBag) // Handle open select reason input.openReasonTrigger.withLatestFrom(reasonsModel) {$1} .drive(onNext: { [weak self] in guard let `self` = self else { return } self.presenter?.openSelectMode(with: $0, type: .reason) }).disposed(by: disposeBag) input.openNativeCountryTrigger.withLatestFrom(nativeCountrisModel) {$1} .drive(onNext: { [weak self] in guard let `self` = self else { return } self.presenter?.openSelectMode(with: $0, type: .nativeCountry) }) .disposed(by: disposeBag) // // Handle save event input.saveTrigger .drive(onNext: { [weak self] in guard let `self` = self else { return } let selectedCountry = try? self.selectedCountryServicesLinker.value() let selectedPaymentMode = try? self.selectedPaymentModeTypesLinker.value() let selectedBank = try? self.selectedBankLinker.value() let selectedBranch = try? self.selectedBranchLinker.value() let selectedIDType = try? self.selectedIDTypeLinker.value() let selectedStateProvince = try? self.selectedStateProvinceLinker.value() let selectedDistrict = try? self.selectedDistrictLinker.value() // let selectedRelation = try? self.selectedRelationLinker.value() // let selectedReason = try? self.selectedReasonLinker.value() let selectedRecipient = try? self.selectedRecipientLinker.value() let selectedNativeCountry = try? self.selectedNativeCountryLinker.value() var recipient = $0 recipient.receiverID = selectedRecipient?.receiverID recipient.country = selectedCountry?.countryName recipient.countryID = selectedCountry?.countryId recipient.countryCode = selectedCountry?.countryCode recipient.paymentMethod?.id = selectedPaymentMode?.id recipient.paymentMethod?.name = selectedPaymentMode?.type recipient.paymentMethod?.localizedName = selectedPaymentMode?.subtitle recipient.paymentMethod?.currency = selectedPaymentMode?.currency recipient.agent = selectedBank?.toAgentModel() recipient.agent?.accountNumber = $0.agent?.accountNumber recipient.agent?.branch = selectedBranch?.toBranchModel() recipient.idType = selectedIDType?.id recipient.state = selectedStateProvince?.name recipient.stateID = selectedStateProvince?.id recipient.district = selectedDistrict?.name recipient.districtID = selectedDistrict?.id // recipient.relationship = selectedRelation?.title // recipient.relationshipID = selectedRelation?.id // recipient.purposeOfRemit = selectedReason?.title // recipient.purposeOfRemitID = selectedReason?.id recipient.nativeCountry = selectedNativeCountry?.text recipient.nativeCountryID = selectedNativeCountry?.id recipient.nativeCountryCode = selectedNativeCountry?.code if selectedBank?.accountValidationRequired == "True" { guard let firstName = recipient.firstName, let lastName = recipient.lastName else { return } let name: String if firstName == "" { name = recipient.fullName ?? "" } else if let middleName = recipient.middleName, middleName != "" { name = "\(firstName) \(middleName)" } else { name = firstName } let validateModel = ValidateAccountRequest( firstName: name, lastName: lastName, accountType: "1", accountNumber: recipient.agent?.accountNumber ?? "", amount: "10000.0", processID: "", payoutPartner: self.payoutPartner ?? "", country: selectedCountry, paymentMethod: selectedPaymentMode, bank: selectedBank, branch: recipient.agent?.branch ) self.presenter?.validateAccount(with: validateModel, recipient: recipient) } else { self.presenter?.saveRecipient(at: recipient) } }) .disposed(by: disposeBag) return Output( isError: errorLinker.asDriverOnErrorJustComplete(), isProgress: progressLinker.asDriverOnErrorJustComplete(), success: successLinker.asDriverOnErrorJustComplete(), models: model, selectedRecipient: selectedRecipientLinker.asDriverOnErrorJustComplete(), selectedCountry: selectedCountryServicesLinker.asDriverOnErrorJustComplete(), selectedPaymentMode: selectedPaymentModeTypesLinker.asDriverOnErrorJustComplete(), selectedBank: selectedBankLinker.asDriverOnErrorJustComplete(), selectedBranch: selectedBranchLinker.asDriverOnErrorJustComplete(), selectedIDType: selectedIDTypeLinker.asDriverOnErrorJustComplete(), selectedStateProvince: selectedStateProvinceLinker.asDriverOnErrorJustComplete(), selectedDistrict: selectedDistrictLinker.asDriverOnErrorJustComplete(), selectedRelation: selectedRelationLinker.asDriverOnErrorJustComplete(), selectedReason: selectedReasonLinker.asDriverOnErrorJustComplete(), selectedNativeCountry: selectedNativeCountryLinker.asDriverOnErrorJustComplete() ) } } // MARK: SetupRecipient view interface extension SetupRecipientViewModel: SetupRecipientViewModelInterface { func setCoutryServices(with model: [CountryAndServiceModel], recipient: Recipient?) { countryServicesLinker.onNext(model) guard let recipient = recipient else { return } selectedRecipientLinker.onNext(recipient) // If exist selected recipient, auto select country and payment mode of selected recipient. setSelectedData(with: model.filter({$0.countryCode == recipient.countryCode}).first, type: .country) let selectedCountry = try? selectedCountryServicesLinker.value() setSelectedData( with: selectedCountry?.availableServices?.filter({$0.id == recipient.paymentMethod?.id}).first, type: .paymentMode ) } func setDynamicFields(with model: DynamicFieldModel, nativeCountires: [NativeCountryModel]) { dynamicFieldsLinker.onNext(model.dynamicField ?? []) reasonsLinker.onNext(model.transferReasons ?? []) relationsLinker.onNext(model.relations ?? []) idTypeLinker.onNext(model.idTypes ?? []) banksLinker.onNext(model.banks ?? []) stateProvincesLinker.onNext(model.provinces ?? []) nativeCountiresLinker.onNext(nativeCountires) payoutPartner = model.payoutPartner let country = try? selectedCountryServicesLinker.value() // Default native country setting as selected country let nativeCountry = nativeCountires.filter({$0.code == country?.countryCode}).first setSelectedData(with: nativeCountry, type: .nativeCountry) guard let recipient = try? selectedRecipientLinker.value() else { return } let selectedBank = model.banks?.filter({$0.id == recipient.agent?.id}).first // let selectedBranch = selectedBank?.branches?.filter({$0.id == recipient.agent?.branch?.id}).first let selectedIDType = model.idTypes?.filter({$0.id == recipient.idType}).first let selectedStateProvince = model.provinces?.filter({$0.id == recipient.stateID}).first let selectedDistrict = selectedStateProvince?.districts?.filter({$0.id == recipient.districtID}).first // let selectedRelation = model.relations?.filter({$0.title == recipient.relationshipID}).first // let selectedReason = model.transferReasons?.filter({$0.title == recipient.purposeOfRemitID}).first let selectedNativeCountry = nativeCountires.filter({$0.text == recipient.nativeCountry}).first setSelectedData(with: selectedBank, type: .bank) setSelectedData(with: recipient.agent?.branch?.toSendMoneyBankBranch(), type: .branch) setSelectedData(with: selectedIDType, type: .idType) setSelectedData(with: selectedStateProvince, type: .stateProvince) setSelectedData(with: selectedDistrict, type: .district) // setSelectedData(with: selectedRelation, type: .relation) // setSelectedData(with: selectedReason, type: .reason) setSelectedData(with: selectedNativeCountry, type: .nativeCountry) } func setSelectedData(with model: TablePresenterProtocol?, type: SetupOpenType) { switch type { case .country: guard let model = model as? CountryAndServiceModel else { return } selectedCountryServicesLinker.onNext(model) selectedPaymentModeTypesLinker.onNext(nil) paymentModeTypesLinker.onNext(model.availableServices ?? []) guard var selectedRecipient = try? selectedRecipientLinker.value() else { return } if model.countryCode != selectedRecipient.countryCode { let countryEnum = CountryEnum(rawValue: selectedRecipient.countryCode?.lowercased() ?? "") selectedRecipient.countryCode = model.countryCode selectedRecipient.country = model.countryName selectedRecipient.countryID = model.countryId selectedRecipient.mobile = selectedRecipient.mobile?.replacingOccurrences( of: countryEnum?.phoneCode ?? "", with: "" ) selectedRecipientLinker.onNext(selectedRecipient) } case .paymentMode: guard let model = model as? PaymentServiceType else { return } selectedPaymentModeTypesLinker.onNext(model) if var recipient = try? selectedRecipientLinker.value(), recipient.agent != nil, !isFirst { recipient.agent = nil selectedRecipientLinker.onNext(recipient) } if (try? selectedBankLinker.value()) != nil { selectedBankLinker.onNext(nil) } if (try? selectedBranchLinker.value()) != nil { selectedBranchLinker.onNext(nil) } let selectedCountry = try? selectedCountryServicesLinker.value() let selectedPaymentMode = try? selectedPaymentModeTypesLinker.value() presenter?.fetchDynamicRecipientFields(country: selectedCountry, paymentMode: selectedPaymentMode) isFirst = false case .bank: guard let model = model as? SendMoneyBank else { return } selectedBankLinker.onNext(model) if let code = model.payoutPartner { payoutPartner = code } if model.branchRequired?.lowercased() == "true" { selectedBranchLinker.onNext(nil) } case .branch: guard let model = model as? SendMoneyBankBranch else { return } selectedBranchLinker.onNext(model) case .idType: guard let model = model as? ReceiverIdType else { return } selectedIDTypeLinker.onNext(model) case .stateProvince: guard let model = model as? Provience else { return } selectedStateProvinceLinker.onNext(model) let count = model.districts?.count ?? 0 if count != 0 { selectedBranchLinker.onNext(nil) } selectedDistrictLinker.onNext(nil) case .district: guard let model = model as? District else { return } selectedDistrictLinker.onNext(model) case .relation: guard let model = model as? Relation else { return } selectedRelationLinker.onNext(model) case .reason: guard let model = model as? TransferReason else { return } selectedReasonLinker.onNext(model) case .nativeCountry: guard let model = model as? NativeCountryModel else { return } selectedNativeCountryLinker.onNext(model) } } func setError(with error: Error) { errorLinker.onNext(error) } func progress(isShow: Bool) { progressLinker.onNext(isShow) } func success(with model: ResponseContainerObject) { successLinker.onNext(model) } }