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
[MBL-1194] Implement Validate Checkout #1999
[MBL-1194] Implement Validate Checkout #1999
Conversation
β¦id' into scott/pcp/validate-checkout-confirm-payment
β¦/github.com/kickstarter/ios-oss into scott/pcp/validate-checkout-confirm-payment
fec43c3
to
7005ac7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly LGTM, but a couple things to address first:
- How will we handle saved credit cards (which have no
PaymentIntent
)? - Why do we need to decode the
GraphID
of a Checkout? Can this be resolved at the mutation level, instead of doing it in the client?
A few non-blocking nits:
- Is the VC the correct place to call Stripe? Should it be in the VM or will that break testability?
- Some miscellanea/style comments
Also left a few nits/comments, but those aren't blocking.
Kickstarter-iOS/Features/PledgeView/Controllers/PostCampaignCheckoutViewController.swift
Show resolved
Hide resolved
Kickstarter-iOS/Features/PledgeView/Controllers/PostCampaignCheckoutViewController.swift
Outdated
Show resolved
Hide resolved
Kickstarter-iOS/Features/PledgeView/Controllers/PostCampaignCheckoutViewController.swift
Show resolved
Hide resolved
@amy-at-kickstarter Looking into your other comments.
I spoke with the backend, and they would rather we did this. It sounded like they could (they do in other cases), but they aren't willing to spend the time updating the different pieces involved right now. |
da13cfc
to
4d7210e
Compare
@@ -211,7 +211,7 @@ public class ConfirmDetailsViewModel: ConfirmDetailsViewModelType, ConfirmDetail | |||
|
|||
/// Hide when there is a reward and shipping is enabled (accounts for digital rewards), and in a pledge context | |||
self.pledgeSummaryViewHidden = Signal.zip(baseReward, context).map { baseReward, context in | |||
(baseReward.isNoReward == false && baseReward.shipping.enabled) && context == .pledge | |||
baseReward.isNoReward == false && context == .pledge |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unrelated fix for showing the summary view on details
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π
Kickstarter-iOS/Features/ConfirmDetails/Controllers/ConfirmDetailsViewController.swift
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with some questions and nits
.observeValues { [weak self] _ in | ||
guard let self else { return } | ||
|
||
// TODO: Confirm paymentIntent using Stripe.confirmPayment() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this // TODO:
correct for the existing card case, too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes we'll have to confirm the payment either way using the intent
return | ||
} | ||
|
||
let paymentMethodId = intent.paymentMethodId! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Could also throw this let
into the above guard
statement, just in case.
} | ||
case let .savedCreditCard(savedCardId): | ||
self.viewModel.inputs | ||
.creditCardSelected(source: paymentSource, paymentMethodId: savedCardId, isNewPaymentMethod: false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π
@@ -9,6 +9,7 @@ public struct UserCreditCards: Decodable { | |||
public var id: String | |||
public var lastFour: String | |||
public var type: CreditCardType? | |||
public var stripeCardId: String? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yeah, I only added it to the GraphQL object. Good find.
@@ -211,7 +211,7 @@ public class ConfirmDetailsViewModel: ConfirmDetailsViewModelType, ConfirmDetail | |||
|
|||
/// Hide when there is a reward and shipping is enabled (accounts for digital rewards), and in a pledge context | |||
self.pledgeSummaryViewHidden = Signal.zip(baseReward, context).map { baseReward, context in | |||
(baseReward.isNoReward == false && baseReward.shipping.enabled) && context == .pledge | |||
baseReward.isNoReward == false && context == .pledge |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π
} | ||
|
||
return checkoutId | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any resolution on why this needs to be decoded from GraphQL? At a minimum, this should really have a //TODO:
explaining the hack.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yea i left an unfortunate comment earlier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its silly that they would give us a string, that we only use to send to one of their mutations, and not format it correctly for us
} | ||
|
||
let storedCardsValues = storedCardsEvent.values() | ||
.filter(second >>> isFalse) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Would prefer this to be a non-Prelude operator for clarity.
let selectedExistingCard = self.creditCardSelectedProperty.signal.skipNil() | ||
.filter { $0.isNewPaymentMethod == false } | ||
|
||
let newPaymentIntentEvent = initialData |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This only needs to happen when you're not adding a new card via the payment method selector, since in that case, we've already made a PI for you. Should this be attached to a different event than initialData
?
let selectedNewCreditCard = self.creditCardSelectedProperty.signal.skipNil() | ||
.filter { $0.isNewPaymentMethod } | ||
|
||
// Runs validation for new cards that were created with payment intents. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Loving these comments
π² What
When tapping pledge, we need to run this mutation so the backend can do some extra validations before we ask Stripe to do its thing.
For New Payment Methods
For Pre-Existing Payment Methods that were originally created with a setup intent
stripeCardId
I opted to make separate calls to this mutation depending on the case since they require enough distinct information to warrant it. There might be an opportunity to remove some duplicate code so if there are any nits please call them out!
The mutation accepts the following params:
STPAPIClient.shared.retrievePaymentIntent(withClientSecret: clientSecret)
for new cards, or thestripeCardId
property on existing cards.Extras
I also updated PostCampaignCheckoutViewController to use our
MessageBannerViewControllerPresenting
to show error messages when an API call fails.π€ Why
Gotta validate, ya dig?
β Acceptance criteria
β° TODO