-
Notifications
You must be signed in to change notification settings - Fork 679
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
Checkout Page Payment Information #2320
Checkout Page Payment Information #2320
Conversation
…age_payment_information
'Checking Credit Card Information', | ||
'Checking Credit Card Information', | ||
'Checking Credit Card Information', | ||
'Checking Credit Card Information' |
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 array still necessary anymore? Now all the steps result in the same text being rendered.
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.
Done 👍
Changed to something more meaningful.
.teardown() | ||
.then(() => { | ||
resetShouldTeardownDropin(); | ||
createDropinInstance(); |
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 is the difference between this effect and this teardown on line 71?
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 am not sure of the internals of the dropping, but Andy added it as part of the initial drop in work that he did for the mini cart. Here I had to move it into a diff function because of a case that can arise due to payment service failing.
Here is some background information.
The credit card checkout process is a 3 step process:
- Save billing address information on the cart
- Get payment nonce from braintree by submitting credit card information
- Save the payment nonce that we got from braintree in step 2.
After step 2, the braintree dropin changes it UI from a form to a summary kind of component which does not confine with out UX.
If the save service in step 3 fails, the dropin needs to be reset to the form. This is where tear down comes into picture. When that happens, we send a signal to the braintree dropin to teardown, which in braintree terms is reset so the user can enter the new payment information and submit again.
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 reason I asked was to try to get an understanding of both cases and see if there was some simplification we could make. In this instance it looks like the original .teardown()
call was used as a sort of cleanup where the modal/dropin was unmounted. That doesn't seem to need the same logic as you've done in your async calls so there's nothing to do here.
There is an edge case I can forsee causing some errors be thrown. If shouldTeardownDropin
is true
the effect will run triggering teardown/recreation of the dropin instance. If a user closes the form during this effect's execution an error will throw because the dropin will mount without a target. That's why we added the didClose
logic in the past.
@revanth0212
|
The first one is a graphql bug. Second is being handled in PWA-523 |
Thanks for clarifying @revanth0212 ! The change is UX approved. |
// behave correctly. | ||
return () => { | ||
didClose = true; | ||
}; |
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.
Now that I look a little closer at this effect I realize it is not functioning as intended with didClose
. The original effect from the dropin file defined didClose
within the same closure as the definition for the createDropinInstance
function. This meant that when the component unmounted and the effect's callback was invoked the didClose
referenced within the createDropinInstance
function was updated and handled correctly.
Here's a simplified example. The whole point is to create a thing
if we're mounted or ignore it if we're unmounted.
const [thing, setThing] = useState();
useEffect(() => {
let unmounted = false;
async function attach() {
const ref = await createThingThatNeedsDom();
// If `unmounted` is still "false" by the time the awaited function resolves we set the ref in state
// but if it is "true" because we unmounted then we should just cleanup and never set state.
if (unmounted) {
ref.cleanup();
}
else {
setThing(ref);
}
}
// Run the async attach.
attach();
return () => {
unmounted = true;
}
}, [
// No dependencies because this component runs on mount.
]);
I've provided this example as a way to show you how it was used in the past because as implemented, createDropinInstance
can break if we unmount before we get to setDropinInstance(...)
. I realize you broke out the creation function because you need the logic twice but it doesn't make sense as written now. createDropinInstance(didClose);
will always be called with false
.
Please refactor this to correctly utilize the previous logic.
@revanth0212 As discussed, check if you can handle this scenario same as Shipping info. On hitting review order button on blank billing fields... we are submitting to GraphQL which return error on UI like below. It's good if we can check all mandatory fields are entered before we submit to graphql. |
QA Pass, need review on recent commits. |
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 saw your message in Slack - down to talk tomorrow morning when I get online.
* Validate billing address fields and only process with | ||
* submit if there are no errors. | ||
*/ | ||
validateBillingAddressForm(); |
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 there no way to validate these fields on blur? Check out how other forms do it. I'm not sure why we didn't use validation on the old mini cart.
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.
Discussed this on the call, commenting for notes.
We can not use the same techniques as in the previous forms, because of the way the form is submitted. In other forms, we submit using the onSubmit
prop on the form so the validation is done by the form. In this case, we submit manually, form just serves as a context provider. Hence we have to perform the form validation manually before submitting it.
const isFieldRequired = useCallback( | ||
value => { | ||
if (isBillingAddressSame) { | ||
/** | ||
* Informed validator functions return `undefined` is | ||
* validation is `true` | ||
*/ | ||
return undefined; | ||
} else { | ||
return isRequired(value); | ||
} | ||
}, | ||
[isBillingAddressSame] | ||
); |
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.
Why is this form being submitted if isBillingAddressSame
is true
? Do we need to submit anything here? I would think if the billing and shipping address are the same (as in the user clicked the checkbox) then we would have sent that information via the graphQL cart mutation which means that this form shouldn't even render.
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 billing address fields are always rendered, they are just hidden if the checkbox is checked. This was due to a review comment way up on the top 😅 . Hence when I have written a wrapper around the isRequired
to only validate if the boolean is false.
@@ -5,19 +5,6 @@ import gql from 'graphql-tag'; | |||
// https://github.com/apollographql/eslint-plugin-graphql/issues/99 | |||
/* eslint-disable graphql/template-strings */ | |||
|
|||
export const GET_ALL_COUNTRIES = gql` |
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.
Why did you remove this query? We were previously validating the countries but that has now changed to just checking that the field is there, not that it's valid. If the change to validation was necessary (I'm not sure it is as we can just hide the form right?) then lets try to find a way to include country validation so we don't lose this functionality.
Edit: Add comment here w/ ticket for global country validation
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.
We were using this query to get the list of countries. The list of countries are being used to validate the region code. But the region code validator that we have only works for US. It does not work for other countries. Hence I am doing what Shipping Address form does, only validate if it is present or not.
This is not the right place for that. A robust validate function needs to be written into the new Region component to handle such cases. It will be handled in https://jira.corp.magento.com/browse/PWA-552.
packages/venia-ui/lib/components/CheckoutPage/PaymentInformation/brainTreeDropIn.js
Outdated
Show resolved
Hide resolved
packages/peregrine/lib/talons/CheckoutPage/PaymentInformation/useCreditCard.js
Show resolved
Hide resolved
…onent is unmounted.
let unmounted = false; | ||
|
||
const renderDropin = async () => { | ||
const instance = await createDropinInstance(); |
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 isn't quite right. We still get an error because it's possible for the component to attempt to attach to a container which is no longer mounted. To repro, submit a shipping method so that the payment info begins to load. Once you see the loading spinner click the venia logo in the header to navigate back to the home page. You'll see the error in console. You should add a try-catch around the createDropinInstance()
call here.
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 tried the same before committing my code and I was not able to reproduce. I tried now, and it is intermittent. Maybe I am clicking it before the initializing is done. Changing now.
packages/venia-ui/lib/components/CheckoutPage/PaymentInformation/brainTreeDropIn.js
Outdated
Show resolved
Hide resolved
packages/venia-ui/lib/components/CheckoutPage/PaymentInformation/brainTreeDropIn.js
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.
And that's a wrap!
Finally 🥳 congrats! |
Description
Guest Payment Workflow for the new Venia Checkout workflow.
As a guest, I should be able to add a credit card in the checkout page and use it for the checkout process.
Without a payment method selected, the review order button will be disabled. Once the user clicks the review order button, the braintree drop-in will make a request for the payment nonce and save it in the apollo cache.
If a payment nonce is present in the cache, it is an indication of the payment information step being complete. Hence the payment information summary should be shown instead.
The payment information summary component should have an edit option to edit the original payment method's data. Note: For security purposes, credit card details will not be stored. They should be entered again to complete the payment edit workflow.
This component saves some stuff in the cache and some on the remote GQL server. It stores payment details like type of card and last 4 digits in the cache but the nonce in the remote server due to incompatibilities between what GQL supports and what UX wants.
Sample Credit Cards for testing: https://developers.braintreepayments.com/guides/credit-cards/testing-go-live/ruby
Deployed version: http://pr-2320.pwa-venia.com
Related Issue
Closes PWA-183
Verification Stakeholders
@soumya-ashok
@schensley
@jimbo
Verification Steps
Screenshots / Screen Captures (if appropriate)
Checklist