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

Delay intent creation and open 'add' if no saved payment methods #2473

Merged
merged 5 commits into from
Apr 18, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -221,9 +221,9 @@ extension SavedPaymentMethodSheetTestPlayground: SavedPaymentMethodsSheetDelegat
self.updateButtons()
let alertController = self.makeAlertController()
if let paymentOptionSelection = paymentOptionSelection {
alertController.message = "Finished with: \(paymentOptionSelection.displayData().label)"
alertController.message = "Success: \(paymentOptionSelection.displayData().label)"
} else {
alertController.message = "Finished, payment method unset"
alertController.message = "Success: payment method unset"
}
self.present(alertController, animated: true) {
self.load()
Original file line number Diff line number Diff line change
@@ -17,15 +17,7 @@ protocol SavedPaymentMethodsAddPaymentMethodViewControllerDelegate: AnyObject {
class SavedPaymentMethodsAddPaymentMethodViewController: UIViewController {
// MARK: - Read-only Properties
weak var delegate: SavedPaymentMethodsAddPaymentMethodViewControllerDelegate?
lazy var paymentMethodTypes: [PaymentSheet.PaymentMethodType] = {
guard let intent = intent else {
return [.card]
}
let paymentMethodTypes = PaymentSheet.PaymentMethodType.recommendedPaymentMethodTypes(from: intent)
.filter { $0 == .card }
assert(!paymentMethodTypes.isEmpty, "At least one payment method type must be available.")
return paymentMethodTypes
}()
let paymentMethodTypes: [PaymentSheet.PaymentMethodType] = [.card]
var selectedPaymentMethodType: PaymentSheet.PaymentMethodType {
return paymentMethodTypesView.selected
}
@@ -38,7 +30,6 @@ class SavedPaymentMethodsAddPaymentMethodViewController: UIViewController {
return nil
}
// MARK: - Writable Properties
private let intent: Intent?
private let configuration: SavedPaymentMethodsSheet.Configuration

private lazy var paymentMethodFormElement: PaymentMethodElement = {
@@ -67,12 +58,10 @@ class SavedPaymentMethodsAddPaymentMethodViewController: UIViewController {
}

required init(
intent: Intent?,
configuration: SavedPaymentMethodsSheet.Configuration,
delegate: SavedPaymentMethodsAddPaymentMethodViewControllerDelegate
) {
self.configuration = configuration
self.intent = intent
self.delegate = delegate
super.init(nibName: nil, bundle: nil)
self.view.backgroundColor = configuration.appearance.colors.background
@@ -137,7 +126,6 @@ class SavedPaymentMethodsAddPaymentMethodViewController: UIViewController {

private func makeElement(for type: PaymentSheet.PaymentMethodType) -> PaymentMethodElement {
let formElement = SavedPaymentMethodsFormFactory(
intent: intent,
configuration: configuration,
paymentMethod: type
).make()! // TODO(wooj) Don't force unwrap
Original file line number Diff line number Diff line change
@@ -13,7 +13,6 @@ import UIKit
class SavedPaymentMethodsFormFactory {

let paymentMethod: PaymentSheet.PaymentMethodType
let intent: Intent?
let configuration: SavedPaymentMethodsSheet.Configuration
let addressSpecProvider: AddressSpecProvider

@@ -22,12 +21,10 @@ class SavedPaymentMethodsFormFactory {
}

init(
intent: Intent?,
configuration: SavedPaymentMethodsSheet.Configuration,
addressSpecProvider: AddressSpecProvider = .shared,
paymentMethod: PaymentSheet.PaymentMethodType
) {
self.intent = intent
self.configuration = configuration
self.paymentMethod = paymentMethod
self.addressSpecProvider = addressSpecProvider
Original file line number Diff line number Diff line change
@@ -148,10 +148,11 @@ extension SavedPaymentMethodsSheet {
@available(iOSApplicationExtension, unavailable)
@available(macCatalystApplicationExtension, unavailable)
extension SavedPaymentMethodsSheet: SavedPaymentMethodsViewControllerDelegate {
func savedPaymentMethodsViewControllerShouldConfirm(_ savedPaymentMethodsViewController: SavedPaymentMethodsViewController, with paymentOption: PaymentOption, completion: @escaping (SavedPaymentMethodsSheetResult) -> Void) {
guard let intent = savedPaymentMethodsViewController.intent else {
assertionFailure("Payment intent not available")
completion(.failed(error: SavedPaymentMethodsSheetError.unknown(debugDescription: "No payment intent available")))
func savedPaymentMethodsViewControllerShouldConfirm(_ intent: Intent?, with paymentOption: PaymentOption, completion: @escaping (SavedPaymentMethodsSheetResult) -> Void) {
guard let intent = intent,
case .setupIntent = intent else {
assertionFailure("Setup intent not available")
completion(.failed(error: SavedPaymentMethodsSheetError.unknown(debugDescription: "No setup intent available")))
return
}
self.confirmIntent(intent: intent, paymentOption: paymentOption) { result in
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ import Foundation
import UIKit

protocol SavedPaymentMethodsViewControllerDelegate: AnyObject {
func savedPaymentMethodsViewControllerShouldConfirm(_ savedPaymentMethodsViewController: SavedPaymentMethodsViewController,
func savedPaymentMethodsViewControllerShouldConfirm(_ intent: Intent?,
with paymentOption: PaymentOption,
completion: @escaping(SavedPaymentMethodsSheetResult) -> Void)
func savedPaymentMethodsViewControllerDidCancel(_ savedPaymentMethodsViewController: SavedPaymentMethodsViewController, completion: @escaping () -> Void)
@@ -40,12 +40,16 @@ class SavedPaymentMethodsViewController: UIViewController {
private(set) var error: Error?
private var processingInFlight: Bool = false
private(set) var intent: Intent?
private var addPaymentMethodViewController: SavedPaymentMethodsAddPaymentMethodViewController?
private lazy var addPaymentMethodViewController: SavedPaymentMethodsAddPaymentMethodViewController = {
return SavedPaymentMethodsAddPaymentMethodViewController(
configuration: configuration,
delegate: self)
}()

var selectedPaymentOption: PaymentOption? {
switch mode {
case .addingNewWithSetupIntent, .addingNewPaymentMethodAttachToCustomer:
if let paymentOption = addPaymentMethodViewController?.paymentOption {
if let paymentOption = addPaymentMethodViewController.paymentOption {
return paymentOption
}
return nil
@@ -113,9 +117,16 @@ class SavedPaymentMethodsViewController: UIViewController {
self.isApplePayEnabled = isApplePayEnabled
self.savedPaymentMethodsSheetDelegate = savedPaymentMethodsSheetDelegate
self.delegate = delegate
self.mode = .selectingSaved
self.addPaymentMethodViewController = nil
super.init(nibName: nil, bundle: nil)
if savedPaymentMethods.isEmpty {
if configuration.createSetupIntentHandler != nil {
self.mode = .addingNewWithSetupIntent
} else {
self.mode = .addingNewPaymentMethodAttachToCustomer
}
} else {
self.mode = .selectingSaved
}
super.init(nibName: nil, bundle: nil)

self.view.backgroundColor = configuration.appearance.colors.background
}
@@ -271,7 +282,7 @@ class SavedPaymentMethodsViewController: UIViewController {
self.navigationBar.additionalButton.removeTarget(
self, action: #selector(didSelectEditSavedPaymentMethodsButton),
for: .touchUpInside)
return .back
return savedPaymentMethods.isEmpty ? .close(showAdditionalButton: false) : .back
}
}())

@@ -310,12 +321,12 @@ class SavedPaymentMethodsViewController: UIViewController {

switch mode {
case .addingNewWithSetupIntent:
guard let newPaymentOption = addPaymentMethodViewController?.paymentOption else {
guard let newPaymentOption = addPaymentMethodViewController.paymentOption else {
return
}
addPaymentOption(paymentOption: newPaymentOption)
case .addingNewPaymentMethodAttachToCustomer:
guard let newPaymentOption = addPaymentMethodViewController?.paymentOption else {
guard let newPaymentOption = addPaymentMethodViewController.paymentOption else {
return
}
addPaymentOptionToCustomer(paymentOption: newPaymentOption)
@@ -350,12 +361,36 @@ class SavedPaymentMethodsViewController: UIViewController {
}

private func addPaymentOption(paymentOption: PaymentOption) {
guard case .new = paymentOption else {
guard case .new = paymentOption,
let createSetupIntentHandler = self.configuration.createSetupIntentHandler else {
return
}
self.processingInFlight = true
updateUI(animated: false)
self.delegate?.savedPaymentMethodsViewControllerShouldConfirm(self, with: paymentOption, completion: { result in

createSetupIntentHandler({ result in
guard let clientSecret = result else {
self.processingInFlight = false
self.updateUI()
self.savedPaymentMethodsSheetDelegate?.didFail(with: .setupIntentClientSecretInvalid)
return
}
self.fetchSetupIntent(clientSecret: clientSecret) { result in
switch result {
case .success(let stpSetupIntent):
let setupIntent = Intent.setupIntent(stpSetupIntent)
self.confirm(intent: setupIntent, paymentOption: paymentOption)
case .failure(let error):
self.processingInFlight = false
self.updateUI()
self.savedPaymentMethodsSheetDelegate?.didFail(with: .setupIntentFetchError(error))
}
}
})
}

func confirm(intent: Intent?, paymentOption: PaymentOption) {
self.delegate?.savedPaymentMethodsViewControllerShouldConfirm(intent, with: paymentOption, completion: { result in
self.processingInFlight = false
switch result {
case .canceled:
@@ -558,52 +593,22 @@ extension SavedPaymentMethodsViewController: SavedPaymentMethodsCollectionViewCo
func didUpdateSelection(
viewController: SavedPaymentMethodsCollectionViewController,
paymentMethodSelection: SavedPaymentMethodsCollectionViewController.Selection) {
// TODO: Add some boolean flag here to avoid making duplicate calls
switch paymentMethodSelection {
case .add:
error = nil
if let createSetupIntentHandler = self.configuration.createSetupIntentHandler {
if self.configuration.createSetupIntentHandler != nil {
mode = .addingNewWithSetupIntent
if let intent = self.intent, !intent.isInTerminalState {
initAddPaymentMethodViewController(intent: intent)
self.updateUI()
} else {
createSetupIntentHandler({ result in
guard let clientSecret = result else {
self.savedPaymentMethodsSheetDelegate?.didFail(with: .setupIntentClientSecretInvalid)
return
}
self.fetchSetupIntent(clientSecret: clientSecret) { result in
switch result {
case .success(let stpSetupIntent):
let setupIntent = Intent.setupIntent(stpSetupIntent)
self.intent = setupIntent
self.initAddPaymentMethodViewController(intent: setupIntent)
case .failure(let error):
self.savedPaymentMethodsSheetDelegate?.didFail(with: .setupIntentFetchError(error))
}
self.updateUI()
}
})
}
} else {
mode = .addingNewPaymentMethodAttachToCustomer
self.initAddPaymentMethodViewController(intent: nil)
self.updateUI()
}
self.updateUI()
case .saved:
updateUI(animated: true)
case .applePay:
updateUI(animated: true)
}
}
private func initAddPaymentMethodViewController(intent: Intent?) {
self.addPaymentMethodViewController = SavedPaymentMethodsAddPaymentMethodViewController(
intent: intent,
configuration: self.configuration,
delegate: self
)
}

func didSelectRemove(
viewController: SavedPaymentMethodsCollectionViewController,
paymentMethodSelection: SavedPaymentMethodsCollectionViewController.Selection) {