Skip to content

Commit

Permalink
Extract details that need to be persisted (email, phone, etc.) into L…
Browse files Browse the repository at this point in the history
…inkSignupDetails, and put it on the IntentConfirmParams
  • Loading branch information
yuki-stripe committed Oct 3, 2024
1 parent 1b7cb42 commit 937abdc
Show file tree
Hide file tree
Showing 10 changed files with 49 additions and 38 deletions.
1 change: 0 additions & 1 deletion Stripe/StripeiOSTests/LinkSignupViewModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import StripeCoreTestUtils
import XCTest

@testable@_spi(STP) import Stripe
@testable@_spi(STP) import StripeCore
@testable@_spi(STP) import StripePayments
@testable@_spi(STP) import StripePaymentSheet
import StripePaymentsTestUtils
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import UIKit

// TODO: Refactor this to be a ContainerElement and contain its sub-elements.
final class LinkInlineSignupElement: Element {

let collectsUserInput: Bool = true

let signupView: LinkInlineSignupView
Expand Down Expand Up @@ -55,13 +56,11 @@ final class LinkInlineSignupElement: Element {
self.signupView = LinkInlineSignupView(viewModel: viewModel)
self.signupView.delegate = self
}

}

extension LinkInlineSignupElement: LinkInlineSignupViewDelegate {

func inlineSignupViewDidUpdate(_ view: LinkInlineSignupView) {
delegate?.didUpdate(element: self)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ final class LinkAccountService: LinkAccountServiceProtocol {
for: email,
with: apiClient
) { [apiClient] result in
sleep(10)
switch result {
case .success(let lookupResponse):
STPAnalyticsClient.sharedClient.logLinkAccountLookupComplete(lookupResult: lookupResponse.responseType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,16 @@ protocol LinkInlineSignupViewModelDelegate: AnyObject {
func signupViewModelDidUpdate(_ viewModel: LinkInlineSignupViewModel)
}

struct LinkSignupDetails: Equatable {
let account: PaymentSheetLinkAccount
let phoneNumber: PhoneNumber
let legalName: String?
let consentAction: PaymentSheetLinkAccount.ConsentAction
}

final class LinkInlineSignupViewModel {
enum Action: Equatable {
case signupAndPay(account: PaymentSheetLinkAccount, phoneNumber: PhoneNumber, legalName: String?)
case signupAndPay(LinkSignupDetails)
case continueWithoutLink
}

Expand Down Expand Up @@ -227,9 +234,12 @@ final class LinkInlineSignupViewModel {
}

return .signupAndPay(
account: linkAccount,
phoneNumber: phoneNumber,
legalName: requiresNameCollection ? legalName : nil
.init(
account: linkAccount,
phoneNumber: phoneNumber,
legalName: requiresNameCollection ? legalName : nil,
consentAction: consentAction
)
)
case .verified, .requiresVerification:
// This should never happen: The session should only be verified as part of the signup request,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ final class IntentConfirmParams {
/// If `true`, a mandate (e.g. "By continuing you authorize Foo Corp to use your payment details for recurring payments...") was displayed to the customer.
var didDisplayMandate: Bool = false

/// Populated when Link signup is filled out in the form.
var linkSignupDetails: LinkSignupDetails?
var financialConnectionsLinkedBank: FinancialConnectionsLinkedBank?
var instantDebitsLinkedBank: InstantDebitsLinkedBank?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ extension PaymentSheet {

/// Signup for Link then pay.
case signUp(
account: PaymentSheetLinkAccount,
phoneNumber: PhoneNumber,
consentAction: PaymentSheetLinkAccount.ConsentAction,
legalName: String?,
details: LinkSignupDetails,
// account: PaymentSheetLinkAccount,
// phoneNumber: PhoneNumber,
// consentAction: PaymentSheetLinkAccount.ConsentAction,
// legalName: String?,
intentConfirmParams: IntentConfirmParams
)

Expand All @@ -37,12 +38,13 @@ extension PaymentSheet {

extension PaymentSheet.LinkConfirmOption {

// TODO: Can we get rid of this? Can we remove details from the signup case assoc val?
var account: PaymentSheetLinkAccount? {
switch self {
case .wallet:
return nil
case .signUp(let account, _, _, _, _):
return account
case .signUp(let details, _):
return details.account
case .withPaymentMethod:
return nil
}
Expand All @@ -52,7 +54,7 @@ extension PaymentSheet.LinkConfirmOption {
switch self {
case .wallet:
return STPPaymentMethodType.link.displayName
case .signUp(_, _, _, _, let intentConfirmParams):
case .signUp(_, let intentConfirmParams):
return intentConfirmParams.paymentMethodParams.paymentSheetLabel
case .withPaymentMethod(let paymentMethod):
return paymentMethod.paymentSheetLabel
Expand All @@ -63,7 +65,7 @@ extension PaymentSheet.LinkConfirmOption {
switch self {
case .wallet:
return nil
case .signUp(_, _, _, _, let intentConfirmParams):
case .signUp(_, let intentConfirmParams):
return intentConfirmParams.paymentMethodParams.billingDetails
case .withPaymentMethod(let paymentMethod):
return paymentMethod.billingDetails
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -438,17 +438,17 @@ extension PaymentSheet {
let linkController = PayWithLinkController(intent: intent, elementsSession: elementsSession, configuration: configuration)
linkController.present(from: authenticationContext.authenticationPresentingViewController(),
completion: completion)
case .signUp(let linkAccount, let phoneNumber, let consentAction, let legalName, let intentConfirmParams):
linkAccount.signUp(with: phoneNumber, legalName: legalName, consentAction: consentAction) { result in
case let .signUp(details: details, intentConfirmParams: intentConfirmParams):
details.account.signUp(with: details.phoneNumber, legalName: details.legalName, consentAction: details.consentAction) { result in
UserDefaults.standard.markLinkAsUsed()
switch result {
case .success:
STPAnalyticsClient.sharedClient.logLinkSignupComplete()
createPaymentDetailsAndConfirm(linkAccount, intentConfirmParams.paymentMethodParams, intentConfirmParams.saveForFutureUseCheckboxState == .selected)
createPaymentDetailsAndConfirm(details.account, intentConfirmParams.paymentMethodParams, intentConfirmParams.saveForFutureUseCheckboxState == .selected)
case .failure(let error as NSError):
STPAnalyticsClient.sharedClient.logLinkSignupFailure(error: error)
// Attempt to confirm directly with params as a fallback.
confirmWithPaymentMethodParams(intentConfirmParams.paymentMethodParams, linkAccount, intentConfirmParams.saveForFutureUseCheckboxState == .selected)
confirmWithPaymentMethodParams(intentConfirmParams.paymentMethodParams, details.account, intentConfirmParams.saveForFutureUseCheckboxState == .selected)
}
}
case .withPaymentMethod(let paymentMethod):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,12 @@ class PaymentMethodFormViewController: UIViewController {
params.setDefaultBillingDetailsIfNecessary(for: configuration)

if let params = form.updateParams(params: params) {
// Hack: determine this is a Link signup by looking for the LinkInlineSignupElement
if let linkInlineSignupElement = form.getAllUnwrappedSubElements().compactMap({ $0 as? LinkInlineSignupElement }).first {
switch linkInlineSignupElement.action {
case .signupAndPay(let account, let phoneNumber, let legalName):
return .link(
option: .signUp(
account: account,
phoneNumber: phoneNumber,
consentAction: linkInlineSignupElement.viewModel.consentAction,
legalName: legalName,
intentConfirmParams: params
)
)
case .signupAndPay(let signupDetails):
params.linkSignupDetails = signupDetails // Hack: instead of this, the LinkInlineSignupElement should update its params with these details
return .link(option: .signUp(details: signupDetails, intentConfirmParams: params))
case .continueWithoutLink:
return .new(confirmParams: params)
case .none:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
// Created by Yuki Tokuhiro on 10/2/24.
//

import XCTest
@testable@_spi(STP) import StripeCore
@testable@_spi(STP) import StripePayments
@testable@_spi(STP) import StripePaymentSheet
@testable@_spi(STP) import StripePaymentsTestUtils
@testable@_spi(STP) import StripePaymentsUI
@testable@_spi(STP) import StripeUICore
import XCTest

@MainActor
final class CardSectionElementTest: XCTestCase {
Expand Down Expand Up @@ -46,19 +46,18 @@ final class CardSectionElementTest: XCTestCase {
let checkbox = form.getCheckboxElement(startingWith: "Save payment details")!
let linkInlineSignupElement: LinkInlineSignupElement = form.getElement()!
let linkInlineView = linkInlineSignupElement.signupView

XCTAssertNotNil(checkbox) // Checkbox should appear since this is a PI w/ customer
form.getTextFieldElement("Card number")?.setText("4242424242424242")
form.getTextFieldElement("MM / YY").setText("1232")
form.getTextFieldElement("CVC").setText("123")
form.getTextFieldElement("ZIP").setText("65432")

XCTAssertEqual(form.getAllUnwrappedSubElements().count, 14)
// XCTAssertNotNil(form.mandateString)
// Simulate selecting checkbox
checkbox.isSelected = true
checkbox.didToggleCheckbox()

// Set the email & phone number
linkInlineView.emailElement.emailAddressElement.setText("\(UUID().uuidString)@foo.com")
linkInlineView.phoneNumberElement.countryDropdownElement.setRawData("GB")
Expand All @@ -79,10 +78,10 @@ final class CardSectionElementTest: XCTestCase {
// Ensure checkbox remains selected
XCTAssertTrue(regeneratedForm.getCheckboxElement(startingWith: "Save payment details")!.isSelected)
XCTAssertEqual(regeneratedIntentConfirmParams, intentConfirmParams)
let linkInlineSignupElement2: LinkInlineSignupElement = regeneratedForm.getElement()!
let linkInlineView2 = linkInlineSignupElement2.signupView
print(linkInlineView2)

let regeneratedLinkInlineSignupElement: LinkInlineSignupElement = regeneratedForm.getElement()!
let regeneratedLinkInlineView = regeneratedLinkInlineSignupElement.signupView
XCTAssertEqual(regeneratedLinkInlineView.phoneNumberElement.phoneNumber, PhoneNumber(number: "1234567890", countryCode: "GB"))
// print(linkInlineView2)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,11 @@ extension IntentConfirmParams: Equatable {
return false
}

if lhs.linkSignupDetails != rhs.linkSignupDetails {
print("Link signup details not equal: \(lhs.linkSignupDetails.debugDescription) vs \(rhs.linkSignupDetails.debugDescription)")
return false
}

// Sanity check to make sure when we add new properties, we check them here
let mirror = Mirror(reflecting: lhs)
let propertyCount = mirror.children.count
Expand Down

0 comments on commit 937abdc

Please sign in to comment.