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

[MBL-1307] Show processing view while payment is processing #2013

Merged
merged 6 commits into from Apr 2, 2024

Conversation

ifosli
Copy link
Contributor

@ifosli ifosli commented Apr 1, 2024

📲 What

Show processing view while payment is processing. This prevents further user interaction until it's dismissed.

Note: It's very important that we make sure that regardless of how checkout goes/where it fails, the processing view will get dismissed. It will lock the app otherwise. The original pledge VC ties the processing view to specific API calls, but we can't do that for post campaign pledges, since we require multiple different API calls to finish the payment flow. Please help me double check that there aren't edge cases that would leave the processing screen up indefinitely!

Note: The processing screen does hide immediately once apple pay is dismissed - I have no idea why the gif is showing it weird.

👀 See

Jira

Pledge flow Apple pay flow
Simulator Screen Recording - iPhone 15 Pro Max - 2024-04-01 at 16 01 41 Simulator Screen Recording - iPhone 15 Pro Max - 2024-04-01 at 16 04 20

✅ Acceptance criteria

  • Processing overlay shows when it should and hides again when it should

⏰ TODO

  • Add tests

@ifosli ifosli self-assigned this Apr 1, 2024
@@ -296,6 +311,7 @@ final class PostCampaignCheckoutViewController: UIViewController, MessageBannerV
guard error == nil, status == .succeeded else {
self.messageBannerViewController?
.showBanner(with: .error, message: Strings.Something_went_wrong_please_try_again())
self.viewModel.inputs.checkoutTerminated()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't like how many different places we're calling checkoutTerminated in this - it feels messy. But I can't think of a better way to implement this. Let me know if y'all have any ideas.

Copy link
Contributor

Choose a reason for hiding this comment

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

You could write a wrapper method like

checkoutTerminated(withErrorMessage message: String?) {
    self.messageBannerViewController?
            .showBanner(with: .error, message: message ?? Strings.Something_went_wrong_please_try_again())
    self.viewModel.inputs.checkoutTerminated()
}

which would consolidate two of these.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That feels more confusing to me actually, since then the checkoutTerminated would sometimes be nested and sometimes not. I think I'm going to leave this as-is if you're okay with it. I also think it's clearer now that I got rid of the extraneous calls, so thanks for that call-out!

The other thing I tried was having the processing view tied directly to api calls the way the PledgeViewModel does, but it did disappear and reappear between linked calls, so I say that very much did not work.

@ifosli ifosli marked this pull request as ready for review April 1, 2024 22:24
validateCheckoutError.mapConst(true), // Card validation error terminates flow.
self.checkoutTerminatedProperty.signal.mapConst(true), // Error/cancellation in VC.
checkoutCompleteSignal.signal.mapConst(true) // Checkout completed.
)
Copy link
Contributor

Choose a reason for hiding this comment

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

I see what you mean about worrying about edge cases in here. I don't see any obvious errors - but for readability, you could sort the merge into clearer groups of true and false.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

Copy link
Contributor

@amy-at-kickstarter amy-at-kickstarter left a comment

Choose a reason for hiding this comment

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

Some suggestions for clarity but overall LGTM

@@ -391,10 +403,25 @@ public class PostCampaignCheckoutViewModel: PostCampaignCheckoutViewModelType,
.map { $0 }

self.checkoutError = checkoutCompleteSignal.signal.errors()

self.processingViewIsHidden = Signal.merge(
initialData.mapConst(true),
Copy link
Contributor

Choose a reason for hiding this comment

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

Because this property starts as true I don't think this one is necessary.

@@ -12,11 +12,14 @@ final class PostCampaignCheckoutViewModelTests: XCTestCase {
Never
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add more tests for the processing view in here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, of course! I wanted to make sure we were on the same page about going with this approach before I wrote proper tests. But I think we're good now!

@@ -296,6 +311,7 @@ final class PostCampaignCheckoutViewController: UIViewController, MessageBannerV
guard error == nil, status == .succeeded else {
self.messageBannerViewController?
.showBanner(with: .error, message: Strings.Something_went_wrong_please_try_again())
self.viewModel.inputs.checkoutTerminated()
Copy link
Contributor

Choose a reason for hiding this comment

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

You could write a wrapper method like

checkoutTerminated(withErrorMessage message: String?) {
    self.messageBannerViewController?
            .showBanner(with: .error, message: message ?? Strings.Something_went_wrong_please_try_again())
    self.viewModel.inputs.checkoutTerminated()
}

which would consolidate two of these.

@@ -430,6 +447,7 @@ extension PostCampaignCheckoutViewController: STPApplePayContextDelegate {
completion: @escaping StripeApplePay.STPIntentClientSecretCompletionBlock
) {
guard let paymentIntentClientSecret = self.applePayPaymentIntent else {
self.viewModel.inputs.checkoutTerminated()
Copy link
Contributor

Choose a reason for hiding this comment

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

These calls aren't needed - AFAIK everywhere that completion(nil, error) is called will end up below in case: .error of func applePayContext(didCompleteWith:error:). Tested this with a breakpoint and by breaking one of the calls.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, thanks! That makes this nicer :) I wasn't sure how to generate one of these errors so I really appreciate that!

Copy link
Contributor

Choose a reason for hiding this comment

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

Ha, me neither, but I just set something to nil and checked what happened 😆

@ifosli ifosli merged commit ec45e46 into main Apr 2, 2024
5 checks passed
@ifosli ifosli deleted the checkoutVcProcessingView branch April 2, 2024 18:08
warrenwegs pushed a commit that referenced this pull request Apr 2, 2024
* Show processing view while payment is processing

* Support rest of payment flow

* Test processing view in apple pay flow

* Minor edits for clarity and more tests
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.

None yet

3 participants