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/test.tsx b/pages/test.tsx index 403bc7b9d..f9296f786 100644 --- a/pages/test.tsx +++ b/pages/test.tsx @@ -1,103 +1,7 @@ -import { useState } from 'react' import { - ButtonCommon, - Layout, - ModalCommon, - ProductCarousel, - RelevantBlogPosts, - CollapseCommon, + CollapseCommon, Layout, RelevantBlogPosts } from 'src/components/common' -import { CollectionCarcousel } from 'src/components/modules/home' -import image5 from '../public/assets/images/image5.png' -import image6 from '../public/assets/images/image6.png' -import image7 from '../public/assets/images/image7.png' -import image8 from '../public/assets/images/image8.png' -const dataTest = [ - { - name: 'Tomato', - weight: '250g', - category: 'VEGGIE', - price: 'Rp 27.500', - imageSrc: image5.src, - }, - { - name: 'Cucumber', - weight: '250g', - category: 'VEGGIE', - price: 'Rp 27.500', - imageSrc: image6.src, - }, - { - name: 'Carrot', - weight: '250g', - category: 'VEGGIE', - price: 'Rp 27.500', - imageSrc: image7.src, - }, - { - name: 'Salad', - weight: '250g', - category: 'VEGGIE', - price: 'Rp 27.500', - imageSrc: image8.src, - }, - { - name: 'Tomato', - weight: '250g', - category: 'VEGGIE', - price: 'Rp 27.500', - imageSrc: image5.src, - }, - { - name: 'Cucumber', - weight: '250g', - category: 'VEGGIE', - price: 'Rp 27.500', - imageSrc: image6.src, - }, - { - name: 'Tomato', - weight: '250g', - category: 'VEGGIE', - price: 'Rp 27.500', - imageSrc: image5.src, - }, - { - name: 'Cucumber', - weight: '250g', - category: 'VEGGIE', - price: 'Rp 27.500', - imageSrc: image6.src, - }, - { - name: 'Carrot', - weight: '250g', - category: 'VEGGIE', - price: 'Rp 27.500', - imageSrc: image7.src, - }, - { - name: 'Salad', - weight: '250g', - category: 'VEGGIE', - price: 'Rp 27.500', - imageSrc: image8.src, - }, - { - name: 'Tomato', - weight: '250g', - category: 'VEGGIE', - price: 'Rp 27.500', - imageSrc: image5.src, - }, - { - name: 'Cucumber', - weight: '250g', - category: 'VEGGIE', - price: 'Rp 27.500', - imageSrc: image6.src, - }, -] + const COLLAPSE_DATA = [ { title: "This is a subtitle", 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/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}

+ +
+ ) +} + +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/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..d0df5efe7 100644 --- a/src/components/common/PaginationCommon/PaginationCommon.tsx +++ b/src/components/common/PaginationCommon/PaginationCommon.tsx @@ -1,15 +1,74 @@ -import React from 'react' - +import classNames from 'classnames' +import React, { useEffect, useState } from 'react' +import { ArrowLeftSmall, ArrowRightSmall } from 'src/components/icons' +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, + 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/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/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/utils/constanst.utils.ts b/src/utils/constanst.utils.ts index a2ccb73f4..0e901ff04 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,4 @@ export const KEY = { ENTER: 'Enter', } +export const OPTION_ALL = 'all'; \ No newline at end of file diff --git a/src/utils/demo-data.ts b/src/utils/demo-data.ts index 64c8128ae..97222b2e9 100644 --- a/src/utils/demo-data.ts +++ b/src/utils/demo-data.ts @@ -1,3 +1,47 @@ +<<<<<<< HEAD +export const RECIPE_DATA_TEST= [ + { + id: '1', + title: "Special Recipe of Vietnamese Phở", + description: "Alright, before we get to the actual recipe, let’s chat for a sec about the ingredients. To make this pho soup recipe, you will need:", + image: 'https://user-images.githubusercontent.com/76729908/132159257-f92574c7-d00d-4142-8ea7-0ca9515fb737.png', + link:'#' + }, + { + id: '2', + title: "Original Recipe of Curry", + description: "Chicken curry is common to several countries including India, countries in Asia and the Caribbean. My favorite of them though is this aromatic Indian...", + image: 'https://user-images.githubusercontent.com/76729908/132159259-ae4c986d-ab53-4758-9137-d06bafdd15d0.png', + link:'#' + }, + { + id: '3', + title: "The Best Recipe of Beef Noodle Soup", + description: "The broth for Bun Bo Hue is prepared by slowly simmering various types of beef and pork bones (ox tail, beef shank, pork neck bones, pork feet,...", + image: 'https://user-images.githubusercontent.com/76729908/132159262-f28a9fb9-4852-47e6-80b5-d600521b548a.png', + link:'#' + }, + { + id: '4', + title: "Special Recipe of Vietnamese Phở", + description: "Alright, before we get to the actual recipe, let’s chat for a sec about the ingredients. To make this pho soup recipe, you will need:", + image: 'https://user-images.githubusercontent.com/76729908/132159257-f92574c7-d00d-4142-8ea7-0ca9515fb737.png', + link:'#' + }, + { + id: '5', + title: "Original Recipe of Curry", + description: "Chicken curry is common to several countries including India, countries in Asia and the Caribbean. My favorite of them though is this aromatic Indian...", + image: 'https://user-images.githubusercontent.com/76729908/132159259-ae4c986d-ab53-4758-9137-d06bafdd15d0.png', + link:'#' + }, + { + id: '6', + title: "The Best Recipe of Beef Noodle Soup", + description: "The broth for Bun Bo Hue is prepared by slowly simmering various types of beef and pork bones (ox tail, beef shank, pork neck bones, pork feet,...", + image: 'https://user-images.githubusercontent.com/76729908/132159262-f28a9fb9-4852-47e6-80b5-d600521b548a.png', + link:'#' +======= import { RecipeCardProps } from "src/components/common/RecipeCard/RecipeCard" export const PRODUCT_DATA_TEST = [ @@ -211,5 +255,6 @@ export const RECIPE_DATA_TEST: RecipeCardProps[] = [ title: "The Best Recipe of Beef Noodle Soup", description: "The broth for Bun Bo Hue is prepared by slowly simmering various types of beef and pork bones (ox tail, beef shank, pork neck bones, pork feet,...", imageSrc: 'https://user-images.githubusercontent.com/76729908/132159262-f28a9fb9-4852-47e6-80b5-d600521b548a.png' +>>>>>>> a9f9f06eb9dee2a1ddefe907ff804237a78c5210 }, ] \ 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', },