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

[bug] Use gql persistence for checkout step between refreshes. #2354

Merged
merged 15 commits into from
Apr 30, 2020

Conversation

sirugh
Copy link
Contributor

@sirugh sirugh commented Apr 22, 2020

Description

The checkout step is used to inform guest checkout flow which step we're in and to prevent early submission before all the data necessary is present. We use gql to store and persist the checkoutStep across refreshes so that a user returning to checkout is presented at the point in time they left off before.

Related Issue

Closes PWA-523.

Acceptance

Verification Stakeholders

Specification

Verification Steps

  1. Go to the cart page.
  2. Check boxes in gift options and add a message.
  3. Refresh the page and check that section. Your selections/message should persist.
  4. Go to checkout and refresh the page after you submit each step. The page should render the step you were just on instead of cascading from each previous step.
  5. Delete apollo-cache-persist entry ONLY from local storage and refresh. The page should render what looks like a cascade while the effects trigger each onSave after fetching data. As there is no way to store nonce info for the payment info summary view, this step will appear as if you never submitted it now.
  6. Log in/out. All $Cart should be deleted and the Cart entry should be recreated with a new id.

Screenshots / Screen Captures (if appropriate)

Checklist

  • I have updated the documentation accordingly, if necessary.
  • I have added tests to cover my changes, if necessary.

