Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Add Slot/Fill to discounts area in cart sidebar #4248

Merged
merged 41 commits into from Jun 4, 2021

Conversation

opr
Copy link
Contributor

@opr opr commented May 20, 2021

This PR adds a Slot/Fill to the Cart sidebar (The same functionality is required in Checkout, but this will come in another PR). Extensions can register components to be fill this Slot, it is rendered just underneath the TotalsCoupon component.

The PR also includes a (partial) revert of #4238 (specifically, the part where ValidatedTextInput was moved to the checkout package) but keeps the part where styles, and a spread were added to ValidatedTextInput to handle the cases when this component is used as type="number".

⚠️ Please ignore the changes in packages/checkout/utils/update-cart-from-api.ts - these are changed again in #4298 which is based off this branch.

Fixes #4205

How to test the changes in this Pull Request:

  1. Check out feature/add-inputs-for-points-redemption from https://github.com/woocommerce/woocommerce-points-and-rewards/ and ensure you've run npm run build in that project.
  2. Go to the file includes/class-wc-points-rewards-extend-store-endpoint.php in Points and Rewards and comment out the following lines (66-72):
self::$extend->register_update_callback(
  array(
    'endpoint'          => CartExtensionsSchema::IDENTIFIER,
    'namespace'         => self::IDENTIFIER,
    'callback_function' => array( 'WC_Points_Rewards_Cart_Checkout', 'rest_apply_discount' ),
  )
);
  1. Ensure you have added points to your user account ( WooCommerce -> Points and Rewards) and that you're logged in
  2. Add items to your cart and visit the Cart block. See that the Points and Rewards input is present. Note that it won't function on this branch. This PR is just to get the display working.

Changelog

Add Slot in the Discounts section of the cart sidebar to allow third party extensions to render their own components there.

@opr opr added category: extensibility Work involving adding or updating extensibility. Useful to combine with other scopes impacted. focus: components Work that introduces new or updates existing components. focus: blocks Specific work involving or impacting how blocks behave. block: cart Issues related to the cart block. block: checkout Issues related to the checkout block. labels May 20, 2021
@opr opr self-assigned this May 20, 2021
@github-actions
Copy link
Contributor

Type this properly when validation context is typed

Type this properly when validation context is typed


https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/8bff20176a15baceeed0547b1bd727e1c2446c35/packages/checkout/text-input/validated-text-input.tsx#L36-L47

🚀 This comment was generated by the automations bot based on a todo comment in 8bff201 in #4248. cc @opr

@github-actions
Copy link
Contributor

github-actions bot commented May 20, 2021

Size Change: +1.09 kB (0%)

Total Size: 987 kB

