Skip to content

Commit

Permalink
Add promo badge in horizontal and vertical mode
Browse files Browse the repository at this point in the history
  • Loading branch information
tillh-stripe committed Nov 21, 2024
1 parent 27ced44 commit b0d3f24
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@
C28450436BDA52BE9BE3BDC3 /* PaymentSheetConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E83494558F0C93C5B05A1DFB /* PaymentSheetConfigurationTests.swift */; };
C346B534D57A952D4415ADFD /* Intent+Link.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C8047FD8994D3FAA3D1A7A /* Intent+Link.swift */; };
C5E3750BBCA700CF364F7578 /* PaymentSheetFormFactory+OXXO.swift in Sources */ = {isa = PBXBuildFile; fileRef = F20379AE078D68A0AC83A6C5 /* PaymentSheetFormFactory+OXXO.swift */; };
CB46EF492CED1A2E00E9A7F2 /* PaymentMethodIncentive.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB46EF482CED1A2E00E9A7F2 /* PaymentMethodIncentive.swift */; };
CB46EF4B2CED1BDA00E9A7F2 /* PromoBadgeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB46EF4A2CED1BDA00E9A7F2 /* PromoBadgeView.swift */; };
CD19725E26DBDB9960D828CB /* BottomSheetPresentationAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8F09CF961C943E36D76860F /* BottomSheetPresentationAnimator.swift */; };
CF2AD2C7F761C46AE559E563 /* SavedPaymentOptionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B3ECDF6CF9AABD573F86CA2 /* SavedPaymentOptionsViewController.swift */; };
Expand Down Expand Up @@ -752,6 +753,7 @@
C90A2636C2A577AF36FB793B /* PaymentSheetLoaderTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentSheetLoaderTest.swift; sourceTree = "<group>"; };
C94104A367EAF6C8785C17A1 /* FormSpecProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormSpecProvider.swift; sourceTree = "<group>"; };
C9726902C985C99F69E6880C /* CustomerSheet+PaymentMethodAvailability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CustomerSheet+PaymentMethodAvailability.swift"; sourceTree = "<group>"; };
CB46EF482CED1A2E00E9A7F2 /* PaymentMethodIncentive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentMethodIncentive.swift; sourceTree = "<group>"; };
CB46EF4A2CED1BDA00E9A7F2 /* PromoBadgeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PromoBadgeView.swift; sourceTree = "<group>"; };
CBCFE3D39D670C3C77C59722 /* cs-CZ */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "cs-CZ"; path = "cs-CZ.lproj/Localizable.strings"; sourceTree = "<group>"; };
CC3498CF4AEAA8F169616CDF /* STPCardBrandChoice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = STPCardBrandChoice.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1027,6 +1029,7 @@
22552CD237A259249CD0C592 /* Intent.swift */,
CCA2B5817236F64A212A8C61 /* IntentConfirmParams.swift */,
9A0D887C5AC6EFFAFE1AFD77 /* PaymentMethodType.swift */,
CB46EF482CED1A2E00E9A7F2 /* PaymentMethodIncentive.swift */,
2A19DBD87D0EBC7FA3DFB2A7 /* PaymentOption+Images.swift */,
6B680A2FF197F612D065F16C /* PaymentSheet.swift */,
5CD1A451B238C1D1ADAA72EC /* PaymentSheet+API.swift */,
Expand Down Expand Up @@ -2048,6 +2051,7 @@
F70BCDEECB5863244085F12F /* BoolReference.swift in Sources */,
8B1D7A7CE7D50382E9FA77E3 /* Images.swift in Sources */,
D3CC2489468E3288FD34C160 /* IntentStatusPoller.swift in Sources */,
CB46EF492CED1A2E00E9A7F2 /* PaymentMethodIncentive.swift in Sources */,
96C307CDEE7028B12D9CB69B /* PaymentSheetLinkAccount.swift in Sources */,
623C2D9F87929D6DA9C09E23 /* STPCameraView.swift in Sources */,
599337DB99E9E7017EF47BCE /* STPCardScanner.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,11 @@ class CustomerAddPaymentMethodViewController: UIViewController {
}()
private lazy var paymentMethodTypesView: PaymentMethodTypeCollectionView = {
let view = PaymentMethodTypeCollectionView(
paymentMethodTypes: paymentMethodTypes, appearance: configuration.appearance, delegate: self)
paymentMethodTypes: paymentMethodTypes,
appearance: configuration.appearance,
incentive: nil,
delegate: self
)
return view
}()
private lazy var paymentMethodDetailsContainerView: DynamicHeightContainerView = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ class AddPaymentMethodViewController: UIViewController {
private var paymentMethodFormElement: PaymentMethodElement {
paymentMethodFormViewController.form
}

private var incentive: PaymentMethodIncentive? {
elementsSession.linkSettings?.linkConsumerIncentive.flatMap { PaymentMethodIncentive(from: $0) }
}

// MARK: - Views
private lazy var paymentMethodFormViewController: PaymentMethodFormViewController = {
Expand All @@ -72,6 +76,7 @@ class AddPaymentMethodViewController: UIViewController {
paymentMethodTypes: paymentMethodTypes,
initialPaymentMethodType: previousCustomerInput?.paymentMethodType,
appearance: configuration.appearance,
incentive: incentive,
delegate: self
)
return view
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,20 @@ class PaymentMethodTypeCollectionView: UICollectionView {
let paymentMethodTypes: [PaymentSheet.PaymentMethodType]
let appearance: PaymentSheet.Appearance
weak var _delegate: PaymentMethodTypeCollectionViewDelegate?

private var incentive: PaymentMethodIncentive?

init(
paymentMethodTypes: [PaymentSheet.PaymentMethodType],
initialPaymentMethodType: PaymentSheet.PaymentMethodType? = nil,
appearance: PaymentSheet.Appearance,
incentive: PaymentMethodIncentive?,
delegate: PaymentMethodTypeCollectionViewDelegate
) {
stpAssert(!paymentMethodTypes.isEmpty, "At least one payment method type must be provided.")

self.paymentMethodTypes = paymentMethodTypes
self.incentive = incentive
self._delegate = delegate
let selectedItemIndex: Int = {
if let initialPaymentMethodType = initialPaymentMethodType {
Expand Down Expand Up @@ -113,9 +117,10 @@ extension PaymentMethodTypeCollectionView: UICollectionViewDataSource, UICollect
stpAssertionFailure()
return UICollectionViewCell()
}
let paymentMethodType = paymentMethodTypes[indexPath.item]
cell.paymentMethodType = paymentMethodType
cell.paymentMethodType = paymentMethodTypes[indexPath.item]
// TODO(tillh-stripe) Pass promo text along
cell.promoBadgeText = nil
cell.promoBadgeText = incentive?.takeIfAppliesTo(paymentMethodType)?.displayText
cell.appearance = appearance
return cell
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// PaymentMethodIncentive.swift
// StripePaymentSheet
//
// Created by Till Hellmund on 11/19/24.
//

import Foundation
@_spi(STP) import StripePayments

struct PaymentMethodIncentive {

private let identifier: String
let displayText: String

func takeIfAppliesTo(_ paymentMethodType: PaymentSheet.PaymentMethodType) -> PaymentMethodIncentive? {
switch paymentMethodType {
case .stripe, .external:
return nil
case .instantDebits, .linkCardBrand:
return identifier == "link_instant_debits" ? self : nil
}
}
}

extension PaymentMethodIncentive {

init?(from incentive: LinkConsumerIncentive) {
guard let displayText = incentive.incentiveDisplayText else {
return nil
}

self.identifier = incentive.incentiveParams.paymentMethod
self.displayText = displayText
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class VerticalPaymentMethodListViewController: UIViewController {
appearance: PaymentSheet.Appearance,
currency: String?,
amount: Int?,
incentive: PaymentMethodIncentive?,
delegate: VerticalPaymentMethodListViewControllerDelegate
) {
self.delegate = delegate
Expand Down Expand Up @@ -114,7 +115,7 @@ class VerticalPaymentMethodListViewController: UIViewController {
let rowButton = RowButton.makeForPaymentMethodType(
paymentMethodType: paymentMethodType,
subtitle: Self.subtitleText(for: paymentMethodType),
promoText: nil, // TODO(tillh-stripe) Pass promo text along
promoText: incentive?.takeIfAppliesTo(paymentMethodType)?.displayText,
savedPaymentMethodType: savedPaymentMethod?.type,
appearance: appearance,
// Enable press animation if tapping this transitions the screen to a form instead of becoming selected
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ class PaymentSheetVerticalViewController: UIViewController, FlowControllerViewCo
appearance: configuration.appearance,
currency: loadResult.intent.currency,
amount: loadResult.intent.amount,
incentive: loadResult.elementsSession.linkSettings?.linkConsumerIncentive.flatMap { PaymentMethodIncentive(from: $0) },
delegate: self
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,22 @@ final class VerticalPaymentMethodListViewControllerSnapshotTest: STPSnapshotTest
}

func testNoSavedPM_noApplePayLink() {
let sut = VerticalPaymentMethodListViewController(initialSelection: nil, savedPaymentMethod: nil, paymentMethodTypes: paymentMethods.map { .stripe($0) }, shouldShowApplePay: false, shouldShowLink: false, savedPaymentMethodAccessoryType: .edit, overrideHeaderView: nil, appearance: .default, currency: "USD", amount: 1099, delegate: self)
let sut = VerticalPaymentMethodListViewController(initialSelection: nil, savedPaymentMethod: nil, paymentMethodTypes: paymentMethods.map { .stripe($0) }, shouldShowApplePay: false, shouldShowLink: false, savedPaymentMethodAccessoryType: .edit, overrideHeaderView: nil, appearance: .default, currency: "USD", amount: 1099, incentive: nil, delegate: self)
STPSnapshotVerifyView(sut.view, autoSizingHeightForWidth: 375)
}

func testSavedCard_noApplePayLink() {
let sut = VerticalPaymentMethodListViewController(initialSelection: .saved(paymentMethod: ._testCard()), savedPaymentMethod: ._testCard(), paymentMethodTypes: paymentMethods.map { .stripe($0) }, shouldShowApplePay: false, shouldShowLink: false, savedPaymentMethodAccessoryType: .edit, overrideHeaderView: nil, appearance: .default, currency: "USD", amount: 1099, delegate: self)
let sut = VerticalPaymentMethodListViewController(initialSelection: .saved(paymentMethod: ._testCard()), savedPaymentMethod: ._testCard(), paymentMethodTypes: paymentMethods.map { .stripe($0) }, shouldShowApplePay: false, shouldShowLink: false, savedPaymentMethodAccessoryType: .edit, overrideHeaderView: nil, appearance: .default, currency: "USD", amount: 1099, incentive: nil, delegate: self)
STPSnapshotVerifyView(sut.view, autoSizingHeightForWidth: 375)
}

func testSavedCard_ApplePayLink() {
let sut = VerticalPaymentMethodListViewController(initialSelection: .saved(paymentMethod: ._testCard()), savedPaymentMethod: ._testCard(), paymentMethodTypes: paymentMethods.map { .stripe($0) }, shouldShowApplePay: true, shouldShowLink: true, savedPaymentMethodAccessoryType: .edit, overrideHeaderView: nil, appearance: .default, currency: "USD", amount: 1099, delegate: self)
let sut = VerticalPaymentMethodListViewController(initialSelection: .saved(paymentMethod: ._testCard()), savedPaymentMethod: ._testCard(), paymentMethodTypes: paymentMethods.map { .stripe($0) }, shouldShowApplePay: true, shouldShowLink: true, savedPaymentMethodAccessoryType: .edit, overrideHeaderView: nil, appearance: .default, currency: "USD", amount: 1099, incentive: nil, delegate: self)
STPSnapshotVerifyView(sut.view, autoSizingHeightForWidth: 375)
}

func testDarkMode() {
let sut = VerticalPaymentMethodListViewController(initialSelection: .saved(paymentMethod: ._testCard()), savedPaymentMethod: ._testCard(), paymentMethodTypes: paymentMethods.map { .stripe($0) }, shouldShowApplePay: true, shouldShowLink: true, savedPaymentMethodAccessoryType: .edit, overrideHeaderView: nil, appearance: .default, currency: "USD", amount: 1099, delegate: self)
let sut = VerticalPaymentMethodListViewController(initialSelection: .saved(paymentMethod: ._testCard()), savedPaymentMethod: ._testCard(), paymentMethodTypes: paymentMethods.map { .stripe($0) }, shouldShowApplePay: true, shouldShowLink: true, savedPaymentMethodAccessoryType: .edit, overrideHeaderView: nil, appearance: .default, currency: "USD", amount: 1099, incentive: nil, delegate: self)
let window = UIWindow()
window.isHidden = false
window.addAndPinSubview(sut.view, insets: .zero)
Expand All @@ -78,7 +78,7 @@ final class VerticalPaymentMethodListViewControllerSnapshotTest: STPSnapshotTest
}

func testAppearance() {
let sut = VerticalPaymentMethodListViewController(initialSelection: .saved(paymentMethod: ._testCard()), savedPaymentMethod: ._testCard(), paymentMethodTypes: paymentMethods.map { .stripe($0) }, shouldShowApplePay: true, shouldShowLink: true, savedPaymentMethodAccessoryType: .edit, overrideHeaderView: nil, appearance: ._testMSPaintTheme, currency: "USD", amount: 1099, delegate: self)
let sut = VerticalPaymentMethodListViewController(initialSelection: .saved(paymentMethod: ._testCard()), savedPaymentMethod: ._testCard(), paymentMethodTypes: paymentMethods.map { .stripe($0) }, shouldShowApplePay: true, shouldShowLink: true, savedPaymentMethodAccessoryType: .edit, overrideHeaderView: nil, appearance: ._testMSPaintTheme, currency: "USD", amount: 1099, incentive: nil, delegate: self)
let window = UIWindow()
window.isHidden = false
window.addAndPinSubview(sut.view, insets: .zero)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ final class VerticalPaymentMethodListViewControllerTest: XCTestCase {
appearance: .default,
currency: "USD",
amount: 1099,
incentive: nil,
delegate: self
)
// ...the current selection should be the saved PM
Expand Down Expand Up @@ -70,6 +71,7 @@ final class VerticalPaymentMethodListViewControllerTest: XCTestCase {
appearance: .default,
currency: "USD",
amount: 1099,
incentive: nil,
delegate: self
)
XCTAssertEqual(["SEPA Debit", "Card", "Apple Pay", "Link"], sut.rowButtons.map { $0.label.text })
Expand All @@ -86,6 +88,7 @@ final class VerticalPaymentMethodListViewControllerTest: XCTestCase {
appearance: .default,
currency: "USD",
amount: 1099,
incentive: nil,
delegate: self
)
XCTAssertEqual(["Card", "Apple Pay", "Link"], sut_cards_only.rowButtons.map { $0.label.text })
Expand All @@ -102,6 +105,7 @@ final class VerticalPaymentMethodListViewControllerTest: XCTestCase {
appearance: .default,
currency: "USD",
amount: 1099,
incentive: nil,
delegate: self
)
XCTAssertEqual(["Apple Pay", "Link", "SEPA Debit"], sut_no_cards.rowButtons.map { $0.label.text })
Expand Down

0 comments on commit b0d3f24

Please sign in to comment.