@m2-community-project m2-community-project bot added this to Ready for Review in Pull Request Progress Apr 22, 2020
Signed-off-by: sirugh <rugh@adobe.com>
@@ -93,7 +93,7 @@ const SET_GIFT_OPTIONS_QUERY = gql`
include_gift_receipt: $include_gift_receipt
include_printed_card: $include_printed_card
gift_message: $gift_message
) @client
) @client @connection(key: "set_gift_options")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These were missed during the PII pass in #2322

@m2-community-project m2-community-project bot moved this from Ready for Review to Review in Progress in Pull Request Progress Apr 22, 2020
if (!initialized) {
// TODO: Replace with app skeleton. See PWA-547.
return null;
}
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 broke this in #2322. We have to wait persistence otherwise we end up not restoring the cache from local storage which is counter to why we even include persistence layer.

// TODO: Replace with heuristic check against cart data. Requires
// fetching more than just total quantity for checkout details query
// "cart" arg will have server result.
return cart.checkoutStep || 1;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This seems fine to me right now but if we wanted to get rid of the onSave callbacks that we require each component make we could have some heuristic that checks all cart data and sets the current step according to whatever data is missing. Good idea from @tjwiebell :)

@PWAStudioBot
Copy link
Contributor

PWAStudioBot commented Apr 22, 2020

Messages
📖

Access a deployed version of this PR here. Make sure to wait for the "pwa-pull-request-deploy" job to complete.

📖 DangerCI Failures related to missing labels/description/linked issues/etc will persist until the next push or next nightly build run (assuming they are fixed).
📖

Associated JIRA tickets: PWA-523.

Generated by 🚫 dangerJS against 1b61023

@sirugh sirugh changed the title Rugh/pwa 523 checkout step fix on refresh [bug] Use gql persistence for checkout step between refreshes. Apr 23, 2020
Signed-off-by: sirugh <rugh@adobe.com>
Signed-off-by: sirugh <rugh@adobe.com>

const [getCheckoutStep, { data: stepData, client }] = useLazyQuery(
getCheckoutStepQuery
Copy link
Contributor Author

@sirugh sirugh Apr 23, 2020

Choose a reason for hiding this comment

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

I replaced this query with a client side resolver for the checkoutStep property of Cart types. The resolver handles the default state as well, setting the step to 1 if undefined.

In the future we could also remove the need for onSave callbacks by moving the determination of step into the resolver and passing all checkout data necessary to figure out the step.

For example instead of shippingdata.city indicating completion of shipping info step in an effect inside that component we would just check it in the resolver.

@@ -159,7 +156,7 @@ export const useCheckoutPage = props => {
hasError: !!placeOrderError,
isCartEmpty: !(checkoutData && checkoutData.cart.total_quantity),
isGuestCheckout: !isSignedIn,
isLoading: checkoutLoading,
isLoading: !checkoutCalled || (checkoutCalled && checkoutLoading),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

There's a moment in render where we aren't loading but also haven't yet called the query. We want to wait to render anything until we've loaded the step at a minimum.

@sirugh sirugh added the version: Major This changeset includes incompatible API changes and its release necessitates a Major version bump. label Apr 23, 2020
Signed-off-by: sirugh <rugh@adobe.com>
@sirugh sirugh marked this pull request as ready for review April 23, 2020 16:52
Signed-off-by: sirugh <rugh@adobe.com>
Signed-off-by: sirugh <rugh@adobe.com>
Copy link
Contributor

@tjwiebell tjwiebell left a comment

Choose a reason for hiding this comment

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

Looks good, I think you can use a single regex to pattern match though.

Comment on lines 69 to 70
await deleteCacheEntry(apolloClient, key => key.match(/^Cart/));
await deleteCacheEntry(apolloClient, key => key.match(/^\$Cart/));
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe add a comment about the dual rule (Apollo caches weird when it can't compute a key).

Suggested change
await deleteCacheEntry(apolloClient, key => key.match(/^Cart/));
await deleteCacheEntry(apolloClient, key => key.match(/^\$Cart/));
await deleteCacheEntry(apolloClient, key => key.match(/^\$?Cart/));

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is an interesting point - we're explicit about which keys to delete, but by combining them in a single regex/function call that point is kind of obscured. Do you think its worth it to combine? I can add a comment above each call just to explain, at least.

Copy link
Contributor

Choose a reason for hiding this comment

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

Using regex obscures what you're doing for most anyway, I don't see any problem with being more efficient. If you were using a string method I would agree, eg. key.startsWith.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Comment on lines 101 to 104
await deleteCacheEntry(apolloClient, key => key.match(/^Cart/));
await deleteCacheEntry(apolloClient, key =>
key.match(/^\$Cart/)
);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
await deleteCacheEntry(apolloClient, key => key.match(/^Cart/));
await deleteCacheEntry(apolloClient, key =>
key.match(/^\$Cart/)
);
await deleteCacheEntry(apolloClient, key =>
key.match(/^\$?Cart/)
);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@@ -118,6 +124,7 @@ export const useCheckoutPage = props => {

// Delete stale cart data from apollo
await deleteCacheEntry(apolloClient, key => key.match(/^Cart/));
await deleteCacheEntry(apolloClient, key => key.match(/^\$Cart/));
Copy link
Contributor

Choose a reason for hiding this comment

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

Merge the rules together, suggestions above.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Comment on lines 183 to 184
!!chosenShippingMethodData.cart.shipping_addresses[0]
.selected_shipping_method;
Copy link
Contributor

Choose a reason for hiding this comment

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

Our components together guard against this use case, but someone just using this talon might still enter this block w/o setting an address. Let's guard against it (don't apply this from GitHub, I'm sure formatting is off).

Suggested change
!!chosenShippingMethodData.cart.shipping_addresses[0]
.selected_shipping_method;
!!chosenShippingMethodData.cart.shipping_addresses.length && chosenShippingMethodData.cart.shipping_addresses[0].selected_shipping_method;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good call. I'll make the change.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixing in 6130923

@@ -97,6 +97,9 @@ export const useCreateAccount = props => {

// Delete stale cart data from apollo
await deleteCacheEntry(apolloClient, key => key.match(/^Cart/));
await deleteCacheEntry(apolloClient, key =>
key.match(/^\$Cart/)
Copy link
Contributor

Choose a reason for hiding this comment

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

Merge rules

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@@ -63,6 +63,9 @@ export const useSignIn = props => {

// Delete stale cart data from apollo
await deleteCacheEntry(apolloClient, key => key.match(/^Cart/));
await deleteCacheEntry(apolloClient, key =>
key.match(/^\$Cart/)
Copy link
Contributor

Choose a reason for hiding this comment

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

Merge rules

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dpatil-magento
Copy link
Contributor

@sirugh If I click Review Order button and then do browser refresh >> Both Review Order and Place Order buttons are displayed.

image

@sirugh
Copy link
Contributor Author

sirugh commented Apr 27, 2020

If I click Review Order button and then do browser refresh >> Both Review Order and Place Order buttons are displayed.

Correct - the logic for when to display that button is currently held within the Payment Information component. When either #2320 is merged or this PR we will have to double check this case. Just keep that in mind after you merge one or the other.

Signed-off-by: sirugh <rugh@adobe.com>
Signed-off-by: sirugh <rugh@adobe.com>
@sirugh sirugh force-pushed the rugh/pwa-523-checkout-step-fix-on-refresh branch from 111f0bd to acf7910 Compare April 27, 2020 17:07
tjwiebell
tjwiebell previously approved these changes Apr 27, 2020
jimbo
jimbo previously approved these changes Apr 28, 2020
Copy link
Contributor

@jimbo jimbo left a comment

Choose a reason for hiding this comment

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

Minor style changes requested, but overall I agree with this approach. 👍

called: checkoutCalled,
client,
loading: checkoutLoading
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Try to avoid nested destructuring.

[setCheckoutStep]
() =>
checkoutStep === CHECKOUT_STEP.SHIPPING_ADDRESS &&
setCheckoutStep(CHECKOUT_STEP.SHIPPING_METHOD),
Copy link
Contributor

Choose a reason for hiding this comment

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

If you have a function that doesn't return anything, such as this one, just open a function body and use an if statement.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

await deleteCacheEntry(apolloClient, key => key.match(/^Cart/));
await deleteCacheEntry(apolloClient, key =>
key.match(/^\$?Cart/)
);
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider extracting this function into a utility, since we're doing this three times in this PR alone. Perhaps deleteStaleCartData?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@sirugh sirugh dismissed stale reviews from jimbo and tjwiebell via 9deb452 April 28, 2020 19:20
@dpatil-magento
Copy link
Contributor

QA Pass, good to merge after recent commits are reviewed.

@m2-community-project m2-community-project bot moved this from Reviewer Approved to Review in Progress in Pull Request Progress Apr 29, 2020
Copy link
Contributor

@tjwiebell tjwiebell left a comment

Choose a reason for hiding this comment

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

Most recent changes look good 👍

@dpatil-magento dpatil-magento merged commit 947b3c1 into develop Apr 30, 2020
@dpatil-magento dpatil-magento deleted the rugh/pwa-523-checkout-step-fix-on-refresh branch April 30, 2020 15:47
@m2-community-project m2-community-project bot moved this from Review in Progress to Done in Pull Request Progress Apr 30, 2020
@sirugh sirugh added version: Minor This changeset includes functionality added in a backwards compatible manner. and removed version: Major This changeset includes incompatible API changes and its release necessitates a Major version bump. labels Jun 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pkg:peregrine pkg:venia-ui version: Minor This changeset includes functionality added in a backwards compatible manner.
Development

Successfully merging this pull request may close these issues.

None yet

5 participants