-
Notifications
You must be signed in to change notification settings - Fork 685
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
Add to Wishlist from Cart #3130
Conversation
|
UX and PM review passed. |
timeout: 5000 | ||
}); | ||
|
||
await removeItemFromCart({ |
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 have discussed this in the Dev time and decided that we will not be rolling back wishlist addition if remove from the cart fails.
@@ -42,6 +42,7 @@ export const ProductListingFragment = gql` | |||
... on ConfigurableCartItem { | |||
configurable_options { | |||
id | |||
configurable_product_option_value_uid |
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.
configurable_product_option_value_uid |
I guess this is a change I forgot to revert after reverting the rollback code.
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.
It looks like you are still using configurable_product_option_value_uid
throughout the code. Not sure what you meant by your comment but...do something? :)
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, my bad. Wrong call.
4786865
to
cf19090
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.
Nice work :) I was a little confused why we have a .ee
file in here when you're just implementing the single wishlist, but I suppose this is going to help be a jumping off point for the next ticket (add to multiple).
const [displayError, setDisplayError] = useState(false); | ||
const [showLoginToast, setShowLoginToast] = useState(0); |
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.
Would prefer a boolean here, but I understand why you use an integer (so the memo fires, and returns a new object, triggering the toast again). I wonder if we have any other instances of a repeated toast in the app, or if this is a new pattern.
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 picked this logic from Tommy's #3105
packages/peregrine/lib/talons/CartPage/ProductListing/useWishlist.ce.js
Outdated
Show resolved
Hide resolved
@@ -91,10 +101,16 @@ const Product = props => { | |||
}) | |||
: ''; | |||
|
|||
useEffect(() => { | |||
if (loginToastProps) { | |||
addToast({ ...loginToastProps, icon: InfoIcon }); |
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 the new style so that the props are customizable via talon export?
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.
Yeah I kind of like this idea of sending toast props from the talon and let the component only worry about when to show the toast itself.
packages/peregrine/lib/talons/CartPage/ProductListing/useWishlist.ee.js
Outdated
Show resolved
Hide resolved
packages/peregrine/lib/talons/CartPage/ProductListing/useProduct.js
Outdated
Show resolved
Hide resolved
packages/venia-ui/lib/components/CartPage/ProductListing/product.js
Outdated
Show resolved
Hide resolved
@@ -376,10 +378,10 @@ | |||
"validation.isRequired": "Is required.", | |||
"validation.mustBeChecked": "Must be checked.", | |||
"validation.validatePassword": "A password must contain at least 3 of the following: lowercase, uppercase, digits, special characters.", | |||
"wishlist.emptyListText": "There are currently no items in this list", | |||
"wishlistButton.addedText": "Added to Favorites", |
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 is nitpicky, sorry, but addedText
should come after addText
as add
comes before added
.
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.
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.
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.
Honestly we should just set up a lint rule to auto sort this file for us :D
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.
Prefer standard string-value sorting, please, as it's the least arbitrary.
addError
addText
addedText
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.
Yeah, the plugin I used is not considering the length of the keys, it is only considering based on the character in the position. Since addEr
comes after added
it sorted it that way.
fragment WishlistFragment on Wishlist { | ||
id | ||
name | ||
items: items_v2 { |
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.
Generally I would avoid renaming or aliasing responses from gql as it is just another layer of abstraction that could make it more difficult to debug. If something went wrong with items
in the response we would have to know that it was aliased from items_v2
. Obviously this is a pretty minor thing, and I won't ask you to change it, but I think it's just good to be aware.
In this case I might actually leave it as items_v2
is...rough.
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.
Yeah dude you are right. I am not a fan of renaming usually but I felt items_v2
is not readable in the code.
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.
After discussion in the other PR I think we should move the alias to the destructure so we don't run into a conflict with the existing items
schema value.
packages/peregrine/lib/talons/CartPage/ProductListing/useWishlist.ce.js
Outdated
Show resolved
Hide resolved
import configuredVariant from '@magento/peregrine/lib/util/configuredVariant'; | ||
|
||
import { useWishlist } from './useWishlist'; |
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 feel like having this hook live as a sibling to the talon within the talons
directory could be confusing. I know we spoke about this regarding @tjwiebell's use case. Did we end up with a decision on where to place these utility hooks?
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.
Not quite completely though. I am trying to see if I can generalize wishlist logic into a talon of its own so all the components/talons that use it can just import. But unfortunately, that can be tricky because the use cases can be different and Jimmy suggested moving over it if it's getting complex to generalize.
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.
Yea I agree. At a minimum, throw the file into a helpers
directory.
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.
If I am able to generalize this, yes I will move it into a helper's folder but if it is bound to stay like this, it's not a helper anymore so we can leave it as it is. I'll update soon about the generalization work and let's make the call then.
Hey @supernova-at, thanks for doing the QA on this. I have handled the simple product's scenario. Unfortunately, I could not understand what the error scenario was. Can you expand on that? |
@sirugh Looks like this PR branch is not updated with latest develop that why those are failing. |
@revanth0212 Sure, it's this one (in the JIRA ticket):
|
@revanth0212 I updated the QA comment after merging in |
@supernova-at Those are valid failures as display position in selectors has been changed. You can try running using this branch https://github.com/magento-commerce/pwa-tests/pull/15 BTW to avoid this kind of things we will have data-ids for cypress :) |
MFTF tests are failing but not because of this PR. Running using a PR in that repo, they all pass. |
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.
Not sure how to evaluate the recent push - could you help me understand how to repro the error state?
const handleWishlistUpdateError = useCallback(() => { | ||
setIsCartUpdating(true); | ||
|
||
fetchCartDetails({ variables: { cartId } }); |
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.
Threading this prop all the way down from the cart page feels odd. Could you tell me why this is necessary in the first place and how to repro or get this function to be called? If we do have to go this route, perhaps we can go with a callback like onError
that is passed down.
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 react state update error I showed earlier today was present even before this change. That said, you can reproduce an error that can call this function by opening the cart in 2 tabs, move an item in 1 cart to the wishlist and do the same on the other tab. Removing items from the cart will fail because the item is not in the cart anymore.
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.
Ok thanks for providing repro.
I do think the handling here is a bit off still - the item greys out, then the success toast pops up, then you see an error on the item for a brief moment and then the item is deleted from the cart page UI.
Edit:
If this is the desired approach (refetching the cart data on error) then I think a callback such as onError
defined by the cart page and passed to any children who care, is preferable to a fetchCartDetails
prop.
I also think we can remove the setDisplayError(true)
call for the product causing the error since it's going to be deleted anyways.
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.
Yeah, it is doggy for sure, but that's the best at the moment till GQL comes up with a unified query. And this is a very very edge case. UX approves this as a valid solution given the circumstances.
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 also think we can remove the
setDisplayError(true)
call for the product causing the error since it's going to be deleted anyways.
Wouldn't that hide legitimate errors as well?
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.
Wouldn't that hide legitimate errors as well?
Would it? Normally you would call setDisplayError(true)
in the catch block related to the mutation that fails. Is this what we use this function for?
Perhaps it would hide legitimate errors but I still think the UX is weird. Look at the gif!
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 understand my confusion about this. In these files we have called setDisplayError
in the catch
block of the related item call, such as here. In fact, I believe that is the code that is causing the error (failure to remove) to display, not what you added here on line 118.
So please disregard my suggestion to remove the call to setDisplayError
. We do need it, in the event that the wishlist mutation throws an error.
I still would like to see my other concern addressed :)
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.
@revanth0212 had reasoning for not making my suggested change, I wanted to post it here so it was captured:
I would prefer it called fetchCartDetails because form the cart page POV we are not using that function for all errors. We are only using that when the wishlist move errors out.
This makes sense to me.
Maybe the state error, at least the one from product listing, is coming from here: https://github.com/magento/pwa-studio/blob/revanth/add-cart-to-wishlist/packages/peregrine/lib/talons/CartPage/ProductListing/useQuantity.js#L94 The backend I'm using got so slow I can't debug this right now, but I was wondering if the problem existed before your PR, such as when you remove the last item from your cart in the cart page (just by deleting, or setting quantity to 0). If it doesn't manifest on develop then there must be some effect being triggered after your "add to wishlist" mutation that is not completing by the time the "remove from cart" mutation completes. |
It is definitely weird but since we're getting a mutation that moves to wishlist from cart all at once, this is an interim weirdness that we made sure to get UX and QA's approval on. |
@supernova-at thanks, I didn't have that context! I also realized that Revanth's use of When are we getting a single mutation? |
@revanth0212 - you mentioned during Office Hour that you were using a single operation for this, and just wanted to clarify what I meant in case it can help with future use cases. No need to re-factor if you've worked through the issues of these mutations being done is separate transactions, but there is one example of this with Configurable Product edits (which happen to be an add + removal). |
This is a wonderful idea @tjwiebell but unfortunately, it did not also solve the problem and also this will be a huge change because the cart fragment resides in |
@sirugh can you do a code review on the recent changes and @supernova-at can you please do a QA re-run on this? |
Likely not until 2.4.3 in August. I created PWA-1736 to track. |
@revanth0212 did you see my previous comment? It may have gotten lost in the discussion about the other issue.
|
QA⏳ In Progress ⏳
|
* Updated handler function to add item to wishlist and remove from cart. * Minor. * Roll back functionality added. * Created CE and EE versions. * Minor. * Added login check. * Added toasts. * Sorting lang files. * Removed the rolling back logic. * Minor. * Added loading state. * Added french dictionary items. * chore: log error from mutation (#3140) * Addressed PR comments. * Minor test updates. * Common useWishlist helper hook. (#3141) * Using useWishlist as a helper. * CE wishlist refactor. * EE wishlist refactor. * onWishlistUpdateError -> setDisplayError * Minor. * Minor. * Added initial test. * Added useWishlist.ce tests. * Added useWishlist.ee tests. * Wishlist hook files refactor. * Revert "Wishlist hook files refactor." This reverts commit 34a771c. * Revert "Common useWishlist helper hook. (#3141)" This reverts commit 063144e. * Updated failing tests. * Added more tests. * Removed unecesaary gql. * Added cart page tests. * More tests. * Removed isFavorite * Fix for simple products. * Minor. * Refreshing cart on error. * Minor prop rename. Co-authored-by: Stephen <sirugh@users.noreply.github.com> Co-authored-by: Andy Terranova <13182778+supernova-at@users.noreply.github.com>
Description
This PR adds a new feature that lets the user move an item from the cart to the wishlist. This PR only targets single wishlist use cases, for instance, CE backends or EE backends with multiple wishlists turned off.
Related Issue
Closes PWA-1495
Verification Stakeholders
@schensley
@tkacheva
@dpatil-magento
Verification Steps
Save for later
button.Screenshots / Screen Captures (if appropriate)
Checklist