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.
302 lines
11 KiB
302 lines
11 KiB
//
|
|
// ExistingUserKycPresenter.swift
|
|
// GME Remit
|
|
//
|
|
// Created by Shiran on 8/18/20.
|
|
//Copyright © 2020 Gobal Money Express Co. Ltd. All rights reserved.
|
|
//
|
|
|
|
import RxSwift
|
|
import RxCocoa
|
|
import CoreLocation
|
|
|
|
class ExistingUserKycPresenter {
|
|
|
|
// MARK: Properties
|
|
enum Step: Int {
|
|
case innerStep1
|
|
case innerStep2
|
|
}
|
|
|
|
var interactor: ExistingUserKycInteractorInput?
|
|
var wireframe: ExistingUserKycWireframeInput?
|
|
|
|
struct Input {
|
|
let viewWillAppear: Driver<Bool>
|
|
let sendLocation: Driver<CLLocation>
|
|
|
|
let sourceOfFund: Driver<KeyValue?>
|
|
let occupation: Driver<KeyValue?>
|
|
let monthlyIncome: Driver<String>
|
|
let businessType: Driver<KeyValue?>
|
|
let visaStatus: Driver<KeyValue?>
|
|
let idType: Driver<KeyValue?>
|
|
let purpose: Driver<KeyValue?>
|
|
|
|
let employerName: Driver<String>
|
|
let mobile: Driver<String>
|
|
let email: Driver<String>
|
|
let address: Driver<String>
|
|
|
|
let isValidPersonalInfo: Driver<Bool>
|
|
let personalInfoSave: Driver<Void>
|
|
let editingPersonalInfo: Driver<Void>
|
|
|
|
let frontIDImage: Driver<String?>
|
|
let backIDImage: Driver<String?>
|
|
let sideIDImage: Driver<String?>
|
|
|
|
let isValidPictures: Driver<Bool>
|
|
let editingPictureInfo: Driver<Void>
|
|
|
|
let submit: Driver<Void>
|
|
}
|
|
|
|
struct Output {
|
|
let isError: Driver<Error>
|
|
let isProgress: Driver<Bool>
|
|
let gpsAddress: Driver<String>
|
|
let model: Driver<KYCInfoModel>
|
|
|
|
let idTypes: Driver<[KeyValue]?>
|
|
let purposes: Driver<[KeyValue]?>
|
|
let busniessType: Driver<[KeyValue]?>
|
|
let sourceOfFund: Driver<[KeyValue]?>
|
|
let occupation: Driver<[KeyValue]?>
|
|
// let monthlyIncome: Driver<[KeyValue]?>
|
|
let visaStatus: Driver<[KeyValue]?>
|
|
|
|
let isSetPersonalInfoModel: Driver<Bool>
|
|
let isSetPictureInfoModel: Driver<Bool>
|
|
let storePersonalSuccess: Driver<Bool>
|
|
let storedSuccess: Driver<String>
|
|
}
|
|
|
|
private let disposeBag = DisposeBag()
|
|
|
|
private let progressLinker = PublishSubject<Bool>()
|
|
private let errorLinker = PublishSubject<Error>()
|
|
private let gpsAddress = PublishSubject<String>()
|
|
private let model = PublishSubject<KYCInfoModel>()
|
|
|
|
private var storedPersonalInfo = PublishSubject<PersonalInfoModel?>()
|
|
private var storedPictureInformation = PublishSubject<PictureInfoModel?>()
|
|
private var storedPersonalSuccess = PublishSubject<String?>()
|
|
private let storedSuccess = PublishSubject<String>()
|
|
|
|
func transform(input: Input) -> Output {
|
|
|
|
let newPicturesInfo = Driver.combineLatest(
|
|
input.isValidPictures,
|
|
input.frontIDImage,
|
|
input.backIDImage,
|
|
input.sideIDImage
|
|
).map { (isValid, frontIdImage, backIdImage, sideIdImage) -> PictureInfoModel? in
|
|
return isValid ? PictureInfoModel(
|
|
idFront: frontIdImage,
|
|
idBack: backIdImage,
|
|
idSide: sideIdImage,
|
|
additionalId: nil,
|
|
facePicture: nil,
|
|
additionalIdBack: nil
|
|
) : nil
|
|
}
|
|
|
|
let newPersonalInfo = Driver.combineLatest(
|
|
input.isValidPersonalInfo,
|
|
input.idType,
|
|
input.visaStatus,
|
|
input.occupation,
|
|
input.purpose,
|
|
Driver.combineLatest(
|
|
input.employerName,
|
|
input.sourceOfFund,
|
|
input.monthlyIncome,
|
|
input.mobile,
|
|
input.businessType,
|
|
input.email,
|
|
input.address,
|
|
model.map{$0.personalInformation?.nativeCountry}.asDriverOnErrorJustComplete()
|
|
).map({ (employerName, sourceOfFund, monthlyIncome, mobile, businessType, email, address, nativeCountry) -> PersonalInfoModel in
|
|
return PersonalInfoModel(
|
|
email: email,
|
|
address: address,
|
|
visaStatus: nil,
|
|
sourceOfFund: sourceOfFund?.id,
|
|
monthlyIncome: monthlyIncome,
|
|
mobile: mobile,
|
|
idType: nil,
|
|
additionalIdType: nil,
|
|
businessType: businessType?.id,
|
|
nativeCountry: nativeCountry,
|
|
employeerName: employerName,
|
|
occupation: nil,
|
|
purpose: nil,
|
|
isBackIDRequired: nil
|
|
)
|
|
})
|
|
).map { (isValid, idType, visaStatus, occupation, purpose, info) -> PersonalInfoModel? in
|
|
if isValid{
|
|
var personalInfo = info
|
|
personalInfo.idType = idType?.id
|
|
personalInfo.visaStatus = visaStatus?.id
|
|
personalInfo.occupation = occupation?.id
|
|
personalInfo.purpose = purpose?.id
|
|
return personalInfo
|
|
}
|
|
return nil
|
|
}
|
|
|
|
let isSetPersonalInformation = Driver
|
|
.combineLatest(input.isValidPersonalInfo, storedPersonalInfo.asDriverOnErrorJustComplete())
|
|
.map { $0 && $1 != nil }
|
|
|
|
let isSetPictureInformation = Driver
|
|
.combineLatest(input.isValidPictures, storedPictureInformation.asDriverOnErrorJustComplete())
|
|
.map {$0 && $1 != nil}
|
|
|
|
let storePersonalSuccess = Driver
|
|
.combineLatest(input.isValidPersonalInfo, storedPersonalSuccess.asDriverOnErrorJustComplete())
|
|
.map {$0 && $1 != nil}
|
|
|
|
input.viewWillAppear.drive(onNext: { [weak self] (value) in
|
|
self?.progressLinker.onNext(value)
|
|
self?.interactor?.fetchInformation()
|
|
}).disposed(by: disposeBag)
|
|
|
|
input.sendLocation.drive(onNext: { [weak self] in
|
|
self?.progressLinker.onNext(true)
|
|
let geocoder = CLGeocoder()
|
|
let locale = Locale(identifier: "en-US")
|
|
|
|
geocoder.reverseGeocodeLocation($0, preferredLocale: locale) {(placemarks, error) in
|
|
if let error = error {
|
|
self?.progressLinker.onNext(false)
|
|
self?.errorLinker.onNext(error)
|
|
}
|
|
|
|
if let address: [CLPlacemark] = placemarks {
|
|
let name = address.last?.name ?? ""
|
|
let locality = address.last?.locality ?? ""
|
|
self?.progressLinker.onNext(false)
|
|
|
|
let mergedAddress = "\(name) \(locality)"//.extract(regex: "[A-Z0-9a-z\\s]")
|
|
self?.gpsAddress.onNext(mergedAddress)
|
|
}
|
|
}
|
|
|
|
}).disposed(by: disposeBag)
|
|
|
|
input.editingPersonalInfo
|
|
.withLatestFrom(newPersonalInfo) { $1 }
|
|
.withLatestFrom(storedPersonalInfo.asDriverOnErrorJustComplete()) {($0, $1)}
|
|
.drive(onNext: {[weak self] in
|
|
guard let new = $0, let stored = $1 else { return }
|
|
if new != stored {
|
|
self?.storedPersonalInfo.onNext(nil)
|
|
}
|
|
})
|
|
.disposed(by: disposeBag)
|
|
|
|
input.editingPictureInfo
|
|
.withLatestFrom(newPicturesInfo) { $1 }
|
|
.withLatestFrom(storedPictureInformation.asDriverOnErrorJustComplete()) {($0, $1)}
|
|
.drive(onNext: {[weak self] in
|
|
guard let new = $0, let stored = $1 else { return }
|
|
if new != stored {
|
|
self?.storedPictureInformation.onNext(nil)
|
|
}
|
|
})
|
|
.disposed(by: disposeBag)
|
|
|
|
input.personalInfoSave
|
|
.withLatestFrom(newPersonalInfo) { $1 }
|
|
.drive(onNext: {[weak self] in
|
|
let saveModel = KYCSaveInformation(
|
|
type: Step.innerStep1.rawValue,
|
|
personalInformation: $0,
|
|
pictures: nil
|
|
)
|
|
self?.progressLinker.onNext(true)
|
|
self?.interactor?.saveInformation(with: saveModel)
|
|
}).disposed(by: disposeBag)
|
|
|
|
input.submit
|
|
.withLatestFrom(newPersonalInfo) { $1 }
|
|
.withLatestFrom(newPicturesInfo) { ($0, $1) }
|
|
.drive(onNext: {[weak self] in
|
|
let saveModel = KYCSaveInformation(
|
|
type: Step.innerStep2.rawValue,
|
|
personalInformation: $0,
|
|
pictures: $1
|
|
)
|
|
self?.progressLinker.onNext(true)
|
|
self?.interactor?.saveInformation(with: saveModel)
|
|
}).disposed(by: disposeBag)
|
|
|
|
return Output(
|
|
isError: errorLinker.asDriverOnErrorJustComplete(),
|
|
isProgress: progressLinker.asDriverOnErrorJustComplete(),
|
|
gpsAddress: gpsAddress.asDriverOnErrorJustComplete(),
|
|
model: model.asDriverOnErrorJustComplete(),
|
|
idTypes: model.map {$0.idType}.asDriverOnErrorJustComplete(),
|
|
purposes: model.map {$0.purpose}.asDriverOnErrorJustComplete(),
|
|
busniessType: model.map {$0.businessType}.asDriverOnErrorJustComplete(),
|
|
sourceOfFund: model.map {$0.sourceOfFund}.asDriverOnErrorJustComplete(),
|
|
occupation: model.map {$0.occupation}.asDriverOnErrorJustComplete(),
|
|
// monthlyIncome: model.map {$0.monthlyIncome}.asDriverOnErrorJustComplete(),
|
|
visaStatus: model.map {$0.visaStatus}.asDriverOnErrorJustComplete(),
|
|
isSetPersonalInfoModel: isSetPersonalInformation,
|
|
isSetPictureInfoModel: isSetPictureInformation,
|
|
storePersonalSuccess: storePersonalSuccess,
|
|
storedSuccess: storedSuccess.asDriverOnErrorJustComplete()
|
|
)
|
|
}
|
|
}
|
|
|
|
// MARK: ExistingUserKyc interactor output interface
|
|
|
|
extension ExistingUserKycPresenter: ExistingUserKycInteractorOutput {
|
|
func setModel(with model: KYCInfoModel) {
|
|
progressLinker.onNext(false)
|
|
self.model.onNext(model)
|
|
guard let personalInformation = model.personalInformation, !personalInformation.isHasEmptyValue() else {
|
|
storedPersonalInfo.onNext(nil)
|
|
return
|
|
}
|
|
|
|
storedPersonalInfo.onNext(model.personalInformation)
|
|
|
|
guard let pictures = model.pictures, !pictures.isHasEmptyValue() else {
|
|
storedPictureInformation.onNext(nil)
|
|
return
|
|
}
|
|
storedPictureInformation.onNext(pictures)
|
|
}
|
|
|
|
func setSaveResult(with storedModel: KYCSaveInformation?, message: String) {
|
|
progressLinker.onNext(false)
|
|
|
|
guard let storedModel = storedModel, let type = Step(rawValue: storedModel.type) else { return }
|
|
switch type {
|
|
case .innerStep1:
|
|
storedPersonalInfo.onNext(storedModel.personalInformation)
|
|
storedPersonalSuccess.onNext(message)
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
|
self.storedPersonalSuccess.onNext(nil)
|
|
}
|
|
|
|
case .innerStep2:
|
|
storedPictureInformation.onNext(storedModel.pictures)
|
|
storedSuccess.onNext(message)
|
|
}
|
|
}
|
|
|
|
func setError(with error: Error) {
|
|
progressLinker.onNext(false)
|
|
errorLinker.onNext(error)
|
|
|
|
}
|
|
|
|
|
|
}
|