mirror of
https://github.com/vercel/commerce.git
synced 2025-07-22 20:26:49 +00:00
✨ feat: cart drawer context
:%s
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { useCartDrawer } from 'src/components/contexts/CartDrawer/CartDrawerContext';
|
||||
import { PRODUCT_CART_DATA_TEST } from 'src/utils/demo-data';
|
||||
import { DrawerCommon } from '..';
|
||||
import s from './CartDrawer.module.scss';
|
||||
@@ -8,24 +9,24 @@ import CartRecommendation from './components/CartRecommendation/CartRecommendati
|
||||
import ProductsInCart from './components/ProductsInCart/ProductsInCart';
|
||||
|
||||
interface Props {
|
||||
visible: boolean
|
||||
onClose: () => void
|
||||
|
||||
}
|
||||
|
||||
const CartDrawer = ({ visible, onClose }: Props) => {
|
||||
const CartDrawer = ({ }: Props) => {
|
||||
const { cartVisible, closeCartDrawer } = useCartDrawer()
|
||||
return (
|
||||
<DrawerCommon
|
||||
title={`Your cart (${PRODUCT_CART_DATA_TEST.length})`}
|
||||
visible={visible}
|
||||
onClose={onClose}>
|
||||
visible={cartVisible}
|
||||
onClose={closeCartDrawer}>
|
||||
<div className={s.cartDrawer}>
|
||||
<div className={s.body}>
|
||||
<ProductsInCart data={PRODUCT_CART_DATA_TEST}/>
|
||||
<ProductsInCart data={PRODUCT_CART_DATA_TEST} />
|
||||
<CartRecommendation />
|
||||
</div>
|
||||
<div>
|
||||
<CartMessage />
|
||||
<CartCheckoutButton onClose={onClose}/>
|
||||
<CartCheckoutButton onClose={closeCartDrawer} />
|
||||
</div>
|
||||
</div>
|
||||
</DrawerCommon>
|
||||
|
@@ -19,15 +19,6 @@ const Header = memo(({ toggleFilter, visibleFilter }: props) => {
|
||||
const [isFullHeader, setIsFullHeader] = useState<boolean>(true)
|
||||
const { visible: visibleModalAuthen, closeModal: closeModalAuthen, openModal: openModalAuthen } = useModalCommon({ initialValue: false })
|
||||
const { visible: visibleModalInfo, closeModal: closeModalInfo, openModal: openModalInfo } = useModalCommon({ initialValue: false })
|
||||
const { visible: visibleCartDrawer, openModal: openCartDrawer, closeModal: closeCartDrawer } = useModalCommon({ initialValue: false })
|
||||
|
||||
const toggleCart = () => {
|
||||
if (visibleCartDrawer) {
|
||||
closeCartDrawer()
|
||||
} else {
|
||||
openCartDrawer()
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
@@ -36,10 +27,6 @@ const Header = memo(({ toggleFilter, visibleFilter }: props) => {
|
||||
} else {
|
||||
setIsFullHeader(true)
|
||||
}
|
||||
// if (!isMobile()) {
|
||||
// } else {
|
||||
// setIsFullHeader(true)
|
||||
// }
|
||||
}
|
||||
window.addEventListener('scroll', handleScroll)
|
||||
return () => {
|
||||
@@ -56,7 +43,6 @@ const Header = memo(({ toggleFilter, visibleFilter }: props) => {
|
||||
<HeaderMenu
|
||||
isStickyHeader={true}
|
||||
toggleFilter={toggleFilter}
|
||||
toggleCart={toggleCart}
|
||||
openModalAuthen={openModalAuthen}
|
||||
openModalInfo={openModalInfo} />
|
||||
</div>
|
||||
@@ -68,7 +54,6 @@ const Header = memo(({ toggleFilter, visibleFilter }: props) => {
|
||||
isFull={isFullHeader}
|
||||
visibleFilter={visibleFilter}
|
||||
toggleFilter={toggleFilter}
|
||||
toggleCart={toggleCart}
|
||||
openModalAuthen={openModalAuthen}
|
||||
openModalInfo={openModalInfo} />
|
||||
<HeaderSubMenu />
|
||||
@@ -78,9 +63,7 @@ const Header = memo(({ toggleFilter, visibleFilter }: props) => {
|
||||
<HeaderSubMenuMobile />
|
||||
<ModalAuthenticate visible={visibleModalAuthen} closeModal={closeModalAuthen} />
|
||||
<ModalCreateUserInfo demoVisible={visibleModalInfo} demoCloseModal={closeModalInfo} />
|
||||
<CartDrawer
|
||||
visible={visibleCartDrawer}
|
||||
onClose={closeCartDrawer} />
|
||||
|
||||
</>
|
||||
)
|
||||
})
|
||||
|
@@ -5,6 +5,7 @@ import { memo, useMemo } from 'react'
|
||||
import { ButtonCommon } from 'src/components/common'
|
||||
import InputSearch from 'src/components/common/InputSearch/InputSearch'
|
||||
import MenuDropdown from 'src/components/common/MenuDropdown/MenuDropdown'
|
||||
import { useCartDrawer } from 'src/components/contexts/CartDrawer/CartDrawerContext'
|
||||
import { IconBuy, IconFilter, IconHeart, IconHistory, IconUser } from 'src/components/icons'
|
||||
import { ACCOUNT_TAB, FILTER_PAGE, QUERY_KEY, ROUTE } from 'src/utils/constanst.utils'
|
||||
import Logo from '../../../Logo/Logo'
|
||||
@@ -17,13 +18,12 @@ interface Props {
|
||||
openModalAuthen: () => void,
|
||||
openModalInfo: () => void,
|
||||
toggleFilter: () => void,
|
||||
toggleCart: () => void,
|
||||
}
|
||||
|
||||
|
||||
const HeaderMenu = memo(({ isFull, isStickyHeader, visibleFilter, openModalAuthen, openModalInfo, toggleFilter, toggleCart }: Props) => {
|
||||
const HeaderMenu = memo(({ isFull, isStickyHeader, visibleFilter, openModalAuthen, openModalInfo, toggleFilter }: Props) => {
|
||||
const router = useRouter()
|
||||
|
||||
const { toggleCartDrawer } = useCartDrawer()
|
||||
|
||||
const optionMenu = useMemo(() => [
|
||||
{
|
||||
@@ -74,7 +74,7 @@ const HeaderMenu = memo(({ isFull, isStickyHeader, visibleFilter, openModalAuthe
|
||||
</button>
|
||||
)
|
||||
}
|
||||
<button className={`${s.iconCart} ${s.btnCart}`} onClick={toggleCart}>
|
||||
<button className={`${s.iconCart} ${s.btnCart}`} onClick={toggleCartDrawer}>
|
||||
<IconBuy />
|
||||
</button>
|
||||
</div>
|
||||
@@ -108,7 +108,7 @@ const HeaderMenu = memo(({ isFull, isStickyHeader, visibleFilter, openModalAuthe
|
||||
<MenuDropdown options={optionMenu} isHasArrow={false}><IconUser /></MenuDropdown>
|
||||
</li>
|
||||
<li>
|
||||
<button className={s.btnCart} onClick={toggleCart}>
|
||||
<button className={s.btnCart} onClick={toggleCartDrawer}>
|
||||
<IconBuy />
|
||||
</button>
|
||||
</li>
|
||||
|
@@ -1,14 +1,8 @@
|
||||
import { CommerceProvider } from '@framework'
|
||||
import { useRouter } from 'next/router'
|
||||
import { FC } from 'react'
|
||||
import { useModalCommon } from 'src/components/hooks'
|
||||
import { BRAND, CATEGORY, FEATURED, FILTER_PAGE, ROUTE } from 'src/utils/constanst.utils'
|
||||
import { ScrollToTop } from '..'
|
||||
import Footer from '../Footer/Footer'
|
||||
import Header from '../Header/Header'
|
||||
import MenuNavigationProductList from '../MenuNavigationProductList/MenuNavigationProductList'
|
||||
import s from './Layout.module.scss'
|
||||
|
||||
import { CartDrawerProvider } from 'src/components/contexts/CartDrawer/CartDrawerProvider'
|
||||
import LayoutContent from './LayoutContent/LayoutContent'
|
||||
interface Props {
|
||||
className?: string
|
||||
children?: any
|
||||
@@ -16,37 +10,14 @@ interface Props {
|
||||
|
||||
// note: demo code
|
||||
const Layout: FC<Props> = ({ children }) => {
|
||||
const { locale = 'en-US', pathname } = useRouter()
|
||||
const { visible: visibleFilter, openModal: openFilter, closeModal: closeFilter } = useModalCommon({ initialValue: false })
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const toggleFilter = () => {
|
||||
if (visibleFilter) {
|
||||
closeFilter()
|
||||
} else {
|
||||
openFilter()
|
||||
}
|
||||
}
|
||||
|
||||
const { locale = 'en-US' } = useRouter()
|
||||
return (
|
||||
<CommerceProvider locale={locale}>
|
||||
<div className={s.mainLayout}>
|
||||
<Header toggleFilter={toggleFilter} visibleFilter={visibleFilter} />
|
||||
{
|
||||
router.pathname === ROUTE.ACCOUNT ?
|
||||
<section className={s.wrapperWithBg}>
|
||||
<main>{children}</main>
|
||||
</section> :
|
||||
<main>{children}</main>
|
||||
}
|
||||
<div className={s.filter}><MenuNavigationProductList categories={CATEGORY} brands={BRAND} featured={FEATURED} visible={visibleFilter} onClose={closeFilter} /> </div>
|
||||
<ScrollToTop visibilityHeight={1500} />
|
||||
{
|
||||
FILTER_PAGE.includes(pathname) && (<div className={s.filter}><MenuNavigationProductList categories={CATEGORY} brands={BRAND} featured={FEATURED} visible={visibleFilter} onClose={closeFilter}/> </div>)
|
||||
}
|
||||
<Footer />
|
||||
</div>
|
||||
<CartDrawerProvider>
|
||||
<LayoutContent>
|
||||
{children}
|
||||
</LayoutContent>
|
||||
</CartDrawerProvider>
|
||||
</CommerceProvider>
|
||||
|
||||
)
|
||||
|
53
src/components/common/Layout/LayoutContent/LayoutContent.tsx
Normal file
53
src/components/common/Layout/LayoutContent/LayoutContent.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import { FC } from 'react'
|
||||
import { useCartDrawer } from 'src/components/contexts/CartDrawer/CartDrawerContext'
|
||||
import { useModalCommon } from 'src/components/hooks'
|
||||
import { BRAND, CATEGORY, FEATURED, FILTER_PAGE, ROUTE } from 'src/utils/constanst.utils'
|
||||
import { CartDrawer, Footer, ScrollToTop } from '../..'
|
||||
import Header from '../../Header/Header'
|
||||
import MenuNavigationProductList from '../../MenuNavigationProductList/MenuNavigationProductList'
|
||||
import s from './LayoutContent.module.scss'
|
||||
|
||||
interface Props {
|
||||
className?: string
|
||||
children?: any
|
||||
}
|
||||
|
||||
const LayoutContent: FC<Props> = ({ children }) => {
|
||||
const { pathname } = useRouter()
|
||||
const { visible: visibleFilter, openModal: openFilter, closeModal: closeFilter } = useModalCommon({ initialValue: false })
|
||||
const router = useRouter()
|
||||
|
||||
const toggleFilter = () => {
|
||||
if (visibleFilter) {
|
||||
closeFilter()
|
||||
} else {
|
||||
openFilter()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={s.mainLayout}>
|
||||
<Header toggleFilter={toggleFilter} visibleFilter={visibleFilter} />
|
||||
{
|
||||
router.pathname === ROUTE.ACCOUNT ?
|
||||
<section className={s.wrapperWithBg}>
|
||||
<main>{children}</main>
|
||||
</section> :
|
||||
<main>{children}</main>
|
||||
}
|
||||
<div className={s.filter}><MenuNavigationProductList categories={CATEGORY} brands={BRAND} featured={FEATURED} visible={visibleFilter} onClose={closeFilter} /> </div>
|
||||
<ScrollToTop visibilityHeight={1500} />
|
||||
{
|
||||
FILTER_PAGE.includes(pathname) && (<div className={s.filter}><MenuNavigationProductList categories={CATEGORY} brands={BRAND} featured={FEATURED} visible={visibleFilter} onClose={closeFilter} /> </div>)
|
||||
}
|
||||
<Footer />
|
||||
</div>
|
||||
<CartDrawer />
|
||||
</>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutContent
|
20
src/components/contexts/CartDrawer/CartDrawerContext.tsx
Normal file
20
src/components/contexts/CartDrawer/CartDrawerContext.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
export type CartDrawerContextType = {
|
||||
cartVisible: boolean;
|
||||
toggleCartDrawer: (visible?: boolean) => void;
|
||||
openCartDrawer: () => void;
|
||||
closeCartDrawer: () => void;
|
||||
};
|
||||
export const DEFAULT_CART_DRAWER_CONTEXT: CartDrawerContextType = {
|
||||
cartVisible: false,
|
||||
toggleCartDrawer: () => { },
|
||||
openCartDrawer: () => { },
|
||||
closeCartDrawer: () => { },
|
||||
};
|
||||
|
||||
export const CartDrawerContext = createContext<CartDrawerContextType>(DEFAULT_CART_DRAWER_CONTEXT)
|
||||
|
||||
export function useCartDrawer() {
|
||||
return useContext(CartDrawerContext);
|
||||
}
|
42
src/components/contexts/CartDrawer/CartDrawerProvider.tsx
Normal file
42
src/components/contexts/CartDrawer/CartDrawerProvider.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import { ReactNode, useEffect, useState } from "react";
|
||||
import { CartDrawerContext } from "./CartDrawerContext";
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export function CartDrawerProvider({ children }: Props) {
|
||||
const [visible, setVisible] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
const bodyElement = document.getElementsByTagName('body')[0]
|
||||
if (bodyElement) {
|
||||
if (visible) {
|
||||
bodyElement.style.overflow = 'hidden'
|
||||
} else {
|
||||
bodyElement.style.overflow = 'auto'
|
||||
bodyElement.removeAttribute('scroll')
|
||||
}
|
||||
}
|
||||
}, [visible])
|
||||
|
||||
const closeCartDrawer = () => {
|
||||
setVisible(false);
|
||||
};
|
||||
|
||||
const openCartDrawer = () => {
|
||||
setVisible(true);
|
||||
};
|
||||
|
||||
const toggleCartDrawer = () => {
|
||||
setVisible(!visible);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<CartDrawerContext.Provider value={{cartVisible: visible, closeCartDrawer, openCartDrawer, toggleCartDrawer}}>
|
||||
{children}
|
||||
</CartDrawerContext.Provider>
|
||||
</>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user