-
Notifications
You must be signed in to change notification settings - Fork 214
@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 6 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 |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| /* | ||
| * 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 | ||
| */ | ||
| import React, {useContext, useState, useEffect} from 'react' | ||
| import {useLocation} from 'react-router-dom' | ||
| import { | ||
| Modal, | ||
| ModalCloseButton, | ||
| ModalContent, | ||
| ModalOverlay, | ||
| useBreakpointValue, | ||
alexvuong marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ModalHeader, | ||
| ModalBody, | ||
| Heading | ||
| } from '@salesforce/retail-react-app/app/components/shared/ui' | ||
| import {useAddToCartModalContext} from '@salesforce/retail-react-app/app/hooks/use-add-to-cart-modal' | ||
| import {isServer} from '@salesforce/retail-react-app/app/utils/utils' | ||
| import PropTypes from 'prop-types' | ||
|
|
||
| export const BonusProductModalContext = React.createContext() | ||
|
|
||
| export const useBonusProductModalContext = () => useContext(BonusProductModalContext) | ||
|
|
||
| export const BonusProductModalProvider = ({children}) => { | ||
| const bonusProductState = useBonusState() | ||
|
|
||
| return ( | ||
| <BonusProductModalContext.Provider value={bonusProductState}> | ||
| {children} | ||
| <BonusProductModal /> | ||
| </BonusProductModalContext.Provider> | ||
| ) | ||
| } | ||
| BonusProductModalProvider.propTypes = { | ||
| children: PropTypes.node.isRequired | ||
| } | ||
|
|
||
| export const BonusProductModal = () => { | ||
|
Collaborator
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 would move components to the component directory
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. Let's break this down into two parts - the hook for business logic (keep it under hooks) and component for presentation (under components)
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. @kzheng-sfdc Sure. This PR was already merged by the time this comment was made. @sf-vrushal-kulkarni will be making this change in his PR |
||
| const {isOpen, data, onClose, onOpen} = useBonusProductModalContext() | ||
| const size = useBreakpointValue({base: 'full', lg: '2xl', xl: '4xl'}) | ||
|
|
||
| if (!isOpen) { | ||
| return null | ||
| } | ||
| return ( | ||
| <Modal size={size} isOpen={isOpen} onClose={onClose} scrollBehavior="inside" isCentered> | ||
| <ModalOverlay /> | ||
| <ModalContent | ||
| margin="0" | ||
| borderRadius={{base: 'none', md: 'base'}} | ||
| bgColor="gray.50" | ||
| containerProps={{'data-testid': 'bonus-product-modal'}} | ||
| > | ||
| <ModalHeader paddingY="8" bgColor="white"> | ||
| <Heading as="h1" fontSize="2xl"></Heading> | ||
| </ModalHeader> | ||
| <ModalCloseButton /> | ||
| {/* Add your modal content here */} | ||
| <ModalBody bgColor="white" padding="0" marginBottom={{base: 40, lg: 0}}></ModalBody> | ||
sf-madhuri-uppu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| </ModalContent> | ||
| </Modal> | ||
| ) | ||
| } | ||
|
|
||
| export const useBonusState = () => { | ||
| const [state, setState] = useState({ | ||
| isOpen: false, | ||
| data: {}, | ||
| bonusProducts: !isServer ? JSON.parse(localStorage.getItem('bonusProducts') || '[]') : [] | ||
| }) | ||
| const {pathname} = useLocation() | ||
| const {onOpen: onAddToCartModalOpen} = useAddToCartModalContext() | ||
|
|
||
| useEffect(() => { | ||
| if (state.isOpen) { | ||
| setState((prev) => ({ | ||
| ...prev, | ||
| isOpen: false | ||
| })) | ||
| } | ||
| }, [pathname]) | ||
|
|
||
| const addBonusProducts = (newBonusItems) => { | ||
| setState((prev) => { | ||
| const updatedBonusProducts = [...prev.bonusProducts, ...newBonusItems] | ||
| // Store in localStorage only in browser environment | ||
| if (!isServer) { | ||
| localStorage.setItem('bonusProducts', JSON.stringify(updatedBonusProducts)) | ||
sf-madhuri-uppu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| return { | ||
| ...prev, | ||
| bonusProducts: updatedBonusProducts | ||
| } | ||
| }) | ||
| } | ||
|
|
||
| const clearBonusProducts = () => { | ||
| setState((prev) => ({ | ||
| ...prev, | ||
| bonusProducts: [] | ||
| })) | ||
| if (!isServer) { | ||
| localStorage.removeItem('bonusProducts') | ||
| } | ||
| } | ||
|
|
||
| return { | ||
| isOpen: state.isOpen, | ||
| data: state.data, | ||
| bonusProducts: state.bonusProducts, | ||
| addBonusProducts, | ||
| clearBonusProducts, | ||
| onClose: () => { | ||
| setState((prev) => ({ | ||
| ...prev, | ||
| isOpen: false, | ||
| data: {} | ||
| })) | ||
| // Show AddToCartModal after BonusProductModal is closed | ||
| if (state.data.product) { | ||
| onAddToCartModalOpen({ | ||
| product: state.data.product, | ||
| itemsAdded: state.data.itemsAdded, | ||
| selectedQuantity: state.data.selectedQuantity | ||
| }) | ||
| } | ||
| }, | ||
| onOpen: (data) => { | ||
| setState((prev) => ({ | ||
| ...prev, | ||
| isOpen: true, | ||
| data | ||
| })) | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
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.
change name to bonusItem?
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.
You can move this to within the "isValidResponse" check, right?