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

Display a “default” badge for the default PM #4333

Merged
merged 86 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from 70 commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
1403094
reading default_payment_method from back end?
joyceqin-stripe Nov 27, 2024
71c5516
revert accidental space changes;
joyceqin-stripe Nov 27, 2024
e3ecc2c
customersheet default from back end
joyceqin-stripe Nov 27, 2024
fb86faa
removed unused value
joyceqin-stripe Dec 2, 2024
b283446
Merge branch 'master' into joyceqin-MOBILESDK-2799
joyceqin-stripe Dec 2, 2024
9ed5ed2
remove unused property
joyceqin-stripe Dec 2, 2024
e689449
Merge branch 'master' into joyceqin-MOBILESDK-2799
joyceqin-stripe Dec 2, 2024
3c36c97
fix build issue
joyceqin-stripe Dec 2, 2024
c749e6e
Merge branch 'joyceqin-MOBILESDK-2799' of github.com:stripe/stripe-io…
joyceqin-stripe Dec 2, 2024
aac6ae1
fix test
joyceqin-stripe Dec 2, 2024
90e15a4
display default badge
joyceqin-stripe Dec 2, 2024
b25eb4b
merged with master
joyceqin-stripe Dec 4, 2024
16e6b0c
use localized string for Default badge
joyceqin-stripe Dec 4, 2024
5936f96
Merge branch 'master' into joyceqin-MOBILESDK-2799
joyceqin-stripe Dec 4, 2024
5cd59d6
small change for less repetition in code
joyceqin-stripe Dec 4, 2024
54a8073
snapshot tests
joyceqin-stripe Dec 5, 2024
0fca0dc
check default pm against savedPaymentMethods instead of customer.paym…
joyceqin-stripe Dec 5, 2024
c8bd06b
Merge branch 'master' into joyceqin-MOBILESDK-2800
joyceqin-stripe Dec 5, 2024
c226e09
removed alternateUpdatePaymentMethodNavigation, consolidated reading …
joyceqin-stripe Dec 5, 2024
4d146b6
Merge branch 'master' into joyceqin-MOBILESDK-2799
joyceqin-stripe Dec 5, 2024
f858536
remove alternateUpdatePaymentMethodNavigation flag and updated tests
joyceqin-stripe Dec 6, 2024
8d1c90b
update snapshot tests
joyceqin-stripe Dec 6, 2024
c70c6a1
update row button chevron condition
joyceqin-stripe Dec 6, 2024
d999b9e
remove removeonly mode, update tests
joyceqin-stripe Dec 6, 2024
ac5189a
fixing tests
joyceqin-stripe Dec 6, 2024
ffcf6e4
remove wait for chevron existence in tests for last card
joyceqin-stripe Dec 6, 2024
403fdcb
localizable string
joyceqin-stripe Dec 6, 2024
c8fbfef
edit a test
joyceqin-stripe Dec 6, 2024
2f515cd
merged with remove alternateupdatepaymentmethodnavigation flag
joyceqin-stripe Dec 6, 2024
0a92c87
remove removeOnly snapshots
joyceqin-stripe Dec 6, 2024
a89890c
Merge branch 'master' into joyceqin-remove-alternateupdatepaymentmeth…
joyceqin-stripe Dec 6, 2024
bd51b31
changelog
joyceqin-stripe Dec 6, 2024
3c69384
Merge branch 'master' into joyceqin-remove-alternateupdatepaymentmeth…
joyceqin-stripe Dec 6, 2024
f239d20
update changelog and tests
joyceqin-stripe Dec 6, 2024
5fad2d3
Merge branch 'joyceqin-remove-alternateupdatepaymentmethodnavigation-…
joyceqin-stripe Dec 6, 2024
4da3034
Merge branch 'master' into joyceqin-MOBILESDK-2799
joyceqin-stripe Dec 6, 2024
f83164f
Merge branch 'master' into joyceqin-MOBILESDK-2800
joyceqin-stripe Dec 6, 2024
05407cc
Merge branch 'joyceqin-remove-alternateupdatepaymentmethodnavigation-…
joyceqin-stripe Dec 6, 2024
60cd77c
merge with persisted default
joyceqin-stripe Dec 6, 2024
fe79f55
readd default badge snapshot test
joyceqin-stripe Dec 6, 2024
ea5228f
remove dead code
joyceqin-stripe Dec 6, 2024
eaae456
Merge branch 'master' into joyceqin-remove-alternateupdatepaymentmeth…
joyceqin-stripe Dec 6, 2024
623ffe3
Merge branch 'master' into joyceqin-MOBILESDK-2800
joyceqin-stripe Dec 6, 2024
7022a11
sleep for 1 second to allow label animation to finish testRemovalOfSa…
joyceqin-stripe Dec 6, 2024
f5fbd58
Merge branch 'joyceqin-remove-alternateupdatepaymentmethodnavigation-…
joyceqin-stripe Dec 6, 2024
05a0a04
fix build
joyceqin-stripe Dec 6, 2024
1794106
remove extra argument
joyceqin-stripe Dec 6, 2024
cb12138
Merge branch 'master' into joyceqin-MOBILESDK-2799
joyceqin-stripe Dec 6, 2024
efb682f
Merge branch 'master' into joyceqin-MOBILESDK-2800
joyceqin-stripe Dec 6, 2024
b592b55
fallback when opted in to set as default not local default but first …
joyceqin-stripe Dec 9, 2024
74c9db8
added tests
joyceqin-stripe Dec 9, 2024
a28440e
merge
joyceqin-stripe Dec 9, 2024
b6d712e
Merge branch 'master' into joyceqin-MOBILESDK-2800
joyceqin-stripe Dec 16, 2024
d4dedf5
merge
joyceqin-stripe Dec 16, 2024
f9d0996
fix non compiling test
joyceqin-stripe Dec 16, 2024
0c52f28
dynamically increase height of collectionview cells when default badg…
joyceqin-stripe Dec 17, 2024
8f30c22
snapshot tests
joyceqin-stripe Dec 17, 2024
d6ea0c6
removed hard coded default value
joyceqin-stripe Dec 17, 2024
04b187d
snapshots
joyceqin-stripe Dec 17, 2024
8d7509c
Merge branch 'master' into joyceqin-MOBILESDK-2800
joyceqin-stripe Dec 17, 2024
afcfc48
revert verticalspmvc snapshot tests
joyceqin-stripe Dec 17, 2024
b88ce62
Merge branch 'joyceqin-MOBILESDK-2800' of github.com:stripe/stripe-io…
joyceqin-stripe Dec 17, 2024
6dba918
do not change cell size if should not display default badge;
joyceqin-stripe Dec 17, 2024
626f4d5
cleanup vertical default badge code
joyceqin-stripe Dec 17, 2024
734345e
update snapshots
joyceqin-stripe Dec 17, 2024
f6844ec
always set isDefaultPM to true or false
joyceqin-stripe Dec 18, 2024
063fcb1
condense activation deactivation code
joyceqin-stripe Dec 18, 2024
3867417
remove num lines on label
joyceqin-stripe Dec 18, 2024
6670834
fix build
joyceqin-stripe Dec 18, 2024
f05cdcb
Merge branch 'master' into joyceqin-MOBILESDK-2800
joyceqin-stripe Dec 18, 2024
ff08f77
revert spacing
joyceqin-stripe Dec 18, 2024
53b894a
Merge branch 'joyceqin-MOBILESDK-2800' of github.com:stripe/stripe-io…
joyceqin-stripe Dec 18, 2024
8382a93
cleaned up elementscustomer functions, nonoptional constraints to act…
joyceqin-stripe Dec 18, 2024
22e2b02
refactored names and defined isDefaultPaymentMethod functions
joyceqin-stripe Dec 19, 2024
6bcc425
Merge branch 'master' into joyceqin-MOBILESDK-2800
joyceqin-stripe Dec 19, 2024
304aa41
fix vertical default badge snapshot;
joyceqin-stripe Dec 19, 2024
9dd0cfb
adjust default badge font weight when selected vs not
joyceqin-stripe Dec 19, 2024
10de2e9
clean up activate and deactivate default badge constraints code
joyceqin-stripe Dec 19, 2024
d27f4c8
Merge branch 'master' into joyceqin-MOBILESDK-2800
joyceqin-stripe Dec 19, 2024
9d16dec
fix if condition
joyceqin-stripe Dec 19, 2024
bdda2bb
`Merge branch 'joyceqin-MOBILESDK-2800' of github.com:stripe/stripe-i…
joyceqin-stripe Dec 19, 2024
9048ed0
pass badgeText into RowButton instead of defaultBadge label
joyceqin-stripe Dec 19, 2024
dd6dedb
reran snapshots
joyceqin-stripe Dec 19, 2024
238e94e
Merge branch 'master' into joyceqin-MOBILESDK-2800
joyceqin-stripe Dec 19, 2024
9b76fa9
separated var for badgetext
joyceqin-stripe Dec 19, 2024
53a55c8
Merge branch 'joyceqin-MOBILESDK-2800' of github.com:stripe/stripe-io…
joyceqin-stripe Dec 19, 2024
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
Expand Up @@ -437,4 +437,11 @@ extension String.Localized {
"Promotional text for Affirm, displayed in a button that lets the customer pay with Affirm"
)
}

static var default_text: String {
STPLocalizedString(
"Default",
"Label for identifying the default payment method."
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,14 @@ struct ElementsCustomer: Equatable, Hashable {
return ElementsCustomer(paymentMethods: paymentMethods, defaultPaymentMethod: defaultPaymentMethod, customerSession: customerSession)
}

func getDefaultPaymentMethod() -> STPPaymentMethod? {
let defaultSavedPaymentMethod = paymentMethods.first { $0.stripeId == defaultPaymentMethod }
return defaultSavedPaymentMethod
joyceqin-stripe marked this conversation as resolved.
Show resolved Hide resolved
}

func getDefaultOrFirstPaymentMethod() -> STPPaymentMethod? {
Copy link
Collaborator

Choose a reason for hiding this comment

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

in PaymentSheetVerticalViewController, we have this logic for the initialSelection

                    if let customer = elementsSession.customer,
                       let defaultPaymentMethod = customer.getDefaultOrFirstPaymentMethod() {
                        customerDefault = CustomerPaymentOption.stripeId(defaultPaymentMethod.stripeId)
                    }

This seems to indicate that the first payment method can become the default. Is this true? Ultimately, i'm trying to wrap my head around when we would access defaultPaymentMethod vs defaultOrFirst.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

From my understanding, the selected payment method should be the default if it exists or the first payment method in the customer's list of saved payment methods. However, the default badge itself should only be displayed if there is a set default in the elementsSession customer.

So we access defaultOrFirst when trying to determine the selected payment method, while we access defaultPaymentMethod to determine if the default badge should be shown and which payment method to show it on.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah thanks for the explanation!

// if customer has a default payment method from the elements session, return the default payment method
let defaultSavedPaymentMethod = paymentMethods.first { $0.stripeId == defaultPaymentMethod }
let defaultSavedPaymentMethod = getDefaultPaymentMethod()
joyceqin-stripe marked this conversation as resolved.
Show resolved Hide resolved
if let defaultSavedPaymentMethod = defaultSavedPaymentMethod {
return defaultSavedPaymentMethod
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ extension LinkPaymentMethodPicker {

private let defaultBadge = LinkBadgeView(
type: .neutral,
text: STPLocalizedString("Default", "Label for identifying the default payment method.")
text: String.Localized.default_text
)

private let alertIconView: UIImageView = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,9 @@ extension CustomerSavedPaymentMethodsCollectionViewController: UICollectionViewD

cell.setViewModel(viewModel.toSavedPaymentOptionsViewControllerSelection(),
cbcEligible: cbcEligible,
allowsPaymentMethodRemoval: configuration.paymentMethodRemove)
allowsPaymentMethodRemoval: configuration.paymentMethodRemove,
allowsSetAsDefaultPM: false,
showDefaultPMBadge: false)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm guessing customerSheet changes will come at a later time?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Bella said that the CustomerSheet should not ever display a default badge because it's implied that the selected payment method in CustomerSheet is your default.

cell.delegate = self
cell.isRemovingPaymentMethods = self.collectionView.isRemovingPaymentMethods
cell.appearance = appearance
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import UIKit
// MARK: - Constants
/// Entire cell size
private let cellSize: CGSize = CGSize(width: 106, height: 94)
private let cellSizeWithDefaultBadge: CGSize = CGSize(width: 106, height: 112)
Comment on lines 18 to +19
Copy link
Collaborator

Choose a reason for hiding this comment

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

What's the harm in making all the cells the new size to account for the possible default badge? What happens if we use the old size? Would be preferred if we can avoid swapping sizes.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The main issue there is that in the Figma, the height of the sheet changes when edit mode is on, but if we just increase the size of the cells constantly, then there will just be extra space under the PMs and the height won't change.

/// Size of the rounded rectangle that contains the PM logo
let roundedRectangleSize = CGSize(width: 100, height: 64)
private let paymentMethodLogoSize: CGSize = CGSize(width: 54, height: 40)
Expand All @@ -24,12 +25,13 @@ private let paymentMethodLogoSize: CGSize = CGSize(width: 54, height: 40)
/// For internal SDK use only
@objc(STP_Internal_SavedPaymentMethodCollectionView)
class SavedPaymentMethodCollectionView: UICollectionView {
init(appearance: PaymentSheet.Appearance) {
init(appearance: PaymentSheet.Appearance, showDefaultPMBadge: Bool = false) {
joyceqin-stripe marked this conversation as resolved.
Show resolved Hide resolved
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.sectionInset = UIEdgeInsets(
top: -6, left: PaymentSheetUI.defaultPadding, bottom: 0,
right: PaymentSheetUI.defaultPadding)
self.showDefaultPMBadge = showDefaultPMBadge
layout.itemSize = cellSize
layout.minimumInteritemSpacing = 12
layout.minimumLineSpacing = 4
Expand All @@ -43,13 +45,23 @@ class SavedPaymentMethodCollectionView: UICollectionView {
}

var isRemovingPaymentMethods: Bool = false
let showDefaultPMBadge: Bool

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override var intrinsicContentSize: CGSize {
return CGSize(width: UIView.noIntrinsicMetric, height: 100)
return showDefaultPMBadge && isRemovingPaymentMethods ? CGSize(width: UIView.noIntrinsicMetric, height: 118) : CGSize(width: UIView.noIntrinsicMetric, height: 100)
}

func updateLayout() {
guard let layout = collectionViewLayout as? UICollectionViewFlowLayout else { return }
let newItemSize = showDefaultPMBadge && isRemovingPaymentMethods ? cellSizeWithDefaultBadge : cellSize
joyceqin-stripe marked this conversation as resolved.
Show resolved Hide resolved
guard newItemSize != layout.itemSize else { return }
layout.itemSize = newItemSize
collectionViewLayout.invalidateLayout()
invalidateIntrinsicContentSize()
}
}

Expand Down Expand Up @@ -91,11 +103,31 @@ extension SavedPaymentMethodCollectionView {
button.accessibilityLabel = String.Localized.edit
return button
}()
lazy var defaultBadge: UILabel = {
let label = UILabel()
label.font = appearance.scaledFont(for: appearance.font.base.regular, style: .caption1, maximumPointSize: 20)
label.textColor = appearance.colors.textSecondary
label.adjustsFontForContentSizeCategory = true
label.text = String.Localized.default_text
label.isHidden = true
return label
}()

fileprivate var viewModel: SavedPaymentOptionsViewController.Selection?
var isDefaultPM: Bool = false

var isRemovingPaymentMethods: Bool = false {
didSet {
if showDefaultPMBadge {
if isRemovingPaymentMethods {
activateDefaultBadge()
defaultBadge.isHidden = !isDefaultPM
joyceqin-stripe marked this conversation as resolved.
Show resolved Hide resolved
joyceqin-stripe marked this conversation as resolved.
Show resolved Hide resolved
}
else {
deactivateDefaultBadge()
defaultBadge.isHidden = true
}
}
update()
}
}
Expand All @@ -110,14 +142,16 @@ extension SavedPaymentMethodCollectionView {

var cbcEligible: Bool = false
var allowsPaymentMethodRemoval: Bool = true
var allowsSetAsDefaultPM: Bool = false
var showDefaultPMBadge: Bool = false

/// Indicates whether the cell for a saved payment method should display the edit icon.
/// True if payment methods can be removed or edited (will update this to include allowing set as default)
/// True if payment methods can be removed or edited
var showEditIcon: Bool {
guard UpdatePaymentMethodViewModel.supportedPaymentMethods.contains(where: { viewModel?.savedPaymentMethod?.type == $0 }) else {
fatalError("Payment method does not match supported saved payment methods.")
}
return allowsPaymentMethodRemoval || (viewModel?.savedPaymentMethod?.isCoBrandedCard ?? false && cbcEligible)
return allowsSetAsDefaultPM || allowsPaymentMethodRemoval || (viewModel?.savedPaymentMethod?.isCoBrandedCard ?? false && cbcEligible)
}

// MARK: - UICollectionViewCell
Expand All @@ -142,12 +176,14 @@ extension SavedPaymentMethodCollectionView {
paymentMethodLogo.contentMode = .scaleAspectFit
accessoryButton.addTarget(self, action: #selector(didSelectAccessory), for: .touchUpInside)
let views = [
label, shadowRoundedRectangle, paymentMethodLogo, plus, selectedIcon, accessoryButton,
label, shadowRoundedRectangle, paymentMethodLogo, plus, selectedIcon, accessoryButton, defaultBadge
]
views.forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview($0)
}
labelBottomConstraint = label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
guard let labelBottomConstraint else { return }
NSLayoutConstraint.activate([
shadowRoundedRectangle.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 6),
shadowRoundedRectangle.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
Expand All @@ -159,7 +195,7 @@ extension SavedPaymentMethodCollectionView {

label.topAnchor.constraint(
equalTo: shadowRoundedRectangle.bottomAnchor, constant: 4),
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
labelBottomConstraint,
label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 2),
label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),

Expand Down Expand Up @@ -188,6 +224,7 @@ extension SavedPaymentMethodCollectionView {
equalTo: contentView.trailingAnchor, constant: 0),
accessoryButton.topAnchor.constraint(
equalTo: contentView.topAnchor, constant: 0),

])
}

Expand All @@ -208,15 +245,20 @@ extension SavedPaymentMethodCollectionView {
}
}

// MARK: - Internal Methods
private var labelBottomConstraint: NSLayoutConstraint?
private var labelHeightConstraint: NSLayoutConstraint?
joyceqin-stripe marked this conversation as resolved.
Show resolved Hide resolved
private var defaultBadgeConstraints: [NSLayoutConstraint] = []

func setViewModel(_ viewModel: SavedPaymentOptionsViewController.Selection, cbcEligible: Bool, allowsPaymentMethodRemoval: Bool) {
// MARK: - Internal Methods
func setViewModel(_ viewModel: SavedPaymentOptionsViewController.Selection, cbcEligible: Bool, allowsPaymentMethodRemoval: Bool, allowsSetAsDefaultPM: Bool, showDefaultPMBadge: Bool) {
paymentMethodLogo.isHidden = false
plus.isHidden = true
shadowRoundedRectangle.isHidden = false
self.viewModel = viewModel
self.cbcEligible = cbcEligible
self.allowsPaymentMethodRemoval = allowsPaymentMethodRemoval
self.allowsSetAsDefaultPM = allowsSetAsDefaultPM
self.showDefaultPMBadge = showDefaultPMBadge
update()
}

Expand Down Expand Up @@ -324,7 +366,6 @@ extension SavedPaymentMethodCollectionView {
selectedIcon.isHidden = true
layer.shadowOpacity = 0
}

if isRemovingPaymentMethods {
if case .saved = viewModel, showEditIcon {
accessoryButton.isHidden = false
Expand All @@ -340,7 +381,6 @@ extension SavedPaymentMethodCollectionView {
plus.alpha = 0.6
label.textColor = appearance.colors.text.disabledColor
}

} else if isSelected {
accessoryButton.isHidden = true
shadowRoundedRectangle.isEnabled = true
Expand Down Expand Up @@ -372,6 +412,37 @@ extension SavedPaymentMethodCollectionView {
}()
}
}

private func activateDefaultBadge() {
labelHeightConstraint = label.heightAnchor.constraint(equalToConstant: 20)
guard let labelBottomConstraint, let labelHeightConstraint else { return }
NSLayoutConstraint.deactivate([
labelBottomConstraint
])
NSLayoutConstraint.activate([
labelHeightConstraint
])
defaultBadgeConstraints = [
defaultBadge.topAnchor.constraint(
equalTo: label.bottomAnchor, constant: 4),
defaultBadge.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
defaultBadge.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 2),
defaultBadge.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
]
NSLayoutConstraint.activate(defaultBadgeConstraints)
}

private func deactivateDefaultBadge() {
guard let labelHeightConstraint, let labelBottomConstraint else { return }
NSLayoutConstraint.deactivate(defaultBadgeConstraints)
NSLayoutConstraint.deactivate([
labelHeightConstraint
])
NSLayoutConstraint.activate([
labelBottomConstraint
])
}

}

// A circle with an image in the middle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ class SavedPaymentOptionsViewController: UIViewController {
}
set {
collectionView.isRemovingPaymentMethods = newValue
collectionView.performBatchUpdates({
collectionView.reloadSections(IndexSet(integer: 0))
animateHeightChange{self.collectionView.updateLayout()}
})
UIView.transition(with: collectionView,
duration: 0.3,
options: .transitionCrossDissolve,
Expand All @@ -147,6 +151,12 @@ class SavedPaymentOptionsViewController: UIViewController {
}
}
}

var hasDefault: Bool {
guard configuration.allowsSetAsDefaultPM, let defaultPaymentMethod = elementsSession.customer?.getDefaultPaymentMethod() else { return false }
return viewModels.contains(where: { $0.savedPaymentMethod?.stripeId == defaultPaymentMethod.stripeId })
}

var bottomNoticeAttributedString: NSAttributedString? {
if case .saved(let paymentMethod, _) = selectedPaymentOption {
if paymentMethod.usBankAccount != nil {
Expand Down Expand Up @@ -267,7 +277,7 @@ class SavedPaymentOptionsViewController: UIViewController {

// MARK: - Views
private lazy var collectionView: SavedPaymentMethodCollectionView = {
let collectionView = SavedPaymentMethodCollectionView(appearance: appearance)
let collectionView = SavedPaymentMethodCollectionView(appearance: appearance, showDefaultPMBadge: hasDefault)
collectionView.delegate = self
collectionView.dataSource = self
return collectionView
Expand Down Expand Up @@ -508,8 +518,15 @@ extension SavedPaymentOptionsViewController: UICollectionViewDataSource, UIColle
stpAssertionFailure()
return UICollectionViewCell()
}
cell.setViewModel(viewModel, cbcEligible: cbcEligible, allowsPaymentMethodRemoval: self.configuration.allowsRemovalOfPaymentMethods)
cell.setViewModel(viewModel, cbcEligible: cbcEligible, allowsPaymentMethodRemoval: self.configuration.allowsRemovalOfPaymentMethods, allowsSetAsDefaultPM: configuration.allowsSetAsDefaultPM, showDefaultPMBadge: hasDefault)
cell.delegate = self
let isDefaultPM: Bool = {
guard self.hasDefault,
let savedPMId = viewModel.savedPaymentMethod?.stripeId,
let defaultPMId = self.elementsSession.customer?.defaultPaymentMethod else { return false }
return savedPMId == defaultPMId
}()
joyceqin-stripe marked this conversation as resolved.
Show resolved Hide resolved
cell.isDefaultPM = isDefaultPM
cell.isRemovingPaymentMethods = self.collectionView.isRemovingPaymentMethods
cell.appearance = appearance

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ final class SavedPaymentMethodRowButton: UIView {
}
}

let showDefaultPMBadge: Bool

private var isEditing: Bool {
switch state {
case .selected, .unselected:
Expand Down Expand Up @@ -90,15 +92,17 @@ final class SavedPaymentMethodRowButton: UIView {
}()

private lazy var rowButton: RowButton = {
let button: RowButton = .makeForSavedPaymentMethod(paymentMethod: paymentMethod, appearance: appearance, rightAccessoryView: chevronButton, didTap: handleRowButtonTapped)
let button: RowButton = .makeForSavedPaymentMethod(paymentMethod: paymentMethod, appearance: appearance, showDefaultPMBadge: showDefaultPMBadge, rightAccessoryView: chevronButton, didTap: handleRowButtonTapped)

return button
}()

init(paymentMethod: STPPaymentMethod,
appearance: PaymentSheet.Appearance) {
appearance: PaymentSheet.Appearance,
showDefaultPMBadge: Bool = false) {
self.paymentMethod = paymentMethod
self.appearance = appearance
self.showDefaultPMBadge = showDefaultPMBadge
super.init(frame: .zero)

addAndPinSubview(rowButton)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,13 @@ class VerticalSavedPaymentMethodsViewController: UIViewController {
}

/// Indicates whether the chevron should be shown
/// True if any saved payment methods can be removed or edited (will update this to include allowing set as default)
/// True if any saved payment methods can be removed or edited
var canRemoveOrEdit: Bool {
let hasSupportedSavedPaymentMethods = paymentMethods.allSatisfy{ UpdatePaymentMethodViewModel.supportedPaymentMethods.contains($0.type) }
guard hasSupportedSavedPaymentMethods else {
fatalError("Saved payment methods contain unsupported payment methods.")
}
return canRemovePaymentMethods || canEditPaymentMethods
return configuration.allowsSetAsDefaultPM || canRemovePaymentMethods || canEditPaymentMethods
}

private var selectedPaymentMethod: STPPaymentMethod? {
Expand Down Expand Up @@ -177,7 +177,8 @@ class VerticalSavedPaymentMethodsViewController: UIViewController {
private func buildPaymentMethodRows(paymentMethods: [STPPaymentMethod]) -> [SavedPaymentMethodRowButton] {
return paymentMethods.map { paymentMethod in
let button = SavedPaymentMethodRowButton(paymentMethod: paymentMethod,
appearance: configuration.appearance)
appearance: configuration.appearance,
showDefaultPMBadge: configuration.allowsSetAsDefaultPM && paymentMethod.stripeId == elementsSession.customer?.defaultPaymentMethod)
joyceqin-stripe marked this conversation as resolved.
Show resolved Hide resolved
button.delegate = self
return button
}
Expand Down Expand Up @@ -363,7 +364,8 @@ extension VerticalSavedPaymentMethodsViewController: UpdatePaymentMethodViewCont
}

// Create the new button
let newButton = SavedPaymentMethodRowButton(paymentMethod: updatedPaymentMethod, appearance: configuration.appearance)
let newButton = SavedPaymentMethodRowButton(paymentMethod: updatedPaymentMethod, appearance: configuration.appearance, showDefaultPMBadge: configuration.allowsSetAsDefaultPM && updatedPaymentMethod.stripeId == elementsSession.customer?.defaultPaymentMethod)

newButton.delegate = self
newButton.previousSelectedState = oldButton.previousSelectedState
newButton.state = oldButton.state
Expand Down
Loading
Loading