Skip to content

Commit

Permalink
MBL-1285: implement CompleteOnSessionCheckoutMutation for new and exi…
Browse files Browse the repository at this point in the history
…sting cards
  • Loading branch information
amy-at-kickstarter committed Mar 28, 2024
1 parent f16bae7 commit 978d902
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,31 @@ final class PostCampaignCheckoutViewController: UIViewController, MessageBannerV
.observeValues { [weak self] paymentAuthorizationData in
self?.goToPaymentAuthorization(paymentAuthorizationData)
}

self.viewModel.outputs.checkoutComplete
.observeForUI()
.observeValues { [weak self] _ in
let alert = UIAlertController(
title: "Wow!",
message: "It worked! Your checkout is done. This should push us to the Thanks page.",
preferredStyle: .alert
)
alert.addAction(UIAlertAction.init(title: "OK", style: .cancel))
self?.present(alert, animated: true)
}

self.viewModel.outputs.checkoutError
.observeForUI()
.observeValues { [weak self] error in

let oopsString = Strings.Something_went_wrong_please_try_again()
let serverError = error.errorMessages.first ?? ""

let message = "\(oopsString)\n\(serverError)"

self?.messageBannerViewController?
.showBanner(with: .error, message: message)
}
}

// MARK: - Functions
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

