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

Update cards in vertical mode #3595

Merged
merged 18 commits into from
May 24, 2024
Merged

Update cards in vertical mode #3595

merged 18 commits into from
May 24, 2024

Conversation

porter-stripe
Copy link
Collaborator

@porter-stripe porter-stripe commented May 21, 2024

Summary

  • Updates UpdateCardViewControllerDelegate to pass itself through the delegate methods than update it so the users pop the update VC rather than the UpdateCardViewController popping itself.
  • Pipes in isCBCEligible and implements UpdateCardViewControllerDelegate in VerticalSavedPaymentMethodsViewController
  • Fixes the UIStackView setup in UpdateCardViewController to resolve a janky push animation (same as we saw earlier in the project)
  • Updates UI test to update a card brand and delete card from the update view controller
  • Fixes UpdateCardViewControllerSnapshotTests to not define a hardcoded height for it's view while testing
  • Changes the behavior of the VerticalSavedPaymentMethodsViewController to only allow removal and not selection or updating when 1 payment method is present and it is not update-able. See below for figma
    CleanShot 2024-05-22 at 20 22 27@2x

Motivation

  • Vert mode
Simulator.Screen.Recording.-.iPhone.15.Plus.-.2024-05-24.at.09.06.57.mp4

Testing

  • Manual
  • Updated UI test

Changelog

N/A

@stripe stripe deleted a comment from emerge-tools bot May 21, 2024
Copy link

github-actions bot commented May 23, 2024

⚠️ Missing Translations

The following translations are missing in Lokalise. While they don't need to be downloaded into the codebase as part of this PR, they do need to exist in Lokalise so that they can be downloaded as part of the release process.

Remove payment method

By adding the label ship without translations to this PR, I acknowledge that there are missing translations.

@porter-stripe porter-stripe marked this pull request as ready for review May 24, 2024 15:07
@porter-stripe porter-stripe requested review from a team as code owners May 24, 2024 15:07
@porter-stripe porter-stripe requested a review from yuki-stripe May 24, 2024 15:07
/// - There is exactly one payment method available at init time.
/// - The single available payment method is not a co-branded card.
/// In this mode, the user can only delete the payment method; updating or selecting other payment methods is disabled.
private(set) lazy var isRemoveOnlyMode: Bool = {
Copy link
Collaborator

Choose a reason for hiding this comment

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

It feels funny that this is lazy. It means that its value can change depending on when it's called, which doesn't seem right. Theoretically if paymentMethods changes before this is called, its value could be incorrect.

This seems like it should be calculated exactly at initialization 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.

Good point!

/// - The single available payment method is not a co-branded card.
/// In this mode, the user can only delete the payment method; updating or selecting other payment methods is disabled.
private(set) lazy var isRemoveOnlyMode: Bool = {
let hasCoBrandedCards = !paymentMethodRows.filter { $0.paymentMethod.isCoBrandedCard }.isEmpty
Copy link
Collaborator

Choose a reason for hiding this comment

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

why not paymentMethods.filter { $0.isCoBrandedCard }...

@@ -165,6 +190,8 @@ class VerticalSavedPaymentMethodsViewController: UIViewController {
}

private func completeSelection() {
// Edge-case: Dismiss `UpdateViewController` if presented, this can occur if `completeSelection` is called before `UpdateViewController` is popped when we remove the last payment method via the `UpdateViewController`
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice comment. Can we eliminate this edge case?

Telling the bottomSheetController to pop the content VC multiple times doesn't seem right, since we could inadvertently pop multiple VCs off when we only mean to pop the update VC. Maybe we should either tell the bottom sheet controller to pop the updateViewController specifically (and have that no-op if it doesn't find it) or otherwise make sure we're only popping the content VC once.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah this is a little confusing. Today, when this edge-case occurs and we double call popContentViewController it will actually no-op on the second call since the bottomSheetController on the update VC is nil after it has been popped since it is no longer in the bottom sheet content stack, but this definitely isn't obvious. From what I can tell popping a VC multiple times is safe due to this logic.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah ok. I feel like there's still an even better way to write this so that like, the update delegate's remove method looks like:

  1. Remove the PM
  2. Pop the VC
  3. Exit the flow if necessary.

but I won't block on it.

guard let oldButton = paymentMethodRows.first(where: { $0.paymentMethod.stripeId == paymentMethod.stripeId }),
let oldButtonModelIndex = paymentMethodRows.firstIndex(of: oldButton),
let oldButtonViewIndex = stackView.arrangedSubviews.firstIndex(of: oldButton) else {
return
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should probably stpAssert here

Comment on lines 299 to 300
newButton.state = .editing(allowsRemoval: canRemovePaymentMethods,
allowsUpdating: updatedPaymentMethod.isCoBrandedCard && isCBCEligible)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I wonder if this could be newButton.state = oldButton.state?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ah yep. I was thinking canRemovePaymentMethods could change after an update but it definitely won't after a second look.

@@ -24,13 +24,18 @@ final class VerticalSavedPaymentMethodsViewControllerSnapshotTests: STPSnapshotT
_test_VerticalSavedPaymentMethodsViewControllerSnapshotTests(darkMode: false, appearance: ._testMSPaintTheme)
}

func _test_VerticalSavedPaymentMethodsViewControllerSnapshotTests(darkMode: Bool, appearance: PaymentSheet.Appearance = .default) {
func test_VerticalSavedPaymentMethodsViewControllerSnapshotTestsLightModeRemoveOnlyMode() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

super nit: I'd remove lightMode in this test method name.

@porter-stripe porter-stripe requested a review from yuki-stripe May 24, 2024 18:05
@porter-stripe porter-stripe merged commit 89f0b88 into master May 24, 2024
5 checks passed
@porter-stripe porter-stripe deleted the porter/MOBILESDK-2028-2 branch May 24, 2024 18:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants