feat: product filter provider

:%s
This commit is contained in:
lytrankieio123
2021-10-07 10:27:07 +07:00
parent b572fcf8d6
commit ee06aff83a
10 changed files with 105 additions and 86 deletions

View File

@@ -1,5 +1,6 @@
import classNames from 'classnames'
import React, { memo, useEffect, useRef, useState } from 'react'
import { useProductFilter } from 'src/components/contexts'
import { useModalCommon } from 'src/components/hooks'
import ModalAuthenticate from '../ModalAuthenticate/ModalAuthenticate'
import ModalCreateUserInfo from '../ModalCreateUserInfo/ModalCreateUserInfo'
@@ -9,11 +10,12 @@ import HeaderSubMenu from './components/HeaderSubMenu/HeaderSubMenu'
import HeaderSubMenuMobile from './components/HeaderSubMenuMobile/HeaderSubMenuMobile'
import s from './Header.module.scss'
interface props {
toggleFilter: () => void,
}
const Header = memo(({ toggleFilter }: props) => {
const Header = memo(({ }: props) => {
const headeFullRef = useRef<HTMLDivElement>(null)
const { toggleProductFilter: toggleFilter } = useProductFilter()
const [isFullHeader, setIsFullHeader] = useState<boolean>(true)
const [isModeAuthenRegister, setIsModeAuthenRegister] = useState<boolean>(false)
const { visible: visibleModalAuthen, closeModal: closeModalAuthen, openModal: openModalAuthen } = useModalCommon({ initialValue: false })

View File

@@ -1,7 +1,7 @@
import { CommerceProvider } from '@framework'
import { useRouter } from 'next/router'
import { FC } from 'react'
import { CartDrawerProvider, MessageProvider } from 'src/components/contexts'
import { CartDrawerProvider, MessageProvider, ProductFilterProvider } from 'src/components/contexts'
import LayoutContent from './LayoutContent/LayoutContent'
interface Props {
className?: string
@@ -13,9 +13,11 @@ const Layout: FC<Props> = ({ children }) => {
return (
<CommerceProvider locale={locale}>
<CartDrawerProvider>
<ProductFilterProvider>
<MessageProvider>
<LayoutContent>{children}</LayoutContent>
</MessageProvider>
</ProductFilterProvider>
</CartDrawerProvider>
</CommerceProvider>
)

View File

@@ -15,21 +15,12 @@ interface Props {
const LayoutContent: FC<Props> = ({ children }) => {
const router = useRouter()
const { visible: visibleFilter, openModal: openFilter, closeModal: closeFilter } = useModalCommon({ initialValue: false })
const {messages, removeMessage} = useMessage()
const toggleFilter = () => {
if (visibleFilter) {
closeFilter()
} else {
openFilter()
}
}
return (
<>
<div className={s.mainLayout}>
<Header toggleFilter={toggleFilter}/>
<Header/>
{
router.pathname === ROUTE.ACCOUNT ?
<section className={s.wrapperWithBg}>
@@ -39,7 +30,7 @@ const LayoutContent: FC<Props> = ({ children }) => {
}
<ScrollToTop visibilityHeight={1500} />
{
FILTER_PAGE.includes(router.pathname) && (<div className={s.filter}><MenuNavigationProductList visible={visibleFilter} onClose={closeFilter} /> </div>)
FILTER_PAGE.includes(router.pathname) && (<div className={s.filter}><MenuNavigationProductList /> </div>)
}
<Footer />
</div>

View File

@@ -3,6 +3,7 @@ import classNames from 'classnames';
import { useRouter } from 'next/router';
import React, { useEffect, useState } from 'react';
import { ButtonCommon } from 'src/components/common';
import { useProductFilter } from 'src/components/contexts';
import { useGetAllCollection } from 'src/components/hooks/collection';
import { useFacets } from 'src/components/hooks/facets';
import IconHide from 'src/components/icons/IconHide';
@@ -15,8 +16,7 @@ import s from './MenuNavigationProductList.module.scss';
import MenuSort from './MenuSort/MenuSort';
interface Props {
visible: boolean,
onClose: () => void
}
const FACET_QUERY = {
@@ -32,8 +32,9 @@ const FACET_QUERY = {
}
} as QueryFacetsArgs
const MenuNavigationProductList = ({ visible, onClose }: Props) => {
const MenuNavigationProductList = ({}: Props) => {
const router = useRouter()
const { productFilterVisible: visible, closeProductFilter: onClose } = useProductFilter()
const { facets, loading: facetsLoading } = useFacets(FACET_QUERY)
const { collections, loading: collectionLoading } = useGetAllCollection()
const [brandQuery, setBrandQuery] = useState<string[]>([])

View File

@@ -1,43 +0,0 @@
import { createContext, ReactNode, useContext, useState } from "react";
import { filterContextType } from "src/utils/types.utils";
const contextDefaultValues: filterContextType = {
visible: false,
open: () => {},
close: () => {},
};
const FilterContext = createContext<filterContextType>(contextDefaultValues);
export function useAuth() {
return useContext(FilterContext);
}
type FilterProviderProps = {
children: ReactNode;
};
export function FilterProvider({ children }: FilterProviderProps) {
const [visible, setVisible] = useState<boolean>(false);
const open = () => {
setVisible(true);
};
const close = () => {
setVisible(false);
};
const value = {
visible,
open,
close,
};
return (
<>
<FilterContext.Provider value={value}>
{children}
</FilterContext.Provider>
</>
);
}

View File

@@ -0,0 +1,20 @@
import { createContext, useContext } from 'react';
export type ProductFilterContextType = {
productFilterVisible: boolean;
toggleProductFilter: (visible?: boolean) => void;
openProductFilter: () => void;
closeProductFilter: () => void;
};
const DEFAULT_VALUE: ProductFilterContextType = {
productFilterVisible: false,
toggleProductFilter: () => { },
openProductFilter: () => { },
closeProductFilter: () => { },
};
export const ProductFilterContext = createContext<ProductFilterContextType>(DEFAULT_VALUE)
export function useProductFilter() {
return useContext(ProductFilterContext);
}

View File

@@ -0,0 +1,30 @@
import { ReactNode, useState } from "react";
import { ProductFilterContext } from "./ProductFilterContext";
type Props = {
children: ReactNode;
};
export function ProductFilterProvider({ children }: Props) {
const [visible, setVisible] = useState<boolean>(false);
const closeProductFilter = () => {
setVisible(false);
};
const openProductFilter = () => {
setVisible(true);
};
const toggleProductFilter = () => {
setVisible(!visible);
};
return (
<>
<ProductFilterContext.Provider value={{productFilterVisible: visible, closeProductFilter, openProductFilter, toggleProductFilter}}>
{children}
</ProductFilterContext.Provider>
</>
);
}

View File

@@ -3,3 +3,6 @@ export * from './CartDrawer/CartDrawerProvider'
export * from './Message/MessageContext'
export * from './Message/MessageProvider'
export * from './ProductFilter/ProductFilterContext'
export * from './ProductFilter/ProductFilterProvider'

View File

@@ -16,29 +16,34 @@
.list{
@apply w-full;
.top {
.left {
@apply flex justify-between items-center;
}
.iconFilter {
@apply relative;
&:focus {
outline: none;
filter: brightness(1.05);
}
&:focus-visible {
outline: 2px solid var(--text-active);
}
.dot {
@apply absolute;
top: -0.08rem;
right: -0.2rem;
background-color: var(--negative);
width: 1.2rem;
height: 1.2rem;
border-radius: 1.2rem;
}
}
@screen md {
@apply flex justify-between flex-wrap w-full;
margin: 1rem 0;
}
}
.inner{
@screen md {
@apply flex flex-col items-center justify-center;
}
.boxItem {
@screen md {
@apply flex justify-between flex-wrap;
margin: 1rem 0;
}
.item {
@screen md {
width: calc(97% / 2);
margin-top:1rem;
}
@screen lg{
width: calc(97% / 3);
margin-top:1rem;
}
.iconFilter {
@apply hidden;
}
}
}

View File

@@ -4,8 +4,9 @@ import { useRouter } from 'next/router'
import React, { useEffect, useState } from 'react'
import { HeadingCommon, ListProductCardSkeleton, ProductList } from 'src/components/common'
import BreadcrumbCommon from 'src/components/common/BreadcrumbCommon/BreadcrumbCommon'
import SkeletonImage from 'src/components/common/SkeletonCommon/SkeletonImage/SkeletonImage'
import { useProductFilter } from 'src/components/contexts'
import { useSearchProducts } from 'src/components/hooks/product'
import { IconFilter } from 'src/components/icons'
import { DEFAULT_PAGE_SIZE, QUERY_KEY, QUERY_SPLIT_SEPERATOR, ROUTE } from 'src/utils/constanst.utils'
import { getFacetIdsFromCodes, getPageFromQuery, getProductSortParamFromQuery } from 'src/utils/funtion.utils'
import s from './ProductListFilter.module.scss'
@@ -34,6 +35,7 @@ const DEFAULT_SEARCH_ARGS = {
const ProductListFilter = ({ facets, collections, products, total }: ProductListFilterProps) => {
const router = useRouter()
const { openProductFilter } = useProductFilter()
const [initialQueryFlag, setInitialQueryFlag] = useState<boolean>(true)
const [optionQueryProduct, setOptionQueryProduct] = useState<QuerySearchArgs>({ input: DEFAULT_SEARCH_ARGS })
const { products: productSearchResult, totalItems, loading } = useSearchProducts(optionQueryProduct)
@@ -101,14 +103,20 @@ const ProductListFilter = ({ facets, collections, products, total }: ProductList
<ProductsMenuNavigationTablet facets={facets} collections={collections} />
<div className={s.list}>
<div className={s.top}>
<div className={s.left}>
<HeadingCommon align="left">SPECIAL RECIPES</HeadingCommon>
<button className={s.iconFilter} onClick={openProductFilter}>
<IconFilter />
<div className={s.dot}></div>
</button>
</div>
<div className={s.boxSelect}>
<ProductSort />
</div>
</div>
{
(!initialQueryFlag && loading && !productSearchResult) && <ListProductCardSkeleton count={DEFAULT_PAGE_SIZE} isWrap/>
(!initialQueryFlag && loading && !productSearchResult) && <ListProductCardSkeleton count={DEFAULT_PAGE_SIZE} isWrap />
}
<ProductList data={initialQueryFlag ? products : (productSearchResult || [])} total={totalItems !== undefined ? totalItems : total} onPageChange={onPageChange} defaultCurrentPage={currentPage} />
</div>