-
Notifications
You must be signed in to change notification settings - Fork 214
@W-18767088 refactor add to cart #2664
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
Changes from 5 commits
f0f10d6
f241f49
f545efe
dd72f4f
a637f3b
f73f650
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,154 @@ | ||
| /* | ||
| * Copyright (c) 2025, Salesforce, Inc. | ||
| * All rights reserved. | ||
| * SPDX-License-Identifier: BSD-3-Clause | ||
| * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
| */ | ||
|
|
||
| /** | ||
| * Handles adding products to cart and sending data to Einstein. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sf-kyle-wright The WI description mentioned one reason to move addToCart out is it can be used from multiple clients like PDP, wishlist etc.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ya so that's a great thought. There are some tradeoffs here but it looks like at this point it might not make sense to move them into a hook. I asked cursor, TLDR:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since this is only working on cart? How about we keep it in cart page? Unless we have plan for these funcs to be used by other components that is not cart
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a larger plan to re-use these functions across wishlist as well
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if that is the case, let's name the file to be a bit more generic.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @alexvuong What do you have in mind?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like that name @sf-emmyzhang
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks. renamed to add-to-cart-utils.js |
||
| * @param {Array} productSelectionValues | ||
| * @param {Function} addItemToNewOrExistingBasket | ||
| * @param {Object} einstein | ||
| * @param {Function} showError | ||
| * @returns {Promise<Array>|undefined} | ||
| */ | ||
| export const handleAddToCart = async ( | ||
| productSelectionValues, | ||
| addItemToNewOrExistingBasket, | ||
| einstein, | ||
| showError | ||
| ) => { | ||
| try { | ||
| const productItems = productSelectionValues.map(({variant, product, quantity}) => ({ | ||
| productId: variant?.productId || product?.id, | ||
| price: variant?.price || product?.price, | ||
| quantity | ||
| })) | ||
|
|
||
| await addItemToNewOrExistingBasket(productItems) | ||
|
|
||
| const productItemsForEinstein = productSelectionValues.map( | ||
| ({product, variant, quantity}) => ({ | ||
| product, | ||
| productId: variant?.productId || product?.id, | ||
| price: variant?.price || product?.price, | ||
| quantity | ||
| }) | ||
| ) | ||
| einstein.sendAddToCart(productItemsForEinstein) | ||
|
|
||
| // If the items were successfully added, set the return value to be used | ||
| // by the add to cart modal. | ||
| return productSelectionValues | ||
| } catch (error) { | ||
| console.log('error', error) | ||
| showError(error) | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Handles adding a product bundle to the cart, including updating child variant selections if needed. | ||
| * @param {Object} product - The parent product (bundle). | ||
| * @param {Object} childProductSelection - Object containing selected child products. | ||
| * @param {number} selectedQuantity - Quantity of the bundle to add. | ||
| * @param {Function} addItemToNewOrExistingBasket - Function to add items to the basket. | ||
| * @param {Object} updateItemsInBasketMutation - Mutation object for updating items in the basket. | ||
| * @param {Object} einstein - Einstein tracking object. | ||
| * @param {Function} showError - Function to show errors. | ||
| * @param {Function} getUpdateBundleChildArray - Utility to get update array for bundle children. | ||
| * @returns {Promise<Array>|undefined} | ||
| */ | ||
| export const handleProductBundleAddToCart = async ( | ||
| product, | ||
| childProductSelection, | ||
| selectedQuantity, | ||
| addItemToNewOrExistingBasket, | ||
| updateItemsInBasketMutation, | ||
| einstein, | ||
| showError, | ||
| getUpdateBundleChildArray | ||
| ) => { | ||
| try { | ||
| const childProductSelections = Object.values(childProductSelection) | ||
|
|
||
| const productItems = [ | ||
| { | ||
| productId: product.id, | ||
| price: product.price, | ||
| quantity: selectedQuantity, | ||
| // The add item endpoint in the shopper baskets API does not respect variant selections | ||
| // for bundle children, so we have to make a follow up call to update the basket | ||
| // with the chosen variant selections | ||
| bundledProductItems: childProductSelections.map((child) => { | ||
| return { | ||
| productId: child.variant?.productId || child.product?.id, | ||
| quantity: child.quantity | ||
| } | ||
| }) | ||
| } | ||
| ] | ||
|
|
||
| const res = await addItemToNewOrExistingBasket(productItems) | ||
|
|
||
| const bundleChildMasterIds = childProductSelections.map((child) => { | ||
| return child.product.id | ||
| }) | ||
|
|
||
| // since the returned data includes all products in basket | ||
| // here we compare list of productIds in bundleProductItems of each productItem to filter out the | ||
| // current bundle that was last added into cart | ||
| const currentBundle = res.productItems.find((productItem) => { | ||
| if (!productItem.bundledProductItems?.length) return | ||
| const bundleChildIds = productItem.bundledProductItems?.map((item) => { | ||
| // seek out the bundle child that still uses masterId as product id | ||
| return item.productId | ||
| }) | ||
| return bundleChildIds.every((id) => bundleChildMasterIds.includes(id)) | ||
| }) | ||
|
|
||
| const itemsToBeUpdated = getUpdateBundleChildArray(currentBundle, childProductSelections) | ||
|
|
||
| if (itemsToBeUpdated.length) { | ||
| // make a follow up call to update child variant selection for product bundle | ||
| // since add item endpoint doesn't currently consider product bundle child variants | ||
| await updateItemsInBasketMutation.mutateAsync({ | ||
| method: 'PATCH', | ||
| parameters: { | ||
| basketId: res.basketId | ||
| }, | ||
| body: itemsToBeUpdated | ||
| }) | ||
| } | ||
|
|
||
| einstein.sendAddToCart(productItems) | ||
|
|
||
| return childProductSelections | ||
| } catch (error) { | ||
| showError(error) | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Handles adding a product set to the cart. | ||
| * @param {Object} childProductSelection - Object containing selected child products. | ||
| * @param {Function} addItemToNewOrExistingBasket - Function to add items to the basket. | ||
| * @param {Object} einstein - Einstein tracking object. | ||
| * @param {Function} showError - Function to show errors. | ||
| * @returns {Promise<Array>|undefined} | ||
| */ | ||
| export const handleProductSetAddToCart = ( | ||
| childProductSelection, | ||
| addItemToNewOrExistingBasket, | ||
| einstein, | ||
| showError | ||
| ) => { | ||
| // Get all the selected products, and pass them to the addToCart handler which accepts an array. | ||
| const productSelectionValues = Object.values(childProductSelection) | ||
| return handleAddToCart( | ||
| productSelectionValues, | ||
| addItemToNewOrExistingBasket, | ||
| einstein, | ||
| showError | ||
| ) | ||
| } | ||
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.
Do we need to move this as well ? If Yes, this can go in some util file.
Others can go in some AddToCart hook/or something, as they are all Adding diff products to 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.
handleChildProductValidation - Moved it back to product-detail since it didn't make sense to extract this one to the util