diff --git a/package.json b/package.json index 91a529d52..57df2ec3b 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,8 @@ "classnames": "^2.3.1", "cookie": "^0.4.1", "email-validator": "^2.0.4", + "eslint": "^7.32.0", + "eslint-config-next": "^11.1.2", "immutability-helper": "^3.1.1", "js-cookie": "^2.2.1", "keen-slider": "^5.5.1", @@ -66,6 +68,7 @@ "@types/node": "^15.12.4", "@types/react": "^17.0.8", "deepmerge": "^4.2.2", + "eslint-config-prettier": "^8.3.0", "graphql": "^15.5.1", "husky": "^6.0.0", "lint-staged": "^11.0.0", diff --git a/pages/index.tsx b/pages/index.tsx index a71748373..7d23ebadd 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -4,7 +4,7 @@ import { HomeBanner, HomeCategories, HomeCollection, HomeCTA, HomeFeature, HomeR export default function Home() { return ( <> - + @@ -12,6 +12,9 @@ export default function Home() { + + {/* // todo: uncomment */} + {/* */} ) } diff --git a/pages/test.tsx b/pages/test.tsx index c21f4cd6c..42dced539 100644 --- a/pages/test.tsx +++ b/pages/test.tsx @@ -1,14 +1,44 @@ -import { useState } from 'react' import { - Layout + CollapseCommon, Layout, RelevantBlogPosts } from 'src/components/common' -import { DeliveryAndPolicyPage } from 'src/components/modules/delivery-policy' - +const COLLAPSE_DATA = [ + { + title: "This is a subtitle", + content: [ + "When you’re trying to eat healthier but want something more substantial than a leafy green salad, broccoli salad is there for you. I love the crunch and heft of broccoli, especially when it’s cut up into bite size spoonable pieces.", + "Some people aren’t into raw broccoli, but I love it! I always go for the raw broccoli on those vegetable platters that seem to be at every potluck/party you go to.", + "This is a simple broccoli salad: you have the bulk of it, raw broccoli; crunchy red onions for a bit of acidity and raw crunch, craisins for sweetness, almonds for a nutty counter point; and a sweet and tangy soy-rice vinegar-sesame dressing.", + ], + }, + { + title: "This is a subtitle", + content: [ + "When you’re trying to eat healthier but want something more substantial than a leafy green salad, broccoli salad is there for you. I love the crunch and heft of broccoli, especially when it’s cut up into bite size spoonable pieces.", + "Some people aren’t into raw broccoli, but I love it! I always go for the raw broccoli on those vegetable platters that seem to be at every potluck/party you go to.", + "This is a simple broccoli salad: you have the bulk of it, raw broccoli; crunchy red onions for a bit of acidity and raw crunch, craisins for sweetness, almonds for a nutty counter point; and a sweet and tangy soy-rice vinegar-sesame dressing.", + ], + }, + { + title: "This is a subtitle", + content: [ + "When you’re trying to eat healthier but want something more substantial than a leafy green salad, broccoli salad is there for you. I love the crunch and heft of broccoli, especially when it’s cut up into bite size spoonable pieces.", + "Some people aren’t into raw broccoli, but I love it! I always go for the raw broccoli on those vegetable platters that seem to be at every potluck/party you go to.", + "This is a simple broccoli salad: you have the bulk of it, raw broccoli; crunchy red onions for a bit of acidity and raw crunch, craisins for sweetness, almonds for a nutty counter point; and a sweet and tangy soy-rice vinegar-sesame dressing.", + ], + }, + { + title: "This is a subtitle", + content: [ + "When you’re trying to eat healthier but want something more substantial than a leafy green salad, broccoli salad is there for you. I love the crunch and heft of broccoli, especially when it’s cut up into bite size spoonable pieces.", + "Some people aren’t into raw broccoli, but I love it! I always go for the raw broccoli on those vegetable platters that seem to be at every potluck/party you go to.", + "This is a simple broccoli salad: you have the bulk of it, raw broccoli; crunchy red onions for a bit of acidity and raw crunch, craisins for sweetness, almonds for a nutty counter point; and a sweet and tangy soy-rice vinegar-sesame dressing.", + ], + }, +] export default function Test() { return ( <> - ) } diff --git a/public/assets/bannerrecipes.png b/public/assets/bannerrecipes.png new file mode 100644 index 000000000..91271cbd2 Binary files /dev/null and b/public/assets/bannerrecipes.png differ diff --git a/public/bg-products.svg b/public/bg-products.svg index 2118c3277..1eaa1df8b 100644 --- a/public/bg-products.svg +++ b/public/bg-products.svg @@ -1,7 +1,7 @@ - - - - + + + + diff --git a/src/components/common/BreadcrumbCommon/BreadcrumbCommon.module.scss b/src/components/common/BreadcrumbCommon/BreadcrumbCommon.module.scss index 8f6c05bf7..95c8526e1 100644 --- a/src/components/common/BreadcrumbCommon/BreadcrumbCommon.module.scss +++ b/src/components/common/BreadcrumbCommon/BreadcrumbCommon.module.scss @@ -2,7 +2,10 @@ .breadcrumbCommon { color: var(--text-base); +<<<<<<< HEAD +======= .currentItem { cursor: default; } +>>>>>>> a9f9f06eb9dee2a1ddefe907ff804237a78c5210 } diff --git a/src/components/common/CardBlog/CardBlog.tsx b/src/components/common/CardBlog/CardBlog.tsx index 17a796bc4..314a6a1fd 100644 --- a/src/components/common/CardBlog/CardBlog.tsx +++ b/src/components/common/CardBlog/CardBlog.tsx @@ -1,21 +1,27 @@ import Link from 'next/link' import React from 'react' -import { RecipeProps } from 'src/utils/types.utils' +import { ROUTE } from 'src/utils/constanst.utils' +import { BlogProps } from 'src/utils/types.utils' import s from './CardBlog.module.scss' -export interface BlogCardProps extends RecipeProps { - link: string, +export interface BlogCardProps extends BlogProps { + // todo: edit when intergrate API + } -const CardBlog = ({ imageSrc, title, description, link }: BlogCardProps) => { +const CardBlog = ({ imageSrc, title, description, slug }: BlogCardProps) => { return (
- -
- image cardblog -
+ + +
+ image cardblog +
+
- -
{title}
+ + +
{title}
+
{description}
diff --git a/src/components/common/CollapseCommon/CollapseChild/CollapseChild.tsx b/src/components/common/CollapseCommon/CollapseChild/CollapseChild.tsx index 397b0dcda..408b0c397 100644 --- a/src/components/common/CollapseCommon/CollapseChild/CollapseChild.tsx +++ b/src/components/common/CollapseCommon/CollapseChild/CollapseChild.tsx @@ -1,15 +1,13 @@ import s from './CollapseChild.module.scss' import { useState } from 'react' import classNames from 'classnames' -import Link from 'next/link' interface CollapseProps{ title?: string, content: string, isToggle?: boolean, - link?: string, } -const CollapseChild = ({title, content, isToggle=false, link="/"}: CollapseProps) => { +const CollapseChild = ({title, content, isToggle=false}: CollapseProps) => { const [isActive, changeActive] = useState(isToggle) const handleToggle = () => { @@ -23,9 +21,7 @@ const CollapseChild = ({title, content, isToggle=false, link="/"}: CollapseProps onClick = { handleToggle } >
- - {title} - +

{title}

diff --git a/src/components/common/Header/components/HeaderMenu/HeaderMenu.module.scss b/src/components/common/Header/components/HeaderMenu/HeaderMenu.module.scss index 2832211c1..eaaabca70 100644 --- a/src/components/common/Header/components/HeaderMenu/HeaderMenu.module.scss +++ b/src/components/common/Header/components/HeaderMenu/HeaderMenu.module.scss @@ -42,7 +42,7 @@ @apply hidden; @screen md { @apply flex items-center list-none; - li { + > li { @apply flex justify-center items-center w-full; &:not(:last-child) { margin-right: 4.8rem; @@ -53,7 +53,7 @@ a { @appy no-underline; &:hover { - opacity: .8; + opacity: 0.8; } &.iconFavourite { svg path { @@ -61,7 +61,14 @@ } } } - + .btnCart { + &:hover { + svg path { + fill: var(--primary); + opacity: 0.8; + } + } + } } } } diff --git a/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx b/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx index aa962605d..05e0b38fa 100644 --- a/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx +++ b/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx @@ -68,7 +68,7 @@ const HeaderMenu = memo(({ isFull, openModalAuthen, openModalInfo }: Props) => {
  • -
  • diff --git a/src/components/common/Layout/Layout.tsx b/src/components/common/Layout/Layout.tsx index e52e70d3e..17f520185 100644 --- a/src/components/common/Layout/Layout.tsx +++ b/src/components/common/Layout/Layout.tsx @@ -29,6 +29,10 @@ const Layout: FC = ({ children }) => {
    {children}
    + +
    diff --git a/src/components/common/MenuDropdown/MenuDropdown.module.scss b/src/components/common/MenuDropdown/MenuDropdown.module.scss index ae5b76c3d..5332794ff 100644 --- a/src/components/common/MenuDropdown/MenuDropdown.module.scss +++ b/src/components/common/MenuDropdown/MenuDropdown.module.scss @@ -3,9 +3,6 @@ .menuDropdown { @apply relative cursor-pointer; width: fit-content; - .label { - all: unset; - } &:hover { .label { color: var(--primary); @@ -20,10 +17,21 @@ } .label { + all: unset; @apply flex justify-end items-center transition-all duration-200; svg path { width: fit-content; } + &:focus, + &:active { + color: var(--primary); + svg path { + fill: currentColor; + } + } + &:focus-visible { + outline: 2px solid #000; + } } &.arrow { @@ -66,18 +74,9 @@ @apply rounded list-none bg-white; border: 1px solid var(--text-active); margin-top: 0.4rem; - li { + > li { @apply block w-full transition-all duration-200 cursor-pointer text-active; - word-wrap: break-word; - -webkit-hyphens: auto; - -ms-hyphens: auto; - -moz-hyphens: auto; - hyphens: auto; - overflow-x: hidden; - position: relative; - max-width: 15rem; white-space: nowrap; - text-overflow: ellipsis; button { all: unset; color: currentColor; diff --git a/src/components/common/MenuFilter/MenuFilter.module.scss b/src/components/common/MenuFilter/MenuFilter.module.scss new file mode 100644 index 000000000..ecea2e119 --- /dev/null +++ b/src/components/common/MenuFilter/MenuFilter.module.scss @@ -0,0 +1,40 @@ +@import "../../../styles/utilities"; +.menuFilterWrapper{ + + @screen md { + @apply hidden; + } + .menuFilterHeading{ + @apply sub-headline font-bold ; + color: var(--text-active); + font-feature-settings: 'salt' on; + margin: 0.8rem 0; + } + .menuFilterList{ + @apply flex flex-wrap justify-start relative; + margin-bottom: 3rem; + box-sizing: border-box; + &::after{ + @apply absolute; + top: 110%; + content: ""; + width: 100%; + border-bottom: 1px solid var(--border-line); + } + + li{ + margin: 1rem 0; + padding:0; + div{ + padding: 0.8rem 1.6rem; + margin-right: 0.8rem; + background-color: var(--gray); + border-radius: 0.8rem; + &.active { + color:white; + background-color: var(--primary); + } + } + } + } +} diff --git a/src/components/common/MenuFilter/MenuFilter.tsx b/src/components/common/MenuFilter/MenuFilter.tsx new file mode 100644 index 000000000..454942734 --- /dev/null +++ b/src/components/common/MenuFilter/MenuFilter.tsx @@ -0,0 +1,48 @@ +import classNames from 'classnames' +import { useEffect, useState } from 'react'; + +import s from './MenuFilter.module.scss' +interface Props { + children?: any, + heading?:string, + categories:{name:string,link:string}[], + type:string, + onChangeValue?: (value: Object) => void +} + +const MenuFilter = ({heading,categories,type,onChangeValue}:Props)=> { + const [active, setActive] = useState(''); + + 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 ( +
    +

    {heading}

    +
      + { + categories.map(item =>
    • +
      handleClick(item.link)} className={classNames({ [s.active]: item.link === active? true: false })}> + {item.name} +
      +
    • ) + } +
    +
    + ) +} + +export default MenuFilter diff --git a/src/components/common/MenuNavigation/MenuNavigation.module.scss b/src/components/common/MenuNavigation/MenuNavigation.module.scss new file mode 100644 index 000000000..7535df707 --- /dev/null +++ b/src/components/common/MenuNavigation/MenuNavigation.module.scss @@ -0,0 +1,29 @@ +@import "../../../styles/utilities"; +.menuNavigationWrapper{ + .menuNavigationHeading{ + @screen md { + @apply sub-headline font-bold ; + color: var(--text-active); + font-feature-settings: 'salt' on; + margin: 1.6rem 0; + } + } + .menuNavigationList{ + @screen md { + li{ + margin: 0.8rem 0; + a{ + display:block; + width:100%; + color:var(--text-base); + &:hover { + @apply text-primary; + } + &.active { + @apply text-primary; + } + } + } + } + } +} diff --git a/src/components/common/MenuNavigation/MenuNavigation.tsx b/src/components/common/MenuNavigation/MenuNavigation.tsx new file mode 100644 index 000000000..4a8943051 --- /dev/null +++ b/src/components/common/MenuNavigation/MenuNavigation.tsx @@ -0,0 +1,34 @@ +import classNames from 'classnames' +import Link from 'next/link' +import { useRouter } from 'next/router' +import s from './MenuNavigation.module.scss' + +interface Props { + children?: any, + heading:string, + categories:{name:string,link:string}[] +} + +const MenuNavigation = ({heading,categories}:Props)=> { + const router = useRouter() + + return ( +
    +

    {heading}({categories.length})

    + +
    + ) +} + +export default MenuNavigation diff --git a/src/components/common/MenuNavigationProductList/MenuNavigationProductList.module.scss b/src/components/common/MenuNavigationProductList/MenuNavigationProductList.module.scss new file mode 100644 index 000000000..aa3f5e6c3 --- /dev/null +++ b/src/components/common/MenuNavigationProductList/MenuNavigationProductList.module.scss @@ -0,0 +1,45 @@ +@import "../../../styles/utilities"; +.menuNavigationProductListDesktop{ + @screen sm-only { + @apply hidden; + } +} +.menuNavigationProductListMobile{ + @apply hidden; + &.isShow{ + @apply block; + @screen md { + @apply hidden; + } + } + .menuNavigationProductModal{ + background: rgba(0, 0, 0, 0.5); + position: fixed; + left: 0; + top: 0; + width: 100%; + height: 100%; + z-index: 10000; + .content{ + @apply spacing-horizontal; + margin-top: 3rem; + padding-top: 2rem ; + padding-bottom: 5rem; + background-color: white; + overflow: auto; + height: 100%; + border-radius: 2.4rem 2.4rem 0 0; + .head{ + @apply flex justify-between; + h3{ + @apply heading-3 font-bold; + color:var(--text-base); + } + } + button{ + margin-top: 2rem; + width: 100%; + } + } + } +} \ No newline at end of file diff --git a/src/components/common/MenuNavigationProductList/MenuNavigationProductList.tsx b/src/components/common/MenuNavigationProductList/MenuNavigationProductList.tsx new file mode 100644 index 000000000..d9ac2aa26 --- /dev/null +++ b/src/components/common/MenuNavigationProductList/MenuNavigationProductList.tsx @@ -0,0 +1,60 @@ +import React, { useState } from 'react'; +import {ButtonCommon} from 'src/components/common'; +import s from './MenuNavigationProductList.module.scss'; +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{ + categories:{name:string,link:string}[], + brands:{name:string,link:string}[], + featured:{name:string,link:string}[], +} + +const MenuNavigationProductList = ({categories,brands,featured}:Props)=>{ + + const [dataSort,setDataSort] = useState({}); + const [isShow,setIsShow] = useState(true); + + function handleValue(value:Object){ + setDataSort({...dataSort,...value}); + } + function filter(){ + console.log(dataSort) + } + + function hideMenu(){ + if(isShow === true){ + setIsShow(false); + } + } + return( + <> +
    + + + +
    +
    +
    +
    +
    +

    FILTER

    +
    +
    + + + + + {LANGUAGE.BUTTON_LABEL.CONFIRM} +
    +
    +
    + + ) +} + +export default MenuNavigationProductList \ No newline at end of file diff --git a/src/components/common/MenuNavigationProductList/MenuSort/MenuSort.module.scss b/src/components/common/MenuNavigationProductList/MenuSort/MenuSort.module.scss new file mode 100644 index 000000000..a25752901 --- /dev/null +++ b/src/components/common/MenuNavigationProductList/MenuSort/MenuSort.module.scss @@ -0,0 +1,46 @@ +@import "../../../../styles/utilities"; +.menuSortWrapper{ + + @screen md { + @apply hidden; + } + .menuSortHeading{ + @apply sub-headline font-bold ; + color: var(--text-active); + font-feature-settings: 'salt' on; + margin: 0.8rem 0; + } + .menuSortList{ + box-sizing: border-box; + &::after{ + @apply absolute; + top: 110%; + content: ""; + width: 100%; + border-bottom: 1px solid var(--border-line); + } + li{ + div{ + height: 4.8rem; + line-height: 4.8rem; + padding: 0 1.6rem; + margin-right: 0.8rem; + border-radius: 0.8rem; + &.active { + @apply font-bold relative; + color:var(--text-active); + background-color: var(--primary-lightest); + &::after{ + @apply absolute; + content:""; + background-image: url('/assets/svg/check.svg'); + right: 1.6rem; + top: calc(50% - 24px/2); + width: 2.4rem; + height: 2.4rem; + } + } + } + } + } +} diff --git a/src/components/common/MenuNavigationProductList/MenuSort/MenuSort.tsx b/src/components/common/MenuNavigationProductList/MenuSort/MenuSort.tsx new file mode 100644 index 000000000..2e66dfc83 --- /dev/null +++ b/src/components/common/MenuNavigationProductList/MenuSort/MenuSort.tsx @@ -0,0 +1,67 @@ +import classNames from 'classnames'; +import { useEffect, useState } from 'react'; +import { QUERY_KEY, ROUTE } from 'src/utils/constanst.utils'; +import s from './MenuSort.module.scss'; + +interface Props { + children?: any, + heading:string, + type:string, + onChangeValue?: (value: Object) => void +} +const SORT = [ + { + name: 'By Name', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.SORTBY}=by-name`, + }, + { + name: 'Price(High to Low)', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.SORTBY}=high-to-low`, + }, + { + name: 'Price (Low to High)', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.SORTBY}=low-to-high`, + }, + { + name: 'On Sale', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.SORTBY}=on-sale`, + }, + ]; + + +const MenuSort = ({heading,type,onChangeValue}:Props)=> { + const [active, setActive] = useState(''); + + 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 ( +
    +

    {heading}

    +
      + { + SORT.map(item =>
    • +
      handleClick(item.link)} className={classNames({ [s.active]: item.link === active? true: false })}> + {item.name} +
      +
    • ) + } +
    +
    + ) +} + +export default MenuSort diff --git a/src/components/common/ModalAuthenticate/components/FormLogin/FormLogin.tsx b/src/components/common/ModalAuthenticate/components/FormLogin/FormLogin.tsx index bedb993f4..b1059a441 100644 --- a/src/components/common/ModalAuthenticate/components/FormLogin/FormLogin.tsx +++ b/src/components/common/ModalAuthenticate/components/FormLogin/FormLogin.tsx @@ -1,7 +1,6 @@ import Link from 'next/link' import React, { useEffect, useRef } from 'react' -import { ButtonCommon, Inputcommon } from 'src/components/common' -import InputPassword from 'src/components/common/InputPassword/InputPassword' +import { ButtonCommon, Inputcommon, InputPassword } from 'src/components/common' import { ROUTE } from 'src/utils/constanst.utils' import { CustomInputCommon } from 'src/utils/type.utils' import s from '../FormAuthen.module.scss' diff --git a/src/components/common/ModalAuthenticate/components/FormRegister/FormRegister.tsx b/src/components/common/ModalAuthenticate/components/FormRegister/FormRegister.tsx index d03dbc39e..66ec1f8a4 100644 --- a/src/components/common/ModalAuthenticate/components/FormRegister/FormRegister.tsx +++ b/src/components/common/ModalAuthenticate/components/FormRegister/FormRegister.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useRef } from 'react' -import { ButtonCommon, Inputcommon } from 'src/components/common' +import { ButtonCommon, Inputcommon, InputPassword } from 'src/components/common' import s from '../FormAuthen.module.scss' import styles from './FormRegister.module.scss' import SocialAuthen from '../SocialAuthen/SocialAuthen' diff --git a/src/components/common/PaginationCommon/PaginationCommon.module.scss b/src/components/common/PaginationCommon/PaginationCommon.module.scss index e69de29bb..6470cd72f 100644 --- a/src/components/common/PaginationCommon/PaginationCommon.module.scss +++ b/src/components/common/PaginationCommon/PaginationCommon.module.scss @@ -0,0 +1,22 @@ +.warpper{ + .item{ + @apply inline-flex items-center justify-center cursor-pointer; + background-color: var(--gray); + margin: 0 0.4rem; + width: 3.2rem; + height: 3.2rem; + &.active{ + @apply border border-solid; + border-color: var(--text-active); + background-color: var(--white); + } + &.disable{ + svg{ + path{ + fill: var(--disabled) + } + } + @apply text-disabled cursor-not-allowed; + } + } +} \ No newline at end of file diff --git a/src/components/common/PaginationCommon/PaginationCommon.tsx b/src/components/common/PaginationCommon/PaginationCommon.tsx index 59bbd3baa..aed2473f3 100644 --- a/src/components/common/PaginationCommon/PaginationCommon.tsx +++ b/src/components/common/PaginationCommon/PaginationCommon.tsx @@ -1,15 +1,75 @@ -import React from 'react' - +import classNames from 'classnames' +import React, { useEffect, useState } from 'react' +import { ArrowLeftSmall, ArrowRightSmall } from 'src/components/icons' +import { DEFAULT_PAGE_SIZE } from 'src/utils/constanst.utils' +import PaginationItem from './components/PaginationItem' +import s from './PaginationCommon.module.scss' interface PaginationCommonProps { - + defaultCurrent?: number + pageSize?: number + total: number + onChange?: (page: number, pageSize: number) => void } -const PaginationCommon = (props: PaginationCommonProps) => { - return ( -
    - -
    - ) +const PaginationCommon = ({ + total, + pageSize=DEFAULT_PAGE_SIZE, + defaultCurrent, + onChange, +}: PaginationCommonProps) => { + const [pageNum, setPageNum] = useState(0) + const [currentPage, setCurrentPage] = useState(0) + useEffect(() => { + setPageNum(Math.ceil(total / pageSize)) + }, [total, pageSize]) + + useEffect(() => { + if (defaultCurrent) { + setCurrentPage(defaultCurrent) + } + }, [defaultCurrent]) + + const onPageClick = (page: number) => { + setCurrentPage(page) + onChange && onChange(page, pageSize) + } + + const onPrevClick = () => { + setCurrentPage(currentPage - 1 < 0 ? 0 : currentPage - 1) + } + + const onNextClick = () => { + setCurrentPage((currentPage + 1) > (pageNum - 1) ? (pageNum - 1) : currentPage + 1) + } + + return ( +
    +
    + +
    + {[...Array(pageNum).keys()].map((index) => { + return ( + + ) + })} +
    = pageNum - 1, + })} + onClick={onNextClick} + > + = pageNum} /> +
    +
    + ) } export default PaginationCommon diff --git a/src/components/common/PaginationCommon/components/PaginationItem.tsx b/src/components/common/PaginationCommon/components/PaginationItem.tsx new file mode 100644 index 000000000..e5f526bc4 --- /dev/null +++ b/src/components/common/PaginationCommon/components/PaginationItem.tsx @@ -0,0 +1,21 @@ +import classNames from 'classnames' +import React from 'react' +import s from "../PaginationCommon.module.scss" +interface PaginationItemProps { + onClick:(page:number)=>void + page:number + active:boolean +} + +const PaginationItem = ({onClick, page, active}: PaginationItemProps) => { + const onPageClick = () => { + onClick && onClick(page) + } + return ( +
    + {page+1} +
    + ) +} + +export default PaginationItem diff --git a/src/components/common/ProductCard/ProductCard.module.scss b/src/components/common/ProductCard/ProductCard.module.scss index 73be21ab1..cffbe063b 100644 --- a/src/components/common/ProductCard/ProductCard.module.scss +++ b/src/components/common/ProductCard/ProductCard.module.scss @@ -59,7 +59,8 @@ .cardBot{ min-height: 4rem; @apply flex justify-between items-center; - .cardButton{ + .cardIcon{ + margin-right: 0.8rem; } } } \ No newline at end of file diff --git a/src/components/common/ProductList/ProductList.module.scss b/src/components/common/ProductList/ProductList.module.scss new file mode 100644 index 000000000..c49696ea5 --- /dev/null +++ b/src/components/common/ProductList/ProductList.module.scss @@ -0,0 +1,11 @@ +.wrapper{ + .list{ + // max-width: 109.4rem; + @apply flex flex-wrap justify-around; + } + .pagination{ + padding-top: 4.8rem; + // max-width: 109.4rem; + @apply flex justify-center items-center ; + } +} \ No newline at end of file diff --git a/src/components/common/ProductList/ProductList.tsx b/src/components/common/ProductList/ProductList.tsx new file mode 100644 index 000000000..7428e3a63 --- /dev/null +++ b/src/components/common/ProductList/ProductList.tsx @@ -0,0 +1,30 @@ +import React, { useState } from 'react' +import PaginationCommon from '../PaginationCommon/PaginationCommon' +import ProductCard, { ProductCardProps } from '../ProductCard/ProductCard' +import s from "./ProductList.module.scss" +interface ProductListProps { + data: ProductCardProps[] +} + +const ProductList = ({data}: ProductListProps) => { + const [currentPage, setCurrentPage] = useState(0) + const onPageChange = (page:number) => { + setCurrentPage(page) + } + return ( +
    +
    + { + data.slice(currentPage*20,(currentPage+1)*20).map((product,index)=>{ + return + }) + } +
    +
    + +
    +
    + ) +} + +export default ProductList diff --git a/src/components/common/RelevantBlogPosts/RelevantBlogPosts.module.scss b/src/components/common/RelevantBlogPosts/RelevantBlogPosts.module.scss index d5a13299d..ed232830f 100644 --- a/src/components/common/RelevantBlogPosts/RelevantBlogPosts.module.scss +++ b/src/components/common/RelevantBlogPosts/RelevantBlogPosts.module.scss @@ -1,6 +1,9 @@ @import '../../../styles/utilities'; .blogPostWarpper { + &.cream{ + background-color: #F5F4F2; + } padding-top: 5.6rem; padding-bottom: 5.2rem; @apply flex flex-col; diff --git a/src/components/common/RelevantBlogPosts/RelevantBlogPosts.tsx b/src/components/common/RelevantBlogPosts/RelevantBlogPosts.tsx index 01e19bb25..1d71a6ca1 100644 --- a/src/components/common/RelevantBlogPosts/RelevantBlogPosts.tsx +++ b/src/components/common/RelevantBlogPosts/RelevantBlogPosts.tsx @@ -1,6 +1,7 @@ import image15 from '../../../../public/assets/images/image15.png' import image16 from '../../../../public/assets/images/image16.png' import image17 from '../../../../public/assets/images/image17.png' +import classNames from 'classnames' import React from 'react' import { HeadingCommon, ViewAllItem } from 'src/components/common' import { BlogCardProps } from 'src/components/common/CardBlog/CardBlog' @@ -9,54 +10,59 @@ import s from './RelevantBlogPosts.module.scss' import { ROUTE } from 'src/utils/constanst.utils'; interface RelevantProps { - data?: BlogCardProps[] - itemKey?: string - title?: string - viewAllLink?: string + data?: BlogCardProps[], + itemKey?: string, + title?: string, + viewAllLink?: string, + bgcolor?: "default" | "cream" } const recipe:BlogCardProps[] = [ { title: "Want to Lose Weight? Here are 10 DEBM Diet Guidelines for Beginners", + slug: 'have-a-nice-lunch', description:"The DEBM diet stands for "+'"Delicious Happy Fun Diet"'+". This diet was popularized by Robert...", imageSrc: image15.src, - link: `${ROUTE.BLOG_DETAIL}` },{ title: "9 Ways to Make an Aloe Vera Mask at Home", + slug: 'have-a-nice-lunch', description:"Aloe vera or aloe vera is a green plant, has thorns on the side of the skin with yellowish patches and...", imageSrc: image16.src, - link: `${ROUTE.BLOG_DETAIL}` },{ title: "Don't Buy Wrong, Here Are 7 Ways to Choose a Ripe Dragon Fruit", + slug: 'have-a-nice-lunch', description:"Dragon fruit is a type of fruit that is a favorite for many people because of its delicious and fresh...", imageSrc: image17.src, - link: `${ROUTE.BLOG_DETAIL}` },{ title: "Want to Lose Weight? Here are 10 DEBM Diet Guidelines for Beginners", + slug: 'have-a-nice-lunch', description:"The DEBM diet stands for "+'"Delicious Happy Fun Diet"'+". This diet was popularized by Robert...", imageSrc: image15.src, - link: `${ROUTE.BLOG_DETAIL}` },{ title: "9 Ways to Make an Aloe Vera Mask at Home", + slug: 'have-a-nice-lunch', description:"Aloe vera or aloe vera is a green plant, has thorns on the side of the skin with yellowish patches and...", imageSrc: image16.src, - link: `${ROUTE.BLOG_DETAIL}` },{ title: "Don't Buy Wrong, Here Are 7 Ways to Choose a Ripe Dragon Fruit", + slug: 'have-a-nice-lunch', description:"Dragon fruit is a type of fruit that is a favorite for many people because of its delicious and fresh...", imageSrc: image17.src, - link: `${ROUTE.BLOG_DETAIL}` }] - const RelevantBlogPosts = ({ data = recipe, itemKey="detail-relevant", title="Relevant Blog Posts" }: RelevantProps) => { + const RelevantBlogPosts = ({ data = recipe, itemKey="detail-relevant", title="Relevant Blog Posts", bgcolor = "default" }: RelevantProps) => { return ( -
    +
    {title}
    - +
    diff --git a/src/components/common/SelectCommon/SelectCommon.module.scss b/src/components/common/SelectCommon/SelectCommon.module.scss index d91b1831e..4809a46bb 100644 --- a/src/components/common/SelectCommon/SelectCommon.module.scss +++ b/src/components/common/SelectCommon/SelectCommon.module.scss @@ -1,69 +1,90 @@ @import "../../../styles/utilities"; -.select{ +.select { background-color: var(--white); - &.base{ + .selectTrigger { + svg { + @apply transition-all duration-200; + } + } + &.base { width: 20.6rem; - .selectTrigger{ + .selectTrigger { width: 20.6rem; padding: 1.2rem 1.6rem; } } - &.large{ + &.large { width: 34.25rem; - .selectTrigger{ + .selectTrigger { width: 34.25rem; padding: 1.6rem 1.6rem; } } - &.default{ - .selectTrigger{ + &.default { + .selectTrigger { @apply border-solid border border-current; - } + } } - &.custom{ - .selectTrigger{ + &.custom { + .selectTrigger { @apply border-2; border-color: var(--border-line); color: var(--text-label); } } - &.isActive{ - .selectOptionWrapper{ + &:hover { + cursor: pointer; + .hoverWrapper { @apply block; + animation: SelectAnimation 0.2s ease-out; + } + .selectTrigger { + svg { + transform: rotate(180deg); + } } } } -.selectTrigger{ +.selectTrigger { @apply outline-none flex justify-between; color: var(--text-active); border-radius: 0.8rem; - } -.selectOptionWrapper{ - @apply outline-none hidden z-10 absolute; - border-radius: 0.8rem; - background-color: var(--white); - padding: 0.4rem 0rem 0.4rem 0rem; - margin-top: 0.6rem; - &.base{ - width: 20.6rem; +.hoverWrapper { + @apply hidden outline-none absolute z-10; + padding-top: 0.6rem; + .selectOptionWrapper { + border-radius: 0.8rem; + background-color: var(--white); + padding: 0.4rem 0rem 0.4rem 0rem; + &.base { + width: 20.6rem; + } + &.large { + width: 34.25rem; + } + &.default { + @apply border-solid border border-current; + } + &.custom { + @apply border-2; + border-color: var(--border-line); + color: var(--text-label); + } } - &.large{ - width: 34.25rem; - } - &.default{ - @apply border-solid border border-current; - } - &.custom{ - @apply border-2; - border-color: var(--border-line); - color: var(--text-label); - } - &.active{ - @apply hidden; + &:hover { + @apply block; } } - - +@keyframes SelectAnimation { + 0% { + opacity: 0; + transform: translateY(1.6rem); + } + 100% { + opacity: 1; + transform: none; + } +} diff --git a/src/components/common/SelectCommon/SelectCommon.tsx b/src/components/common/SelectCommon/SelectCommon.tsx index 5bb3d15d6..9b8c88e24 100644 --- a/src/components/common/SelectCommon/SelectCommon.tsx +++ b/src/components/common/SelectCommon/SelectCommon.tsx @@ -1,43 +1,25 @@ import s from './SelectCommon.module.scss' import classNames from 'classnames' -import { useState, useRef, useEffect } from 'react' +import { useState } from 'react' import { IconVectorDown } from 'src/components/icons' import SelectOption from './SelectOption/SelectOption' interface Props { - children? : React.ReactNode, + placeholder? : string, size?: 'base' | 'large', type?: 'default' | 'custom', - option: {name: string}[], + option: {name: string, value: string}[], + onChange?: (value: string) => void, } -const SelectCommon = ({ type = 'default', size = 'base', option, children }: Props) => { - const [isActive, setActive] = useState(false) - const [selectedName, setSelectedName] = useState(children) - const ref = useRef(null) - - useEffect(() => { - const handleClick = (event: MouseEvent) => { - const { target } = event; - if (!ref?.current || ref?.current.contains(target as Node)) { - return - } - else{ - setActive(false) - } - } - document.addEventListener('click', handleClick) - return () => { - document.removeEventListener('click', handleClick) - } - }, [ref]) +const SelectCommon = ({ type = 'default', size = 'base', option, placeholder, onChange}: Props) => { + const [selectedName, setSelectedName] = useState(placeholder) + const [selectedValue, setSelectedValue] = useState('') - const changeActiveStatus = () => { - setActive(!isActive) - } - - const changeSelectedName = (item:string) => { + const changeSelectedName = (item:string, value: string) => { + setSelectedValue(value) setSelectedName(item) + onChange && onChange(value) } return( <> @@ -45,29 +27,29 @@ const SelectCommon = ({ type = 'default', size = 'base', option, children }: Pro [s.select] : true, [s[size]] : !!size, [s[type]] : !!type, - [s.isActive] : isActive, })} - onClick = { changeActiveStatus } - ref = {ref} >
    {selectedName}
    - -
    - { - option.map(item => - - ) - } + +
    +
    + { + option.map(item => + + ) + } +
    +
    ) diff --git a/src/components/common/SelectCommon/SelectOption/SelectOption.module.scss b/src/components/common/SelectCommon/SelectOption/SelectOption.module.scss index 5448f9879..ef504c112 100644 --- a/src/components/common/SelectCommon/SelectOption/SelectOption.module.scss +++ b/src/components/common/SelectCommon/SelectOption/SelectOption.module.scss @@ -13,5 +13,9 @@ } &:hover{ background-color: var(--gray); + color: var(--primary); + } + &.isChoose{ + background-color: var(--gray); } } \ No newline at end of file diff --git a/src/components/common/SelectCommon/SelectOption/SelectOption.tsx b/src/components/common/SelectCommon/SelectOption/SelectOption.tsx index 54877d5fe..7e1968f9e 100644 --- a/src/components/common/SelectCommon/SelectOption/SelectOption.tsx +++ b/src/components/common/SelectCommon/SelectOption/SelectOption.tsx @@ -2,20 +2,22 @@ import s from './SelectOption.module.scss' import classNames from 'classnames' interface Props{ - onClick: (value: string) => void, + onClick: (name: string, value: string) => void, itemName: string, size: 'base' | 'large', + value: string, + selected?: boolean, } -const SelectOption = ({onClick, itemName, size}: Props) => { - +const SelectOption = ({onClick, itemName, size, value, selected} : Props) => { const changeName = () => { - onClick(itemName) + onClick(itemName, value) } return(
    {itemName}
    diff --git a/src/components/common/index.ts b/src/components/common/index.ts index d10f17f8c..e04566de9 100644 --- a/src/components/common/index.ts +++ b/src/components/common/index.ts @@ -30,6 +30,7 @@ export { default as SelectCommon} from './SelectCommon/SelectCommon' export { default as ModalCommon} from './ModalCommon/ModalCommon' export { default as ModalConfirm} from "./ModalConfirm/ModalConfirm" export { default as ModalInfo} from "./ModalInfo/ModalInfo" +export { default as ProductList} from "./ProductList/ProductList" export { default as ModalCreateUserInfo} from './ModalCreateUserInfo/ModalCreateUserInfo' export { default as CardBlog} from './CardBlog/CardBlog' export { default as RelevantBlogPosts} from './RelevantBlogPosts/RelevantBlogPosts' diff --git a/src/components/icons/ArrowLeftSmall.tsx b/src/components/icons/ArrowLeftSmall.tsx new file mode 100644 index 000000000..7bb82665d --- /dev/null +++ b/src/components/icons/ArrowLeftSmall.tsx @@ -0,0 +1,18 @@ +const ArrowLeft = ({ ...props }) => { + return ( + + + + ) +} + +export default ArrowLeft diff --git a/src/components/icons/ArrowRightSmall.tsx b/src/components/icons/ArrowRightSmall.tsx new file mode 100644 index 000000000..36b4cd589 --- /dev/null +++ b/src/components/icons/ArrowRightSmall.tsx @@ -0,0 +1,18 @@ +const ArrowRight = ({ ...props }) => { + return ( + + + + ) +} + +export default ArrowRight diff --git a/src/components/icons/IconArrowUp.tsx b/src/components/icons/IconArrowUp.tsx index 3eac6391b..1f518d612 100644 --- a/src/components/icons/IconArrowUp.tsx +++ b/src/components/icons/IconArrowUp.tsx @@ -2,7 +2,7 @@ const ArrowUp = () => { return ( - + ) } diff --git a/src/components/icons/IconHide.tsx b/src/components/icons/IconHide.tsx new file mode 100644 index 000000000..a977aff84 --- /dev/null +++ b/src/components/icons/IconHide.tsx @@ -0,0 +1,12 @@ +import React from 'react' + +const IconHide = () => { + return ( + + + + + ) +} + +export default IconHide diff --git a/src/components/icons/IconVectorDown.tsx b/src/components/icons/IconVectorDown.tsx index 019fc2806..0bb1cb8c1 100644 --- a/src/components/icons/IconVectorDown.tsx +++ b/src/components/icons/IconVectorDown.tsx @@ -1,5 +1,3 @@ - - const IconVectorDown = ({ ...props }) => { return ( div { + @apply w-full h-full custom-border-radius-lg; + } + img { + object-fit: cover; + } + } .text { @apply relative font-heading text-center; diff --git a/src/components/modules/home/HomeBanner/HomeBanner.tsx b/src/components/modules/home/HomeBanner/HomeBanner.tsx index 2a3a632fb..18432ec82 100644 --- a/src/components/modules/home/HomeBanner/HomeBanner.tsx +++ b/src/components/modules/home/HomeBanner/HomeBanner.tsx @@ -1,8 +1,9 @@ import React from 'react' import { Banner } from 'src/components/common' -import s from './HomeBanner.module.scss' import BannerImgRight from './assets/banner_full.png' -import BannerImgRight2 from './assets/banner_product.png' +import HomeBannerImg from './assets/home_banner.png' +import s from './HomeBanner.module.scss' +import Image from 'next/image' interface Props { className?: string @@ -13,6 +14,9 @@ const HomeBanner = ({ }: Props) => { return (
    +
    + +
    Freshness
    guaranteed
    @@ -28,10 +32,10 @@ const HomeBanner = ({ }: Props) => { { title: "Save 15% on your first order 2", subtitle: "Last call! Shop deep deals on 100+ bulk picks while you can.", - imgLink: BannerImgRight2.src, + imgLink: BannerImgRight.src, size: "small", } - ] + ] } />
    diff --git a/src/components/modules/home/HomeBanner/assets/banner_product.png b/src/components/modules/home/HomeBanner/assets/banner_product.png deleted file mode 100644 index 82f1b7fee..000000000 Binary files a/src/components/modules/home/HomeBanner/assets/banner_product.png and /dev/null differ diff --git a/src/components/modules/home/HomeVideo/assets/bg_left.svg b/src/components/modules/home/HomeVideo/assets/bg_left.svg index d730f777d..74b215ae0 100644 --- a/src/components/modules/home/HomeVideo/assets/bg_left.svg +++ b/src/components/modules/home/HomeVideo/assets/bg_left.svg @@ -1,19 +1,19 @@ - - + + - - + + - - + + diff --git a/src/components/modules/home/HomeVideo/assets/bg_right.svg b/src/components/modules/home/HomeVideo/assets/bg_right.svg index e89652a3a..346d14e31 100644 --- a/src/components/modules/home/HomeVideo/assets/bg_right.svg +++ b/src/components/modules/home/HomeVideo/assets/bg_right.svg @@ -1,21 +1,21 @@ - - + + - - + + - - + + diff --git a/src/styles/_utilities.scss b/src/styles/_utilities.scss index cc13ea3cf..6b919de76 100644 --- a/src/styles/_utilities.scss +++ b/src/styles/_utilities.scss @@ -149,6 +149,7 @@ .line { @apply flex justify-between items-center; > div { + flex: 1; &:not(:last-child) { margin-right: 1.6rem; } diff --git a/src/utils/constanst.utils.ts b/src/utils/constanst.utils.ts index a2ccb73f4..1522e477f 100644 --- a/src/utils/constanst.utils.ts +++ b/src/utils/constanst.utils.ts @@ -33,7 +33,9 @@ export const QUERY_KEY = { TAB: 'tab', CATEGORY: 'category', BRAND: 'brand', - FEATURED: 'feature' + FEATURED: 'feature', + SORTBY:'sortby', + RECIPES:'recipes' } export enum ProductFeature { @@ -47,3 +49,5 @@ export const KEY = { ENTER: 'Enter', } +export const OPTION_ALL = 'all'; +export const DEFAULT_PAGE_SIZE=20 \ No newline at end of file diff --git a/src/utils/language.utils.ts b/src/utils/language.utils.ts index 191215aaa..8b3d8f8d5 100644 --- a/src/utils/language.utils.ts +++ b/src/utils/language.utils.ts @@ -2,6 +2,7 @@ export const LANGUAGE = { BUTTON_LABEL: { BUY_NOW: 'Buy now', SHOP_NOW: 'Shop now', + CONFIRM:'Confirm', ADD_TO_CARD: 'Add to Cart', PREORDER: 'Pre-Order Now', }, diff --git a/src/utils/types.utils.ts b/src/utils/types.utils.ts index c87305f2b..d6f1b47ad 100644 --- a/src/utils/types.utils.ts +++ b/src/utils/types.utils.ts @@ -24,4 +24,11 @@ export interface RecipeProps { imageSrc: string } +export interface BlogProps { + title: string + slug: string + description: string + imageSrc: string +} + export type MouseAndTouchEvent = MouseEvent | TouchEvent \ No newline at end of file