extension GraphAPI.ApplePayInput {
public extension GraphAPI.ApplePayInput {
static func from(_ input: ApplePayParams?) -> GraphAPI.ApplePayInput? {
guard let input = input else { return nil }
return GraphAPI.ApplePayInput(
Expand Down
106 changes: 106 additions & 0 deletions Library/ViewModels/PostCampaignCheckoutViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ public protocol PostCampaignCheckoutViewModelOutputs {
var showWebHelp: Signal<HelpType, Never> { get }
var validateCheckoutSuccess: Signal<PaymentSourceValidation, Never> { get }
var goToApplePayPaymentAuthorization: Signal<PostCampaignPaymentAuthorizationData, Never> { get }
var checkoutComplete: Signal<(), Never> { get }
var checkoutError: Signal<ErrorEnvelope, Never> { get }
}

public protocol PostCampaignCheckoutViewModelType {
Expand Down Expand Up @@ -186,6 +188,10 @@ public class PostCampaignCheckoutViewModel: PostCampaignCheckoutViewModelType,
!isNewPaymentMethod
}

let selectedNewCard = selectedCard.filter { (_, _, isNewPaymentMethod: Bool) in
isNewPaymentMethod
}

let newPaymentIntentForExistingCards = initialData
.takeWhen(selectedExistingCard)
.switchMap { initialData in
Expand All @@ -201,6 +207,23 @@ public class PostCampaignCheckoutViewModel: PostCampaignCheckoutViewModelType,
.materialize()
}

let newPaymentIntentForApplePay = initialData
.takeWhen(self.applePayButtonTappedSignal.signal)
.switchMap { initialData in
let projectId = initialData.project.graphID
let pledgeTotal = initialData.total

return AppEnvironment.current.apiService
.createPaymentIntentInput(input: CreatePaymentIntentInput(
projectId: projectId,
amountDollars: String(format: "%.2f", pledgeTotal),
digitalMarketingAttributed: nil
))
.materialize()
}
.values()
.map { $0.clientSecret }

let paymentIntentClientSecretForExistingCards = newPaymentIntentForExistingCards.values()
.map { $0.clientSecret }

Expand Down Expand Up @@ -277,6 +300,8 @@ public class PostCampaignCheckoutViewModel: PostCampaignCheckoutViewModelType,
.merge(validateCheckoutExistingCard.errors(), validateCheckoutNewCard.errors())
.map { _ in Strings.Something_went_wrong_please_try_again() }

// MARK: ApplePay

let paymentAuthorizationData: Signal<PostCampaignPaymentAuthorizationData, Never> = self
.configureWithDataProperty
.signal
Expand Down Expand Up @@ -335,6 +360,85 @@ public class PostCampaignCheckoutViewModel: PostCampaignCheckoutViewModelType,

// MARK: CompleteOnSessionCheckout

let completeCheckoutWithExistingCard = Signal
.combineLatest(self.confirmPaymentSuccessfulProperty.signal.skipNil(), checkoutId, selectedExistingCard)
.switchMap { (
clientSecret: String,
checkoutId: String,
selectedCard: (source: PaymentSourceSelected, paymentMethodId: String, isNewPaymentMethod: Bool)?
) -> SignalProducer<Signal<GraphAPI.CompleteOnSessionCheckoutMutation.Data, ErrorEnvelope>.Event, Never> in

let input = GraphAPI
.CompleteOnSessionCheckoutInput(
checkoutId: encodeToBase64("Checkout-\(checkoutId)"),
paymentIntentClientSecret: clientSecret,
paymentSourceId: selectedCard?.paymentMethodId,
paymentSourceReusable: true,
applePay: nil
)

return AppEnvironment.current.apiService
.completeOnSessionCheckout(input: input)
.materialize()
}

let completeCheckoutWithNewCard = Signal
.combineLatest(self.confirmPaymentSuccessfulProperty.signal.skipNil(), checkoutId, selectedNewCard)
.switchMap { (
clientSecret: String,
checkoutId: String,
_: (source: PaymentSourceSelected, paymentMethodId: String, isNewPaymentMethod: Bool)?
) -> SignalProducer<Signal<GraphAPI.CompleteOnSessionCheckoutMutation.Data, ErrorEnvelope>.Event, Never> in

let input = GraphAPI
.CompleteOnSessionCheckoutInput(
checkoutId: encodeToBase64("Checkout-\(checkoutId)"),
paymentIntentClientSecret: clientSecret,
paymentSourceId: nil,
paymentSourceReusable: true,
applePay: nil
)

return AppEnvironment.current.apiService
.completeOnSessionCheckout(input: input)
.materialize()
}

let completeCheckoutWithApplePay = Signal
.combineLatest(newPaymentIntentForApplePay, checkoutId, applePayParams)
.switchMap { (
clientSecret: String,
checkoutId: String,
applePayParams: ApplePayParams
) -> SignalProducer<Signal<GraphAPI.CompleteOnSessionCheckoutMutation.Data, ErrorEnvelope>.Event, Never> in

let input = GraphAPI
.CompleteOnSessionCheckoutInput(
checkoutId: encodeToBase64("Checkout-\(checkoutId)"),
paymentIntentClientSecret: clientSecret,
paymentSourceId: nil,
paymentSourceReusable: nil,
applePay: GraphAPI.ApplePayInput.from(applePayParams)
)

return AppEnvironment.current.apiService
.completeOnSessionCheckout(input: input)
.materialize()
}

self.checkoutComplete = Signal
.merge(
completeCheckoutWithExistingCard.values().ignoreValues(),
completeCheckoutWithNewCard.values().ignoreValues(),
completeCheckoutWithApplePay.values().ignoreValues()
)
self.checkoutError = Signal
.merge(
completeCheckoutWithExistingCard.errors(),
completeCheckoutWithNewCard.errors(),
completeCheckoutWithApplePay.errors()
)

// TODO: Call .completeOnSessionCheckout when self.confirmPaymentSuccessfulProperty.signal is called
}

Expand Down Expand Up @@ -442,6 +546,8 @@ public class PostCampaignCheckoutViewModel: PostCampaignCheckoutViewModelType,
public let showWebHelp: Signal<HelpType, Never>
public let validateCheckoutSuccess: Signal<PaymentSourceValidation, Never>
public let goToApplePayPaymentAuthorization: Signal<PostCampaignPaymentAuthorizationData, Never>
public let checkoutComplete: Signal<(), Never>
public let checkoutError: Signal<ErrorEnvelope, Never>

public var inputs: PostCampaignCheckoutViewModelInputs { return self }
public var outputs: PostCampaignCheckoutViewModelOutputs { return self }
Expand Down

0 comments on commit 978d902

Please sign in to comment.