-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Feature: Add UI for SCA error banner and re-authentication flow #46319
Conversation
Looked at this locally. I think we should apply these changes so that (A) the authenticate button only shows if the error banner also shows, and (B) so that the error banner will show even if the user is on a free trial and even if there is no amount owed. Lemme know what you think. diff --git a/src/libs/SubscriptionUtils.ts b/src/libs/SubscriptionUtils.ts
index 0cc4e05f7b..8516d8e082 100644
--- a/src/libs/SubscriptionUtils.ts
+++ b/src/libs/SubscriptionUtils.ts
@@ -175,7 +175,7 @@ function hasAmountOwed(): boolean {
* @returns Whether there is a card authentication error.
*/
function hasCardAuthenticatedError() {
- return stripeCustomerId?.status === 'authentication_required' && amountOwed === 0;
+ return stripeCustomerId?.status === 'authentication_required' && getAmountOwed() === 0;
}
/**
@@ -460,5 +460,6 @@ export {
getCardForSubscriptionBilling,
hasSubscriptionGreenDotInfo,
hasRetryBillingError,
+ hasCardAuthenticatedError,
PAYMENT_STATUS,
};
diff --git a/src/pages/settings/Subscription/CardSection/CardSection.tsx b/src/pages/settings/Subscription/CardSection/CardSection.tsx
index df3c6809e1..a501c61a8b 100644
--- a/src/pages/settings/Subscription/CardSection/CardSection.tsx
+++ b/src/pages/settings/Subscription/CardSection/CardSection.tsx
@@ -32,6 +32,7 @@ import CardSectionDataEmpty from './CardSectionDataEmpty';
import RequestEarlyCancellationMenuItem from './RequestEarlyCancellationMenuItem';
import type {BillingStatusResult} from './utils';
import CardSectionUtils from './utils';
+import { hasCardAuthenticatedError } from '@libs/SubscriptionUtils';
function CardSection() {
const [isRequestRefundModalVisible, setIsRequestRefundModalVisible] = useState(false);
@@ -85,7 +86,9 @@ function CardSection() {
BillingBanner = <TrialStartedBillingBanner />;
} else if (SubscriptionUtils.hasUserFreeTrialEnded()) {
BillingBanner = <TrialEndedBillingBanner />;
- } else if (billingStatus) {
+ }
+
+ if (billingStatus) {
BillingBanner = (
<SubscriptionBillingBanner
title={billingStatus.title}
@@ -144,7 +147,7 @@ function CardSection() {
large
/>
)}
- {billingStatus?.isAuthenticationRequired !== undefined && (
+ {hasCardAuthenticatedError() && (
<Button
text={translate('subscription.cardSection.authenticatePayment')}
isDisabled={isOffline || !billingStatus?.isAuthenticationRequired} |
@blimpich Looks a bit weird this part: "getAmountOwed() === 0", do we need to check for owed amount for authentication error? Shouldn't it be only like this return stripeCustomerId?.status === 'authentication_required' ? |
This confuses me too, and to be completely honest I don't understand why that is the logic, but that is the logic that we have in the Old Dot version of the application too, so we should try to mimic it. I looked into why that code was written that way in the old version of the app, but there wasn't really an explanation in the PR that added it, so 🤷. Lets keep it with the owed amount conditional. My guess is that if there is an owed amount we have prioritized showing a different error banner instead of the authentication error banner. |
@blimpich Can you please verify it works or not |
@waterim I will try to get to it today. I was on vacation yesterday so couldn't get to it. |
Error banner looks good but when I click "Authenticate" it just opens up a empty billing card form. It looks like the problem is that we clear the authenticationLink onyx key here, which means we aren't able to reuse it when we try to reauthenticate. The clearing of the authentication link also seems to be how we decide to close the the iframe modal in the first place. That's an issue. We need the modal to close without clearing the authentication link from our onyx data. @waterim can you figure out a way to do that? Screen.Recording.2024-07-31.at.1.39.46.PM.mov |
I will try it tomorrow without clearing the link |
If we can clear it on success and keep it on failure then that should be good but I also don't see a problem with keeping it. There's nothing in that link that I'm worried about being exposed on the frontend. |
Hmmm, so the iframe opens but then closes before rendering. Not sure why that is. Screen.Recording.2024-08-01.at.2.15.35.PM.mov |
I can make the modal not auto-close by removing this line but I still just get a blank page instead of the stripe verification screen. Probably something backend I need to adjust here. Looking into it. |
Ah, I think I've figured it out. Comes down to onyx updates. The old way we did this was we would call Lets do this:
The changes I'm going to make also mean that we shouldn't need to use makeRequestWithSideEffect here. The backend will update the onyx key and push it to the frontend. Does that sound good @waterim? |
Sounds great and makes a lot of sense for me know. thank you! |
@mananjadhav Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
I'll start with the review of this code, but I don't see any screenshots/videos for the testing. @waterim Can you please add them? |
@mananjadhav Its not possible to test it without a local backend and dev env stripe Also I will be able to upload a video with steps only when @blimpich ngrok is online (in 3-4 hours from now) If its okay for you you are able to go through code for now and when @blimpich will be online we can proceed with testing this flow manually |
@mananjadhav added video with the flow Firstly you will need to fail the 3ds secure and after this PRs flow starts from "Authenticate payment" |
@@ -81,7 +95,8 @@ function CardSection() { | |||
BillingBanner = <TrialStartedBillingBanner />; | |||
} else if (SubscriptionUtils.hasUserFreeTrialEnded()) { | |||
BillingBanner = <TrialEndedBillingBanner />; | |||
} else if (billingStatus) { | |||
} | |||
if (billingStatus) { |
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 else if
--> if
intentional?
Are we saying along with Trial/Trial ended banner we would show the authenticate payment button?
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.
I think I got the change now.
Reviewer Checklist
Screenshots/VideosAndroid: mWeb Chromemweb-chrome-sca-error.moviOS: NativeiOS: mWeb Safarimweb-safari-sca-error.movMacOS: Chrome / Safariweb-sca-error.movMacOS: Desktopdesktop-sca-error.mov |
@blimpich There is no popup shown on payment currency change right. Steps:
|
Correct. That is a known issue, choosing not to prioritize right now. |
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.
The code changes look good and also works well.
My iOS build is failing but this feature is anyway not available for native app.
Another follow up thing unrelated to the current PR could be, when clicking on Submit instead of Fail, Authenticate payment
modal doesn't have a good visible loader. This is I think loaded from iframe. The rest it looks good.
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.
Looks good and tests well but can we follow up on this comment I made awhile back?
The changes I'm going to make also mean that we shouldn't need to use makeRequestWithSideEffect here. The backend will update the onyx key and push it to the frontend.
It would be good to get rid of the side effect usage where we can, and I think we can here.
@waterim can you also update this branch with |
@blimpich Sure! |
@blimpich updated, can you test please? |
Ugh, I was wrong, I misunderstood one of the backend api endpoints and how it worked. @waterim can you please revert the changes related to getting rid of |
Sure! Will revert it tomorrow morning :) |
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.
Tested it again, works great! Lets merge this!!!
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
🚀 Deployed to staging by https://github.com/blimpich in version: 9.0.23-0 🚀
|
@mvtglobally yes staging points to prod stripe, sorry I should have written something here before you QA'ed. Please skip QA for this. |
🚀 Deployed to production by https://github.com/chiragsalian in version: 9.0.23-0 🚀
|
Details
Add UI for SCA error banner and re-authentication flow
Fixed Issues
$ #46064
PROPOSAL: N/A
Tests
NOTE: You need to connect to someone local backend to test live mode of the stripe
/settings/subscription/add-payment-card
Offline tests
Same as tests
QA Steps
None
PR Author Checklist
### Fixed Issues
section aboveTests
sectionOffline steps
sectionQA steps
sectiontoggleReport
and notonIconClick
)myBool && <MyComponent />
.src/languages/*
files and using the translation methodWaiting for Copy
label for a copy review on the original GH to get the correct copy.STYLE.md
) were followedAvatar
, I verified the components usingAvatar
are working as expected)/** comment above it */
this
properly so there are no scoping issues (i.e. foronClick={this.submit}
the methodthis.submit
should be bound tothis
in the constructor)this
are necessary to be bound (i.e. avoidthis.submit = this.submit.bind(this);
ifthis.submit
is never passed to a component event handler likeonClick
)StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)
)Avatar
is modified, I verified thatAvatar
is working as expected in all cases)ScrollView
component to make it scrollable when more elements are added to the page.main
branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTest
steps.Screenshots/Videos
Web
Screen.Recording.2024-08-12.at.23.39.49.mov