feat: get collections, facets in menu filter

:%s
This commit is contained in:
lytrankieio123
2021-10-06 11:14:10 +07:00
parent c154541948
commit ef7b490416
12 changed files with 136 additions and 95 deletions

View File

@@ -3228,8 +3228,9 @@ export type GetAllFacetsQuery = { __typename?: 'Query' } & {
items: Array< items: Array<
{ __typename?: 'Facet' } & Pick< { __typename?: 'Facet' } & Pick<
Facet, Facet,
'id' | 'name' | 'code' 'id' | 'name' | 'code' | 'values'
> & { >
& {
parent?: Maybe<{ __typename?: 'Facet' } & Pick<Facet, 'id'>> parent?: Maybe<{ __typename?: 'Facet' } & Pick<Facet, 'id'>>
children?: Maybe< children?: Maybe<
Array<{ __typename?: 'Facet' } & Pick<Facet, 'id'>> Array<{ __typename?: 'Facet' } & Pick<Facet, 'id'>>

View File

@@ -42,7 +42,7 @@ const HeaderSubMenu = memo(() => {
<ul className={s.menu}> <ul className={s.menu}>
{/* todo: handle active item */} {/* todo: handle active item */}
<li> <li>
<MenuDropdown options={collections?.items ?? []} align="left">Categories</MenuDropdown> <MenuDropdown options={collections || []} align="left">Categories</MenuDropdown>
</li> </li>
{ {
MENU.map(item => <li key={item.name} MENU.map(item => <li key={item.name}

View File

@@ -2,7 +2,7 @@ import { useRouter } from 'next/router'
import { FC } from 'react' import { FC } from 'react'
import { useMessage } from 'src/components/contexts' import { useMessage } from 'src/components/contexts'
import { useModalCommon } from 'src/components/hooks' import { useModalCommon } from 'src/components/hooks'
import { BRAND, CATEGORY, FEATURED, FILTER_PAGE, ROUTE } from 'src/utils/constanst.utils' import { FILTER_PAGE, ROUTE } from 'src/utils/constanst.utils'
import { CartDrawer, Footer, MessageCommon, ScrollToTop } from '../..' import { CartDrawer, Footer, MessageCommon, ScrollToTop } from '../..'
import Header from '../../Header/Header' import Header from '../../Header/Header'
import MenuNavigationProductList from '../../MenuNavigationProductList/MenuNavigationProductList' import MenuNavigationProductList from '../../MenuNavigationProductList/MenuNavigationProductList'
@@ -14,9 +14,8 @@ interface Props {
} }
const LayoutContent: FC<Props> = ({ children }) => { const LayoutContent: FC<Props> = ({ children }) => {
const { pathname } = useRouter()
const { visible: visibleFilter, openModal: openFilter, closeModal: closeFilter } = useModalCommon({ initialValue: false })
const router = useRouter() const router = useRouter()
const { visible: visibleFilter, openModal: openFilter, closeModal: closeFilter } = useModalCommon({ initialValue: true })
const {messages, removeMessage} = useMessage() const {messages, removeMessage} = useMessage()
const toggleFilter = () => { const toggleFilter = () => {
@@ -30,6 +29,7 @@ const LayoutContent: FC<Props> = ({ children }) => {
return ( return (
<> <>
<div className={s.mainLayout}> <div className={s.mainLayout}>
{router.pathname}
<Header toggleFilter={toggleFilter} visibleFilter={visibleFilter} /> <Header toggleFilter={toggleFilter} visibleFilter={visibleFilter} />
{ {
router.pathname === ROUTE.ACCOUNT ? router.pathname === ROUTE.ACCOUNT ?
@@ -38,10 +38,9 @@ const LayoutContent: FC<Props> = ({ children }) => {
</section> : </section> :
<main>{children}</main> <main>{children}</main>
} }
<div className={s.filter}><MenuNavigationProductList categories={CATEGORY} brands={BRAND} featured={FEATURED} visible={visibleFilter} onClose={closeFilter} /> </div>
<ScrollToTop visibilityHeight={1500} /> <ScrollToTop visibilityHeight={1500} />
{ {
FILTER_PAGE.includes(pathname) && (<div className={s.filter}><MenuNavigationProductList categories={CATEGORY} brands={BRAND} featured={FEATURED} visible={visibleFilter} onClose={closeFilter} /> </div>) FILTER_PAGE.includes(router.pathname) && (<div className={s.filter}><MenuNavigationProductList visible={visibleFilter} onClose={closeFilter} /> </div>)
} }
<Footer /> <Footer />
</div> </div>

View File

@@ -1,9 +1,7 @@
@import "../../../styles/utilities"; @import "../../../styles/utilities";
.menuFilterWrapper{ .menuFilterWrapper{
@apply spacing-horizontal;
.menuFilterHeading{ .menuFilterHeading{
@apply sub-headline font-bold ; @apply sub-headline font-bold;
color: var(--text-active); color: var(--text-active);
font-feature-settings: 'salt' on; font-feature-settings: 'salt' on;
margin: 0.8rem 0; margin: 0.8rem 0;

View File

@@ -2,43 +2,31 @@ import classNames from 'classnames'
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import s from './MenuFilter.module.scss' import s from './MenuFilter.module.scss'
import MenuFilterItem from './MenuFilterItem/MenuFilterItem';
interface Props { interface Props {
children?: any, children?: any,
heading?:string, heading?: string,
categories:{name:string,link:string}[], categories: { name: string, slug?: string, code?: string }[],
type:string, type: string,
onChangeValue?: (value: Object) => void onChangeValue?: (value: Object) => void
} }
const MenuFilter = ({heading,categories,type,onChangeValue}:Props)=> { const MenuFilter = ({ heading, categories, type, onChangeValue }: Props) => {
const [active, setActive] = useState<string>(''); function handleClick(value: string) {
function handleClick(link:string){
setActive(link);
if(active === link){
setActive('');
}
} }
useEffect(()=>{
let href = active?.split("=");
const linkValue = href[1];
onChangeValue && onChangeValue({[type]:linkValue});
},[active])
return ( return (
<section className={s.menuFilterWrapper}> <section className={s.menuFilterWrapper}>
<h2 className={s.menuFilterHeading}>{heading}</h2> <h2 className={s.menuFilterHeading}>{heading}</h2>
<ul className={s.menuFilterList}> <ul className={s.menuFilterList}>
{ {
categories.map(item => <li key={item.name}> categories.map(item => <MenuFilterItem
<div onClick={()=> handleClick(item.link)} className={classNames({ [s.active]: item.link === active? true: false })}> key={item.slug || item.code}
{item.name} name={item.name}
</div> value={item.slug || item.code || ''}
</li>) onClick={handleClick}
/>)
} }
</ul> </ul>
</section> </section>

View File

@@ -0,0 +1,16 @@
.menuFilterItem {
margin: 1rem 0;
padding: 0;
div {
padding: 0.8rem 1.6rem;
margin-right: 0.8rem;
background-color: var(--gray);
border-radius: 0.8rem;
cursor: pointer;
&.active {
color: var(--white);
background-color: var(--primary);
}
}
}

View File

@@ -0,0 +1,28 @@
import classNames from 'classnames';
import { useState } from 'react';
import s from './MenuFilterItem.module.scss';
interface Props {
name: string,
value: string,
onClick: (value: string) => void
}
const MenuFilterItem = ({ name, value, onClick }: Props) => {
const [isSelected, setIsSelected] = useState(false)
function handleClick() {
// todo
setIsSelected(!isSelected)
}
return (
<li className={s.menuFilterItem}>
<div onClick={handleClick} className={classNames({ [s.active]: isSelected })}>
{name}
</div>
</li>
)
}
export default MenuFilterItem

View File

@@ -1,13 +1,5 @@
@import "../../../styles/utilities"; @import "../../../styles/utilities";
.menuNavigationProductListDesktop{
@screen sm {
@apply hidden;
}
@screen xl {
@apply block;
}
}
.menuNavigationProductListMobile{ .menuNavigationProductListMobile{
@apply relative transition-all duration-100; @apply relative transition-all duration-100;
&.isShow{ &.isShow{
@@ -37,7 +29,7 @@
transform: translateY(0%) transform: translateY(0%)
} }
.content{ .content{
@apply absolute w-full h-full; @apply absolute w-full h-full spacing-horizontal custom-scroll;
margin-top: 3rem; margin-top: 3rem;
padding-top: 10rem ; padding-top: 10rem ;
padding-bottom: 10rem; padding-bottom: 10rem;
@@ -46,6 +38,7 @@
height: 96%; height: 96%;
bottom: 0; bottom: 0;
border-radius: 2.4rem 2.4rem 0 0; border-radius: 2.4rem 2.4rem 0 0;
.head{ .head{
@apply flex justify-between fixed; @apply flex justify-between fixed;
top:0; top:0;
@@ -57,12 +50,11 @@
background-color: white; background-color: white;
z-index: 10000; z-index: 10000;
h3{ h3{
@apply heading-3 font-bold; @apply heading-3 font-heading;
color:var(--text-base);
} }
} }
.foot{ .foot{
@apply fixed; @apply fixed text-center;
bottom: 0; bottom: 0;
left:0; left:0;
width: 100%; width: 100%;
@@ -70,7 +62,7 @@
padding: 0 1rem 3rem 1rem; padding: 0 1rem 3rem 1rem;
} }
button{ button {
margin-top: 2rem; margin-top: 2rem;
width: 100%; width: 100%;
} }

View File

@@ -1,56 +1,78 @@
import { QueryFacetsArgs } from '@framework/schema';
import classNames from 'classnames';
import React, { useState } from 'react'; import React, { useState } from 'react';
import {ButtonCommon} from 'src/components/common'; import { ButtonCommon } from 'src/components/common';
import { useGetAllCollection } from 'src/components/hooks/collection';
import { useFacets } from 'src/components/hooks/facets';
import IconHide from 'src/components/icons/IconHide';
import { CODE_FACET_BRAND, CODE_FACET_FEATURED, QUERY_KEY } from 'src/utils/constanst.utils';
import { LANGUAGE } from 'src/utils/language.utils';
import { SortOrder } from 'src/utils/types.utils';
import MenuFilter from '../MenuFilter/MenuFilter';
import SkeletonParagraph from '../SkeletonCommon/SkeletonParagraph/SkeletonParagraph';
import s from './MenuNavigationProductList.module.scss'; import s from './MenuNavigationProductList.module.scss';
import MenuSort from './MenuSort/MenuSort'; import MenuSort from './MenuSort/MenuSort';
import {LANGUAGE} from 'src/utils/language.utils';
import classNames from 'classnames'
import MenuFilter from '../MenuFilter/MenuFilter';
import MenuNavigation from '../MenuNavigation/MenuNavigation';
import IconHide from 'src/components/icons/IconHide';
interface Props{ interface Props {
categories:{name:string,link:string}[],
brands:{name:string,link:string}[],
featured:{name:string,link:string}[],
visible: boolean, visible: boolean,
onClose: () => void onClose: () => void
} }
const MenuNavigationProductList = ({categories,brands,featured,visible,onClose}:Props)=>{ const FACET_QUERY = {
options: {
const [dataSort,setDataSort] = useState({}); sort: {
code: SortOrder.Asc
function handleValue(value:Object){ },
setDataSort({...dataSort,...value}); filter: {
code: {
in: [CODE_FACET_FEATURED, CODE_FACET_BRAND]
}
}
} }
function filter(){ } as QueryFacetsArgs
const MenuNavigationProductList = ({ visible, onClose }: Props) => {
const { facets, loading: facetsLoading } = useFacets(FACET_QUERY)
const { collections, loading: collectionLoading } = useGetAllCollection()
const [dataSort, setDataSort] = useState({});
function handleValue(value: Object) {
setDataSort({ ...dataSort, ...value });
}
function filter() {
// console.log(dataSort) // console.log(dataSort)
} }
return(
<>
<div className={s.menuNavigationProductListDesktop}> return (
<MenuNavigation categories={categories} heading="Categories"/> <div className={classNames({ [s.menuNavigationProductListMobile]: true, [s.isShow]: visible })}>
<MenuNavigation categories={brands} heading="Brands"/> <div className={classNames({ [s.menuNavigationProductModal]: true, [s.animation]: visible })}>
<MenuNavigation categories={featured} heading="Featured"/> <div className={s.content}>
</div> <div className={s.head}>
<div className={classNames({ [s.menuNavigationProductListMobile] :true,[s.isShow]: visible})}> <h3>FILTER</h3>
<div className={classNames({ [s.menuNavigationProductModal] :true,[s.animation]: visible})}> <div onClick={onClose}><IconHide /></div>
<div className={s.content}> </div>
<div className={s.head}> {collectionLoading && <SkeletonParagraph rows={5} />}
<h3>FILTER</h3> <MenuFilter categories={collections} heading="Categories" type={QUERY_KEY.CATEGORY} onChangeValue={handleValue} />
<div onClick={onClose}><IconHide/></div> {facetsLoading && <>
</div> <SkeletonParagraph rows={5} />
<MenuFilter categories={categories} heading="Categories" type="category" onChangeValue={handleValue}/> <SkeletonParagraph rows={5} />
<MenuFilter categories={brands} heading="Brand" type="brand" onChangeValue={handleValue}/> </>}
<MenuFilter categories={featured} heading="Featured" type="featured" onChangeValue={handleValue}/> {
<MenuSort heading="SORT BY" type="sort" onChangeValue={handleValue}/> facets?.map(item => <MenuFilter
<div className={s.foot}> key={item.id}
<ButtonCommon size="large" onClick={filter}>{LANGUAGE.BUTTON_LABEL.CONFIRM}</ButtonCommon> type={item.code}
</div> categories={item.values}
heading={item.name} />)
}
<MenuSort heading="SORT BY" type="sort" onChangeValue={handleValue} />
<div className={s.foot}>
<ButtonCommon size="large" onClick={filter}>{LANGUAGE.BUTTON_LABEL.CONFIRM}</ButtonCommon>
</div> </div>
</div> </div>
</div> </div>
</> </div>
) )
} }

View File

@@ -1,11 +1,8 @@
@import "../../../../styles/utilities"; @import "../../../../styles/utilities";
.menuSortWrapper{
@apply spacing-horizontal;
.menuSortWrapper{
.menuSortHeading{ .menuSortHeading{
@apply sub-headline font-bold ; @apply heading-3 font-heading;
color: var(--text-active);
font-feature-settings: 'salt' on;
margin: 0.8rem 0; margin: 0.8rem 0;
} }
.menuSortList{ .menuSortList{

View File

@@ -5,8 +5,8 @@ import useSWR from 'swr';
const useGetAllCollection = () => { const useGetAllCollection = () => {
const { data, ...rest } = useSWR<GetCollectionsQuery>([getCollectionsNameQuery], gglFetcher) const { data, isValidating, ...rest } = useSWR<GetCollectionsQuery>([getCollectionsNameQuery], gglFetcher)
return { collections: data?.collections, ...rest } return { collections: data?.collections.items || [], loading: isValidating, ...rest }
} }
export default useGetAllCollection; export default useGetAllCollection;

View File

@@ -5,7 +5,7 @@ import useSWR from 'swr'
const useFacets = (options?: QueryFacetsArgs) => { const useFacets = (options?: QueryFacetsArgs) => {
const { data, isValidating, ...rest } = useSWR<GetAllFacetsQuery>([getAllFacetsQuery, options], gglFetcher) const { data, isValidating, ...rest } = useSWR<GetAllFacetsQuery>([getAllFacetsQuery, options], gglFetcher)
return { items: data?.facets.items, totalItems: data?.facets.totalItems, loading: isValidating, ...rest } return { facets: data?.facets.items, totalItems: data?.facets.totalItems, loading: isValidating, ...rest }
} }
export default useFacets export default useFacets