Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NT-359] Integrate Updating Backing mutation #893

Merged
merged 9 commits into from
Oct 16, 2019
2 changes: 1 addition & 1 deletion KsApi/mutations/inputs/ApplePayParams.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

public struct ApplePayParams: Encodable {
public struct ApplePayParams: Encodable, Equatable {
let paymentInstrumentName: String
let paymentNetwork: String
let transactionIdentifier: String
Expand Down
7 changes: 4 additions & 3 deletions Library/UpdateBackingInput+Constructor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import KsApi

extension UpdateBackingInput {
internal static func input(
from updateBackingData: UpdateBackingData
from updateBackingData: UpdateBackingData,
isApplePay: Bool
) -> UpdateBackingInput {
let pledgeAmount: String? = updateBackingData.pledgeAmount.flatMap { pledgeAmount in
pledgeAmountString(withAmount: pledgeAmount, shippingRule: updateBackingData.shippingRule)
Expand All @@ -14,10 +15,10 @@ extension UpdateBackingInput {

return UpdateBackingInput(
amount: pledgeAmount,
applePay: nil,
applePay: isApplePay ? updateBackingData.applePayParams : nil,
id: backingId,
locationId: locationId,
paymentSourceId: nil,
paymentSourceId: isApplePay ? nil : updateBackingData.paymentSourceId,
rewardId: rewardId
)
}
Expand Down
43 changes: 40 additions & 3 deletions Library/UpdateBackingInput+ConstructorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,56 @@
import XCTest

final class UpdateBackingInput_ConstructorTests: TestCase {
func testUpdateBackingInput_UpdateBackingData() {
func testUpdateBackingInput_UpdateBackingData_NotApplePay() {
let applePayParams = ApplePayParams(
paymentInstrumentName: "paymentInstrumentName",
paymentNetwork: "paymentNetwork",
transactionIdentifier: "transactionIdentifier",
token: "token"
)

let data: UpdateBackingData = (
backing: Backing.template,
reward: Reward.template,
pledgeAmount: 100,
shippingRule: ShippingRule.template
shippingRule: ShippingRule.template,
paymentSourceId: GraphUserCreditCard.amex.id,
applePayParams: applePayParams
)
let input = UpdateBackingInput.input(from: data)

let input = UpdateBackingInput.input(from: data, isApplePay: false)

XCTAssertEqual(input.amount, "105.00")
XCTAssertNil(input.applePay)
XCTAssertEqual(input.id, "QmFja2luZy0x")
XCTAssertEqual(input.locationId, "42")
XCTAssertEqual(input.paymentSourceId, "6")
XCTAssertEqual(input.rewardId, "UmV3YXJkLTE=")
}

func testUpdateBackingInput_UpdateBackingData_IsApplePay() {
let applePayParams = ApplePayParams(
paymentInstrumentName: "paymentInstrumentName",
paymentNetwork: "paymentNetwork",
transactionIdentifier: "transactionIdentifier",
token: "token"
)

let data: UpdateBackingData = (
backing: Backing.template,
reward: Reward.template,
pledgeAmount: 100,
shippingRule: ShippingRule.template,
paymentSourceId: GraphUserCreditCard.amex.id,
applePayParams: applePayParams
)

let input = UpdateBackingInput.input(from: data, isApplePay: true)

XCTAssertEqual(input.amount, "105.00")
XCTAssertEqual(input.applePay, applePayParams)
XCTAssertEqual(input.id, "QmFja2luZy0x")
XCTAssertEqual(input.locationId, "42")
XCTAssertNil(input.paymentSourceId)
XCTAssertEqual(input.rewardId, "UmV3YXJkLTE=")
}
Expand Down
195 changes: 152 additions & 43 deletions Library/ViewModels/PledgeViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ public typealias UpdateBackingData = (
backing: Backing,
reward: Reward,
pledgeAmount: Double?,
shippingRule: ShippingRule?
shippingRule: ShippingRule?,
paymentSourceId: String?,
applePayParams: ApplePayParams?
)
public typealias PaymentAuthorizationData = (
project: Project, reward: Reward, pledgeAmount: Double,
Expand Down Expand Up @@ -132,6 +134,13 @@ public class PledgeViewModel: PledgeViewModelType, PledgeViewModelInputs, Pledge
}
.skipNil()

self.confirmationLabelAttributedText = Signal.merge(
project,
project.takeWhen(self.traitCollectionDidChangeSignal)
)
.map(attributedConfirmationString(with:))
.skipNil()

self.continueViewHidden = Signal
.combineLatest(isLoggedIn, context)
.map { $0 || $1.continueViewHidden }
Expand Down Expand Up @@ -168,6 +177,11 @@ public class PledgeViewModel: PledgeViewModelType, PledgeViewModelInputs, Pledge
self.shippingRuleSelectedSignal.wrapInOptional()
)

let selectedPaymentSourceId = Signal.merge(
initialData.mapConst(nil),
self.creditCardSelectedSignal.wrapInOptional()
)

let createBackingData = Signal.combineLatest(
project,
reward,
Expand All @@ -177,7 +191,7 @@ public class PledgeViewModel: PledgeViewModelType, PledgeViewModelInputs, Pledge
)
.map { $0 as CreateBackingData }

// MARK: Create Backing
// MARK: - Create Backing

let createButtonTapped = Signal.combineLatest(
self.submitButtonTappedSignal,
Expand Down Expand Up @@ -209,7 +223,7 @@ public class PledgeViewModel: PledgeViewModelType, PledgeViewModelInputs, Pledge
let createBackingEventError = createBackingEvent.errors()
.map { $0.localizedDescription }

// MARK: Apple Pay
// MARK: - Apple Pay

let paymentAuthorizationData = createBackingData.map {
(
Expand Down Expand Up @@ -276,14 +290,21 @@ public class PledgeViewModel: PledgeViewModelType, PledgeViewModelInputs, Pledge
applePayStatusFailure
)

// MARK: - Apple Pay
// MARK: - Create Apple Pay Backing

let willCreateApplePayBacking = Signal.combineLatest(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and willUpdateApplePayBacking are to ensure that upon completion of these asynchronous events we show the appropriate messaging/view to the user.

applePayStatusSuccess,
context
)
.map { $1.isCreating }
.filter(isTrue)

let createApplePayBackingData = Signal.combineLatest(
createBackingData,
pkPaymentData.skipNil(),
self.stripeTokenSignal.skipNil()
)
.takeWhen(applePayStatusSuccess)
.takeWhen(willCreateApplePayBacking)
.map { backingData, paymentData, stripeToken
-> (Project, Reward, Double, ShippingRule?, PKPaymentData, String, RefTag?) in
(
Expand All @@ -308,69 +329,68 @@ public class PledgeViewModel: PledgeViewModelType, PledgeViewModelInputs, Pledge
.materialize()
}

let createApplePayBackingEventSuccess = createApplePayBackingEvent.values()

let createApplePayBackingEventErrors = createApplePayBackingEvent.errors()
.map { $0.localizedDescription }
let createApplePayBackingError = createApplePayBackingEventErrors
.takeWhen(self.paymentAuthorizationDidFinishSignal)
// MARK: - Update Apple Pay Backing

self.createBackingError = Signal.merge(
createApplePayBackingError,
createBackingEventError
let applePayParams = Signal.combineLatest(
pkPaymentData.skipNil(),
self.stripeTokenSignal.skipNil()
)
.map { paymentData, token in
(
paymentData.displayName,
paymentData.network,
paymentData.transactionIdentifier,
token
)
}
.map(ApplePayParams.init)

let applePayTransactionCompleted = Signal.combineLatest(project, createApplePayBackingEventSuccess)
.takeWhen(self.paymentAuthorizationDidFinishSignal)
.map(first)

self.confirmationLabelAttributedText = Signal.merge(
project,
project.takeWhen(self.traitCollectionDidChangeSignal)
let applePayParamsData = Signal.merge(
initialData.mapConst(nil),
applePayParams.wrapInOptional()
)
.map(attributedConfirmationString(with:))
.skipNil()

let createBackingTransactionSuccess = project.takeWhen(createBackingEventSuccess)

self.goToThanks = Signal.merge(applePayTransactionCompleted, createBackingTransactionSuccess)

self.submitButtonTitle = context.map { $0.submitButtonTitle }
self.title = context.map { $0.title }

// MARK: Update Backing

let updateBackingData = Signal.combineLatest(
backing,
reward,
pledgeAmount.wrapInOptional(),
selectedShippingRule
selectedShippingRule,
selectedPaymentSourceId,
applePayParamsData
)
.map { $0 as UpdateBackingData }

// MARK: - Update Backing

let willUpdateApplePayBacking = Signal.combineLatest(
applePayStatusSuccess,
context
)
.map { $1.isUpdating }
.filter(isTrue)

let updateButtonTapped = Signal.combineLatest(
self.submitButtonTappedSignal,
context
)
.filter { _, context in context.isUpdating }
.ignoreValues()

let updateBackingEvent = updateBackingData
.takeWhen(updateButtonTapped)
.map(UpdateBackingInput.input(from:))
let updateBackingDataAndIsApplePay = updateBackingData.takePairWhen(
Signal.merge(
updateButtonTapped.mapConst(false),
willUpdateApplePayBacking
)
)

let updateBackingEvent = updateBackingDataAndIsApplePay
.map(UpdateBackingInput.input(from:isApplePay:))
.switchMap { input in
AppEnvironment.current.apiService.updateBacking(input: input)
.ksr_delay(AppEnvironment.current.apiDelayInterval, on: AppEnvironment.current.scheduler)
.materialize()
}

self.notifyDelegateUpdatePledgeDidSucceedWithMessage = updateBackingEvent.values()
.mapConst(Strings.Got_it_your_changes_have_been_saved())
self.updatePledgeFailedWithError = updateBackingEvent.errors()
.map { $0.localizedDescription }

self.popViewController = self.notifyDelegateUpdatePledgeDidSucceedWithMessage.ignoreValues()

// MARK: - Form Validation

let amountChangedAndValid = Signal.combineLatest(
Expand Down Expand Up @@ -428,6 +448,95 @@ public class PledgeViewModel: PledgeViewModelType, PledgeViewModelInputs, Pledge
createBackingEvent.filter { $0.isTerminating }.mapConst(true),
updateBackingEvent.filter { $0.isTerminating }.mapConst(true)
)

// MARK: - Success/Failure Create

let createPaymentAuthorizationDidFinishSignal = willCreateApplePayBacking
.takeWhen(self.paymentAuthorizationDidFinishSignal)

let createApplePayBackingCompleted = Signal.combineLatest(
createApplePayBackingEvent
.filter { $0.isTerminating }
.ignoreValues(),
createPaymentAuthorizationDidFinishSignal
)

let createApplePayBackingEventSuccess = createApplePayBackingEvent.values()

let createApplePayBackingEventErrors = createApplePayBackingEvent.errors()
.map { $0.localizedDescription }

let createApplePayBackingError = createApplePayBackingEventErrors
.takeWhen(createApplePayBackingCompleted)

self.createBackingError = Signal.merge(
createApplePayBackingError,
createBackingEventError
)

let applePayTransactionCompleted = Signal.combineLatest(project, createApplePayBackingEventSuccess)
.takeWhen(createApplePayBackingCompleted)
.map(first)

let createBackingTransactionSuccess = project.takeWhen(createBackingEventSuccess)

self.goToThanks = Signal.merge(applePayTransactionCompleted, createBackingTransactionSuccess)

// MARK: - Success/Failure Update

let updatePaymentAuthorizationDidFinishSignal = willUpdateApplePayBacking
.takeWhen(self.paymentAuthorizationDidFinishSignal)

let updateApplePayBackingCompleted = Signal.combineLatest(
updateBackingEvent
.filter { $0.isTerminating }
.ignoreValues(),
updatePaymentAuthorizationDidFinishSignal
)

let updateApplePayBackingSuccess = updateBackingEvent.values()
.takeWhen(updateApplePayBackingCompleted)

let updateBackingDidCompleteApplePay = updateApplePayBackingSuccess
.ignoreValues()

let submitButtonTapped = Signal.merge(
self.submitButtonTappedSignal.mapConst(true),
willUpdateApplePayBacking.mapConst(false)
)

let updateBackingDidComplete = submitButtonTapped
.takeWhen(updateBackingEvent.values())
.filter(isTrue)
.ignoreValues()

let updateBackingEventErrors = updateBackingEvent.errors()

let updateApplePayBackingError = updateApplePayBackingCompleted
.withLatest(from: updateBackingEventErrors)
.map(second)

let updateBackingError = submitButtonTapped
.takePairWhen(updateBackingEventErrors)
.filter(first >>> isTrue)
.map(second)

self.notifyDelegateUpdatePledgeDidSucceedWithMessage = Signal.merge(
updateBackingDidCompleteApplePay,
updateBackingDidComplete
)
.mapConst(Strings.Got_it_your_changes_have_been_saved())

self.updatePledgeFailedWithError = Signal.merge(
updateApplePayBackingError,
updateBackingError
)
.map { $0.localizedDescription }

self.popViewController = self.notifyDelegateUpdatePledgeDidSucceedWithMessage.ignoreValues()

self.submitButtonTitle = context.map { $0.submitButtonTitle }
self.title = context.map { $0.title }
}

// MARK: - Inputs
Expand Down
Loading