Filename Size Change
build/active-filters-frontend.js 7.98 kB +1 B (0%)
build/all-products.js 36.5 kB -2 B (0%)
build/all-reviews.js 9.15 kB +4 B (0%)
build/atomic-block-components/add-to-cart-frontend.js 8.74 kB -11 B (0%)
build/atomic-block-components/add-to-cart.js 7.8 kB -2 B (0%)
build/atomic-block-components/price.js 2.01 kB -1 B (0%)
build/attribute-filter-frontend.js 17.7 kB -2 B (0%)
build/attribute-filter.js 11.4 kB +1 B (0%)
build/blocks-checkout-editor.js 10.6 kB +180 B (+2%)
build/blocks-checkout.js 19.8 kB +198 B (+1%)
build/cart-frontend.js 77.9 kB +150 B (0%)
build/cart.js 44.3 kB +123 B (0%)
build/checkout-frontend.js 81.9 kB +134 B (0%)
build/checkout.js 46.6 kB +117 B (0%)
build/featured-category.js 7.23 kB +2 B (0%)
build/featured-product.js 9.4 kB +2 B (0%)
build/price-filter-frontend.js 14.2 kB +15 B (0%)
build/price-filter.js 9.3 kB +1 B (0%)
build/reviews-by-category.js 11.2 kB +6 B (0%)
build/reviews-by-product.js 12.7 kB +1 B (0%)
build/single-product-frontend.js 38.1 kB +3 B (0%)
build/style-rtl.css 18.9 kB +84 B (0%)
build/style.css 18.9 kB +87 B (0%)
build/vendors.js 242 kB +3 B (0%)
build/wc-blocks-data.js 10.6 kB -1 B (0%)
build/wc-blocks-registry.js 2.73 kB -6 B (0%)
build/wc-settings.js 2.93 kB -2 B (0%)
build/wc-shared-hocs.js 1.73 kB +1 B (0%)
ℹ️ View Unchanged
Filename Size Change
build/active-filters.js 7.53 kB 0 B
build/all-products-frontend.js 34.7 kB 0 B
build/atomic-block-components/add-to-cart--atomic-block-components/button--atomic-block-components/image---a7e2bb9b.js 2.39 kB 0 B
build/atomic-block-components/add-to-cart--atomic-block-components/button.js 1.95 kB 0 B
build/atomic-block-components/add-to-cart--atomic-block-components/image--atomic-block-components/title.js 334 B 0 B
build/atomic-block-components/button-frontend.js 1.73 kB 0 B
build/atomic-block-components/button.js 844 B 0 B
build/atomic-block-components/category-list-frontend.js 469 B 0 B
build/atomic-block-components/category-list.js 478 B 0 B
build/atomic-block-components/image-frontend.js 1.66 kB 0 B
build/atomic-block-components/image.js 1.3 kB 0 B
build/atomic-block-components/price-frontend.js 1.98 kB 0 B
build/atomic-block-components/rating-frontend.js 521 B 0 B
build/atomic-block-components/rating.js 525 B 0 B
build/atomic-block-components/sale-badge-frontend.js 470 B 0 B
build/atomic-block-components/sale-badge.js 474 B 0 B
build/atomic-block-components/sku-frontend.js 389 B 0 B
build/atomic-block-components/sku.js 393 B 0 B
build/atomic-block-components/stock-indicator-frontend.js 569 B 0 B
build/atomic-block-components/stock-indicator.js 572 B 0 B
build/atomic-block-components/summary-frontend.js 906 B 0 B
build/atomic-block-components/summary.js 910 B 0 B
build/atomic-block-components/tag-list-frontend.js 464 B 0 B
build/atomic-block-components/tag-list.js 472 B 0 B
build/atomic-block-components/title-frontend.js 1.41 kB 0 B
build/atomic-block-components/title.js 1.26 kB 0 B
build/blocks.js 3.51 kB 0 B
build/editor-rtl.css 14.9 kB 0 B
build/editor.css 14.9 kB 0 B
build/handpicked-products.js 5.89 kB 0 B
build/price-format.js 1.37 kB 0 B
build/product-best-sellers.js 6.12 kB 0 B
build/product-categories.js 3.24 kB 0 B
build/product-category.js 6.99 kB 0 B
build/product-new.js 6.28 kB 0 B
build/product-on-sale.js 6.62 kB 0 B
build/product-search.js 2.56 kB 0 B
build/product-tag.js 6.1 kB 0 B
build/product-top-rated.js 6.26 kB 0 B
build/products-by-attribute.js 7.22 kB 0 B
build/reviews-frontend.js 8.94 kB 0 B
build/single-product.js 9.65 kB 0 B
build/vendors--atomic-block-components/price-frontend.js 6.54 kB 0 B
build/vendors-style-rtl.css 1.05 kB 0 B
build/vendors-style.css 1.05 kB 0 B
build/wc-blocks-google-analytics.js 1.99 kB 0 B
build/wc-blocks-middleware.js 1.48 kB 0 B
build/wc-payment-method-bacs.js 812 B 0 B
build/wc-payment-method-cheque.js 807 B 0 B
build/wc-payment-method-cod.js 903 B 0 B
build/wc-payment-method-paypal.js 844 B 0 B
build/wc-payment-method-stripe.js 12.4 kB 0 B
build/wc-shared-context.js 1.54 kB 0 B

compressed-size-action

