-
Notifications
You must be signed in to change notification settings - Fork 213
@W-18407137 Trigger a modal if new bonus products exist in AddToCart response #2541
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 14 commits
968f1bb
4259a1b
58ad8fe
8c44ea7
802b9d3
790a72b
c2021fa
0aadd8b
83b1dbb
0a697ef
4a0950c
afb7dc9
bd8f645
392c52f
9414838
f8fd65e
e441ee9
4848f14
9f6cfe5
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 |
|---|---|---|
|
|
@@ -23,6 +23,7 @@ import { | |
| } from '@salesforce/retail-react-app/app/components/shared/ui' | ||
| import {useCurrency, useDerivedProduct} from '@salesforce/retail-react-app/app/hooks' | ||
| import {useAddToCartModalContext} from '@salesforce/retail-react-app/app/hooks/use-add-to-cart-modal' | ||
| import {useBonusProductModalContext} from '@salesforce/retail-react-app/app/hooks/use-bonus-product-modal' | ||
|
|
||
| // project components | ||
| import ImageGallery from '@salesforce/retail-react-app/app/components/image-gallery' | ||
|
|
@@ -131,6 +132,13 @@ const ProductView = forwardRef( | |
| onOpen: onAddToCartModalOpen, | ||
| onClose: onAddToCartModalClose | ||
| } = useAddToCartModalContext() | ||
| const { | ||
| isOpen: isBonusProductModalOpen, | ||
| onOpen: onBonusProductModalOpen, | ||
| onClose: onBonusProductModalClose, | ||
| bonusProducts, | ||
| addBonusProducts | ||
| } = useBonusProductModalContext() | ||
| const theme = useTheme() | ||
| const [showOptionsMessage, toggleShowOptionsMessage] = useState(false) | ||
| const { | ||
|
|
@@ -272,16 +280,46 @@ const ProductView = forwardRef( | |
| return | ||
| } | ||
| try { | ||
| const itemsAdded = await addToCart(variant, quantity) | ||
| // Open modal only when `addToCart` returns some data | ||
| // It's possible that the item has been added to cart, but we don't want to open the modal. | ||
| // See wishlist_primary_action for example. | ||
| if (itemsAdded) { | ||
| onAddToCartModalOpen({ | ||
| product, | ||
| itemsAdded, | ||
| selectedQuantity: quantity | ||
| }) | ||
| const addToCartResponse = await addToCart(variant, quantity) | ||
|
|
||
| // For regular products: addToCartResponse has productSelectionValues and possibly bonusDiscountLineItems | ||
| // For product bundles: addToCartResponse is just the childProductSelections array | ||
| const itemsAdded = | ||
| addToCartResponse?.productSelectionValues || addToCartResponse | ||
| const isValidResponse = | ||
| itemsAdded && (Array.isArray(itemsAdded) || itemsAdded.length > 0) | ||
|
|
||
| // Compare existing bonus products with new bonus discount line items | ||
| // Only regular products (not bundles) can have bonusDiscountLineItems | ||
| const newBonusItems = | ||
| addToCartResponse?.bonusDiscountLineItems?.filter( | ||
| (newItem) => | ||
|
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. change name to bonusItem?
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. You can move this to within the "isValidResponse" check, right? |
||
| !bonusProducts.some( | ||
| (existingItem) => existingItem.id === newItem.id | ||
| ) | ||
| ) || [] | ||
|
|
||
| if (isValidResponse) { | ||
| // Show bonus product modal first if there are bonus items | ||
| if (newBonusItems?.length > 0) { | ||
| // Update bonusProducts list with the new bonus items | ||
| addBonusProducts(newBonusItems) | ||
| onBonusProductModalOpen({ | ||
| newBonusItems, | ||
| allBonusItems: addToCartResponse.bonusDiscountLineItems, | ||
| openAddToCartModalIfNeeded: true, | ||
| product, | ||
| itemsAdded, | ||
| selectedQuantity: quantity | ||
| }) | ||
| } else { | ||
| // If no bonus items, just show add to cart modal | ||
| onAddToCartModalOpen({ | ||
| product, | ||
| itemsAdded, | ||
| selectedQuantity: quantity | ||
| }) | ||
| } | ||
| } | ||
| } catch (e) { | ||
| showError() | ||
|
|
@@ -366,6 +404,12 @@ const ProductView = forwardRef( | |
| } | ||
| }, [location.pathname]) | ||
|
|
||
| useEffect(() => { | ||
| if (isBonusProductModalOpen) { | ||
| onBonusProductModalClose() | ||
| } | ||
sf-madhuri-uppu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }, [location.pathname]) | ||
|
|
||
| useEffect(() => { | ||
| if ( | ||
| !isProductASet && | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -46,9 +46,13 @@ afterEach(() => { | |
| sessionStorage.clear() | ||
| }) | ||
|
|
||
| const mockBasket = {bonusDiscountLineItems: []} | ||
sf-madhuri-uppu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| test('ProductView Component renders properly', async () => { | ||
| const addToCart = jest.fn() | ||
| renderWithProviders(<MockComponent product={mockProductDetail} addToCart={addToCart} />) | ||
| renderWithProviders(<MockComponent product={mockProductDetail} addToCart={addToCart} />, { | ||
| wrapperProps: {basket: mockBasket} | ||
| }) | ||
| expect(screen.getAllByText(/Black Single Pleat Athletic Fit Wool Suit/i)).toHaveLength(2) | ||
| expect(screen.getAllByText(/299\.99/)).toHaveLength(4) | ||
| expect(screen.getAllByText(/Add to cart/i)).toHaveLength(2) | ||
|
|
@@ -58,7 +62,9 @@ test('ProductView Component renders properly', async () => { | |
|
|
||
| test('ProductView Component renders with addToCart event handler', async () => { | ||
| const addToCart = jest.fn() | ||
| await renderWithProviders(<MockComponent product={mockProductDetail} addToCart={addToCart} />) | ||
| await renderWithProviders(<MockComponent product={mockProductDetail} addToCart={addToCart} />, { | ||
| wrapperProps: {basket: mockBasket} | ||
| }) | ||
|
|
||
| const addToCartButton = screen.getAllByText(/add to cart/i)[0] | ||
| fireEvent.click(addToCartButton) | ||
|
|
@@ -72,7 +78,10 @@ test('ProductView Component renders with addToWishList event handler', async () | |
| const addToWishlist = jest.fn() | ||
|
|
||
| await renderWithProviders( | ||
| <MockComponent product={mockProductDetail} addToWishlist={addToWishlist} /> | ||
| <MockComponent product={mockProductDetail} addToWishlist={addToWishlist} />, | ||
| { | ||
| wrapperProps: {basket: mockBasket} | ||
| } | ||
| ) | ||
|
|
||
| await waitFor(() => { | ||
|
|
@@ -91,7 +100,10 @@ test('ProductView Component renders with updateWishlist event handler', async () | |
| const updateWishlist = jest.fn() | ||
|
|
||
| await renderWithProviders( | ||
| <MockComponent product={mockProductDetail} updateWishlist={updateWishlist} /> | ||
| <MockComponent product={mockProductDetail} updateWishlist={updateWishlist} />, | ||
| { | ||
| wrapperProps: {basket: mockBasket} | ||
| } | ||
| ) | ||
|
|
||
| await waitFor(() => { | ||
|
|
@@ -109,7 +121,9 @@ test('ProductView Component renders with updateWishlist event handler', async () | |
| test('Product View can update quantity', async () => { | ||
| const user = userEvent.setup() | ||
| const addToCart = jest.fn() | ||
| await renderWithProviders(<MockComponent product={mockProductDetail} addToCart={addToCart} />) | ||
| await renderWithProviders(<MockComponent product={mockProductDetail} addToCart={addToCart} />, { | ||
| wrapperProps: {basket: mockBasket} | ||
| }) | ||
|
|
||
| let quantityBox | ||
| await waitFor(() => { | ||
|
|
@@ -132,7 +146,9 @@ test('Product View handles invalid quantity inputs', async () => { | |
| const user = userEvent.setup() | ||
|
|
||
| // Any invalid input should be reset to minOrderQuantity | ||
| await renderWithProviders(<MockComponent product={mockProductDetail} />) | ||
| await renderWithProviders(<MockComponent product={mockProductDetail} />, { | ||
| wrapperProps: {basket: mockBasket} | ||
| }) | ||
|
|
||
| const quantityInput = screen.getByRole('spinbutton', {name: /quantity/i}) | ||
| const minQuantity = mockProductDetail.minOrderQuantity.toString() | ||
|
|
@@ -156,7 +172,9 @@ test('Product View handles invalid quantity inputs', async () => { | |
| describe('ProductView Component', () => { | ||
| test('increases quantity when increment button is clicked', async () => { | ||
| const user = userEvent.setup() | ||
| renderWithProviders(<ProductView product={mockProductDetail} />) | ||
| renderWithProviders(<ProductView product={mockProductDetail} />, { | ||
| wrapperProps: {basket: mockBasket} | ||
| }) | ||
|
|
||
| const quantityInput = await screen.findByRole('spinbutton') | ||
| const incrementButton = screen.getByTestId('quantity-increment') | ||
|
|
@@ -179,7 +197,10 @@ describe('ProductView Component', () => { | |
| test('renders a product set properly - parent item', () => { | ||
| const parent = mockProductSet | ||
| renderWithProviders( | ||
| <MockComponent product={parent} addToCart={() => {}} addToWishlist={() => {}} /> | ||
| <MockComponent product={parent} addToCart={() => {}} addToWishlist={() => {}} />, | ||
| { | ||
| wrapperProps: {basket: mockBasket} | ||
| } | ||
| ) | ||
|
|
||
| // NOTE: there can be duplicates of the same element, due to mobile and desktop views | ||
|
|
@@ -204,7 +225,10 @@ test('renders a product set properly - parent item', () => { | |
| test('renders a product set properly - child item', () => { | ||
| const child = mockProductSet.setProducts[0] | ||
| renderWithProviders( | ||
| <MockComponent product={child} addToCart={() => {}} addToWishlist={() => {}} /> | ||
| <MockComponent product={child} addToCart={() => {}} addToWishlist={() => {}} />, | ||
| { | ||
| wrapperProps: {basket: mockBasket} | ||
| } | ||
|
||
| ) | ||
|
|
||
| // NOTE: there can be duplicates of the same element, due to mobile and desktop views | ||
|
|
@@ -239,7 +263,10 @@ test('validateOrderability callback is called when adding a set to cart', async | |
| validateOrderability={validateOrderability} | ||
| addToCart={() => {}} | ||
| addToWishlist={() => {}} | ||
| /> | ||
| />, | ||
| { | ||
| wrapperProps: {basket: mockBasket} | ||
| } | ||
| ) | ||
|
|
||
| const button = screen.getByRole('button', {name: /add set to cart/i}) | ||
|
|
@@ -262,7 +289,10 @@ test('onVariantSelected callback is called after successfully selected a variant | |
| onVariantSelected={onVariantSelected} | ||
| addToCart={() => {}} | ||
| addToWishlist={() => {}} | ||
| /> | ||
| />, | ||
| { | ||
| wrapperProps: {basket: mockBasket} | ||
| } | ||
| ) | ||
|
|
||
| const size = screen.getByRole('radio', {name: /xl/i}) | ||
|
|
@@ -280,7 +310,10 @@ describe('add to cart button loading tests', () => { | |
| product={mockProductDetail} | ||
| addToCart={() => {}} | ||
| isBasketLoading={true} | ||
| /> | ||
| />, | ||
| { | ||
| wrapperProps: {basket: mockBasket} | ||
| } | ||
| ) | ||
| expect(screen.getByRole('button', {name: /add to cart/i})).toBeDisabled() | ||
| }) | ||
|
|
@@ -291,7 +324,10 @@ describe('add to cart button loading tests', () => { | |
| product={mockProductDetail} | ||
| addToCart={() => {}} | ||
| isBasketLoading={false} | ||
| /> | ||
| />, | ||
| { | ||
| wrapperProps: {basket: mockBasket} | ||
| } | ||
| ) | ||
| expect(screen.getByRole('button', {name: /add to cart/i})).toBeEnabled() | ||
| }) | ||
|
|
@@ -300,7 +336,10 @@ describe('add to cart button loading tests', () => { | |
| test('renders a product bundle properly - parent item', () => { | ||
| const parent = mockProductBundle | ||
| renderWithProviders( | ||
| <MockComponent product={parent} addToCart={() => {}} addToWishlist={() => {}} /> | ||
| <MockComponent product={parent} addToCart={() => {}} addToWishlist={() => {}} />, | ||
| { | ||
| wrapperProps: {basket: mockBasket} | ||
| } | ||
| ) | ||
|
|
||
| // NOTE: there can be duplicates of the same element, due to mobile and desktop views | ||
|
|
@@ -330,7 +369,10 @@ test('renders a product bundle properly - child item', () => { | |
| addToWishlist={() => {}} | ||
| isProductPartOfBundle={true} | ||
| setChildProductOrderability={() => {}} | ||
| /> | ||
| />, | ||
| { | ||
| wrapperProps: {basket: mockBasket} | ||
| } | ||
| ) | ||
|
|
||
| const addToCartButton = screen.queryByRole('button', {name: /add to cart/i}) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.