Comment on lines 117 to 123
const discountsSlotFillProps = {
extensions,
cart,
contexts: {
validation: useValidationContext(),
storeCart: useStoreCart(),
},
components: {
ValidationInputError,
},
};
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of doing this which is a side-effect of exporting ValidatedTextInput from the checkout package (which wouldn't have access to the same validation context instance). Could you avoid removing the encapsulation of the validation logic in ValidatedTextInput and have the component passed through on the slot-fill here? So you'd end up with something like:

Suggested change
const discountsSlotFillProps = {
extensions,
cart,
contexts: {
validation: useValidationContext(),
storeCart: useStoreCart(),
},
components: {
ValidationInputError,
},
};
const discountsSlotFillProps = {
extensions,
cart,
contexts: {
storeCart: useStoreCart(),
},
components: {
ValidatedTextInput
},
};

The concern I have with the current implementation is it exposes more of the implementation details to extensions and makes it harder for us to make changes in the future.

Copy link
Contributor

@nerrad nerrad May 21, 2021

Choose a reason for hiding this comment

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

I also have a high level of concern around exposing the entire cart implementation details here. I realize points and rewards redemption requires some ability to update the cart but this again exposes implementation details that makes it harder for us to modify how this works in the future - especially when in the current implementation there's some pretty high dependency on making sure the right shape for the cart data is fed to the receiveCart dispatcher.

This is an interface that would be fairly hard for extensions to understand and apply correctly without deep knowledge of internals.

I don't have any immediate alternatives to suggest but I'd be wary about shipping with the current implementation.

Copy link
Contributor Author

@opr opr May 21, 2021

Choose a reason for hiding this comment

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

Thanks Darren, could you clarify what you mean about the ValidatedTextInput change here? This component renders a ValidationInputError which is (at the moment) passed to ValidatedTextInput as a prop. Previously it was imported from the base-context package, but since moving the input to the checkout package, the context instance is different one, so errors don't show up. Are you suggesting to move ValidatedTextInput back out of the checkout package and instead pass it through the slot?

Also, right now I no longer need the useStoreCart context, following the addition of https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/4248/files#diff-e9030d5520892c9926d801219c89bbc21b4863a510ce18409f74b0a148f1270eR1-R24, BUT, the caveat is, after updating the cart, the extension needs to request fresh data to be loaded, which has a pretty poor UX especially on slower devices or connections: https://www.loom.com/share/8a9871aeb0b5494a84cfc54f84c00dfd

Copy link
Contributor

@nerrad nerrad May 21, 2021

Choose a reason for hiding this comment

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

Are you suggesting to move ValidatedTextInput back out of the checkout package and instead pass it through the slot?

Yes this. That would also remove the need to expose implementation details from the validation context right?

Copy link
Contributor

Choose a reason for hiding this comment

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

BUT, the caveat is, after updating the cart, the extension needs to request fresh data to be loaded, which has a pretty poor UX especially on slower devices or connections: https://www.loom.com/share/8a9871aeb0b5494a84cfc54f84c00dfd

Ya that's not the best UX. I wonder if instead of doing this, we could provide some API that signals the checkout should do some sort of "update_cart" post to the server on the StoreAPI that extensions could react to server side and make any necessary updates? So it'd work similarly to when quantity is updated etc except extensions are simply triggering the post and response? So the rough flow would be something like:

  1. Extension updates a value attached to it's state in the cart store.
  2. Extension uses some way of signaling it's state needs updated in on the server.
  3. This triggers a checkout "update" POST.
  4. Extension is hooked into the StoreAPI "update" POST for capturing the data it needs to process server side and preparing the response.
  5. StoreAPI returns the updated Cart response (and the extension could react to value changes in it's cart store state)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for your feedback @nerrad, as we have discussed in our 1:1 and in this PR, this is the approach I think we'll continue with.

I have reverted the changes in #4238 and instead opted to pass this through the slot, due to us not wanting to pass validation contexts through the slot.

This PR is now ready for a full review 🎉

@opr opr force-pushed the feature/coupon-area-slotfill branch from b6a4a74 to d0f49cc Compare May 31, 2021 08:38
@opr opr marked this pull request as ready for review June 2, 2021 11:26
@opr opr requested a review from a team as a code owner June 2, 2021 11:26
@opr opr requested review from Aljullu and removed request for a team June 2, 2021 11:26
Copy link
Contributor

@Aljullu Aljullu left a comment

Choose a reason for hiding this comment

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

Changes look good. I left a couple of CSS suggestions but I'm approving because none is blocking.

One thing I noticed is that when I run npm run build in Points and Rewards, I can't see the rewards panel, it only works when I run npm run start. Is that a known issue?

Another thing is that text doesn't seem to wrap correctly:
imatge

packages/checkout/panel/style.scss Outdated Show resolved Hide resolved
@Aljullu
Copy link
Contributor

Aljullu commented Jun 2, 2021

Oh, one more thing: are the up and down arrows expected in the number input? They collide with the placeholder. I would personally remove them, but leaving the decision to you:

imatge

Copy link
Member

@senadir senadir left a comment

Choose a reason for hiding this comment

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

I do have some concerns about the amount of things we're exposing here and if they make sense for us to do that. I did leave some questions.

assets/js/base/components/text-input/text-input.tsx Outdated Show resolved Hide resolved
Comment on lines 120 to 122
components: {
ValidatedTextInput,
},
Copy link
Member

Choose a reason for hiding this comment

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

I'm still not sold on this components pattern tbh. Why are we doing it this way? Do people need this exact input with its validation context and all? can't just they get a regular input and handle validation themselves?

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 guess I got too bogged down here, I think there's actually no reason to pass this component through... let me get rid of it and see how it goes 👌🏼 .

Copy link
Contributor

@nerrad nerrad Jun 3, 2021

Choose a reason for hiding this comment

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

Just noting that Thomas and I chatted about this today. A couple reasons why this was passed through was to:

  • Expose (what would likely be a common type of) component for extension developers to use to preserve consistent styling and behaviour.
  • Make it easier for extension developers to implement this kind of functionality.

However, the tradeoffs are that we are establishing a contract to preserve this component and kicks off a pattern that might be hard to maintain in the future if extension developers have need for other types of components in the checkout (checkbox etc). There's some element here of just including this component because Points & Rewards needs it.

So for now, we agreed that we'll hold off exposing this and Thomas will implement the functionality directly in Points & Rewards. I do think we'll still need to address the issue of exposing some components/style system for extension developers to use so they can inherit/preserve the current (and any evolution of the) design of the blocks which makes for a better shopper experience. The work Thomas will be doing in Points and Rewards implementation will unblock that integration but will be more inherently fragile in relation to potential changes in the Cart and Checkout design down the road (for example when we potentially start including Global Styles from Gutenberg to allow for more customization options by merchants etc). So I think we will need to address this in a followup.

Copy link
Member

Choose a reason for hiding this comment

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

Expose (what would likely be a common type of) component for extension developers to use to preserve consistent styling and behaviour.
Make it easier for extension developers to implement this kind of functionality.

Why wouldn't having the component in @woocommerce/blocks-checkout be enough? previously we passed shippingSelector from there to preserve an already passed context I guess, but that pattern is up for reconsideration during this cooldown in which we might delete the shipping methods slotFill for a registration API.

In my mind, components was used to pass components that are harder to move to the checkout package or are very opinionated to a specific case.

I'm not against exposing components in general via a components package, in that case, we have a real boundary of "all code in this folder is public" type of protection, making it easier for us to maintain it.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is exactly the sort of discussion that we need to work through separately now that we are starting to see integrations that could use more of these components (whether published via package, or passed through as an interface prop etc).

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 already tried moving the ValidatedTextInput component to the checkout package, but it didn't work with the validation context, because they were in different packages it seemed they couldn't work together. Then we tried passing the context through the slot, and that worked, but wasn't the right approach to take as we didn't want to expose this context to third parties.

For now I'm sticking with what Darren has already said - we will duplicate the component in P&R until we can revisit this and find a way to expose ValidatedTextInput to extensions.

packages/checkout/discounts-meta/index.js Outdated Show resolved Hide resolved
@opr opr force-pushed the feature/coupon-area-slotfill branch from a08709f to d7bbe0f Compare June 3, 2021 07:45
Copy link
Contributor

@Aljullu Aljullu left a comment

Choose a reason for hiding this comment

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

Thanks for the updating this PR @opr! Changes look good to me. I noticed there is an issue in Firefox (input field lets you write numbers and on unfocus the label collides with the input):

imatge

I would say we don't need to fix this since this is a Firefox bug and IMO an edge-case most users will not encounter. But wanted to raise it in here in case you think differently.

I will leave the final approval of this PR to @senadir given that he made other comments.

@opr
Copy link
Contributor Author

opr commented Jun 3, 2021

Thanks for the updating this PR @opr! Changes look good to me. I noticed there is an issue in Firefox (input field lets you write numbers and on unfocus the label collides with the input):

imatge

I would say we don't need to fix this since this is a Firefox bug and IMO an edge-case most users will not encounter. But wanted to raise it in here in case you think differently.

I will leave the final approval of this PR to @senadir given that he made other comments.

Yep, you can also write the letter e in the box and it will do the same in chromium, I don't think there's anything we can do to stop this besides revert to a type="text" input and parseInt on the value, but this gives degraded performance to mobile users as it won't display the numerical keyboard. I think this is an edge case we are OK with leaving as fixing it would result in a worse overall experience for more users.

Copy link
Member

@senadir senadir left a comment

Choose a reason for hiding this comment

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

All good to me.
I wonder if it just made sense to create a new number field instead of having the logic inside the text field. I'd leave this to a follow up for now.

Thank you for addressing the feedback Thomas!

@opr opr merged commit b6a9cc6 into trunk Jun 4, 2021
@opr opr deleted the feature/coupon-area-slotfill branch June 4, 2021 08:44
@ralucaStan ralucaStan added this to the 5.3.0 milestone Jun 7, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
block: cart Issues related to the cart block. block: checkout Issues related to the checkout block. category: extensibility Work involving adding or updating extensibility. Useful to combine with other scopes impacted. focus: blocks Specific work involving or impacting how blocks behave. focus: components Work that introduces new or updates existing components.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add SlotFill to the Discounts area of the new Cart and Checkout sidebar
5 participants