diff --git a/grocery-vercel-commerce b/grocery-vercel-commerce deleted file mode 160000 index 3c7aa8e86..000000000 --- a/grocery-vercel-commerce +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3c7aa8e862bfd8d44719be44c6c0a31ab01524a3 diff --git a/pages/404.tsx b/pages/404.tsx index 38a01bcc4..7fb30b9de 100644 --- a/pages/404.tsx +++ b/pages/404.tsx @@ -1,25 +1,4 @@ -import type { GetStaticPropsContext } from 'next' -import commerce from '@lib/api/commerce' import { Layout } from '@components/common' - -export async function getStaticProps({ - preview, - locale, - locales, -}: GetStaticPropsContext) { - const config = { locale, locales } - const { pages } = await commerce.getAllPages({ config, preview }) - const { categories, brands } = await commerce.getSiteInfo({ config, preview }) - return { - props: { - pages, - categories, - brands, - }, - revalidate: 200, - } -} - export default function NotFound() { return (
diff --git a/pages/[...pages].tsx b/pages/[...pages].tsx deleted file mode 100644 index a8a24b3aa..000000000 --- a/pages/[...pages].tsx +++ /dev/null @@ -1,86 +0,0 @@ -import type { - GetStaticPathsContext, - GetStaticPropsContext, - InferGetStaticPropsType, -} from 'next' -import commerce from '@lib/api/commerce' -import { Text } from '@components/ui' -import { Layout } from '@components/common' -import getSlug from '@lib/get-slug' -import { missingLocaleInPages } from '@lib/usage-warns' -import type { Page } from '@commerce/types/page' -import { useRouter } from 'next/router' - -export async function getStaticProps({ - preview, - params, - locale, - locales, -}: GetStaticPropsContext<{ pages: string[] }>) { - const config = { locale, locales } - const pagesPromise = commerce.getAllPages({ config, preview }) - const siteInfoPromise = commerce.getSiteInfo({ config, preview }) - const { pages } = await pagesPromise - const { categories } = await siteInfoPromise - const path = params?.pages.join('/') - const slug = locale ? `${locale}/${path}` : path - const pageItem = pages.find((p: Page) => - p.url ? getSlug(p.url) === slug : false - ) - const data = - pageItem && - (await commerce.getPage({ - variables: { id: pageItem.id! }, - config, - preview, - })) - - const page = data?.page - - if (!page) { - // We throw to make sure this fails at build time as this is never expected to happen - throw new Error(`Page with slug '${slug}' not found`) - } - - return { - props: { pages, page, categories }, - revalidate: 60 * 60, // Every hour - } -} - -export async function getStaticPaths({ locales }: GetStaticPathsContext) { - const config = { locales } - const { pages }: { pages: Page[] } = await commerce.getAllPages({ config }) - const [invalidPaths, log] = missingLocaleInPages() - const paths = pages - .map((page) => page.url) - .filter((url) => { - if (!url || !locales) return url - // If there are locales, only include the pages that include one of the available locales - if (locales.includes(getSlug(url).split('/')[0])) return url - - invalidPaths.push(url) - }) - log() - - return { - paths, - fallback: 'blocking', - } -} - -export default function Pages({ - page, -}: InferGetStaticPropsType) { - const router = useRouter() - - return router.isFallback ? ( -

Loading...

// TODO (BC) Add Skeleton Views - ) : ( -
- {page?.body && } -
- ) -} - -Pages.Layout = Layout diff --git a/pages/cart.tsx b/pages/cart.tsx deleted file mode 100644 index b9659d21b..000000000 --- a/pages/cart.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import type { GetStaticPropsContext } from 'next' -import commerce from '@lib/api/commerce' -import { Layout } from '@components/common' -// import useCart from '@framework/cart/use-cart' -// import usePrice from '@framework/product/use-price' -// import { Button, Text } from '@components/ui' -// import { Bag, Cross, Check, MapPin, CreditCard } from '@components/icons' -// import { CartItem } from '@components/cart' - -export async function getStaticProps({ - preview, - locale, - locales, -}: GetStaticPropsContext) { - const config = { locale, locales } - const pagesPromise = commerce.getAllPages({ config, preview }) - const siteInfoPromise = commerce.getSiteInfo({ config, preview }) - const { pages } = await pagesPromise - const { categories } = await siteInfoPromise - return { - props: { pages, categories }, - } -} - -export default function Cart() { - // const error = null - // const success = null - // const { data, isLoading, isEmpty } = useCart() - - // const { price: subTotal } = usePrice( - // data && { - // amount: Number(data.subtotalPrice), - // currencyCode: data.currency.code, - // } - // ) - // const { price: total } = usePrice( - // data && { - // amount: Number(data.totalPrice), - // currencyCode: data.currency.code, - // } - // ) - - return ( -
- This is cart page -
- ) -} - -Cart.Layout = Layout diff --git a/pages/demo.tsx b/pages/demo.tsx new file mode 100644 index 000000000..f23c10583 --- /dev/null +++ b/pages/demo.tsx @@ -0,0 +1,17 @@ +import { Layout, RecipeDetail } from 'src/components/common'; +import { ProductInfoDetail, ViewedProducts, ReleventProducts, RecommendedRecipes } from 'src/components/modules/product-detail'; +import { INGREDIENT_DATA_TEST, RECIPE_DATA_TEST } from 'src/utils/demo-data'; + + + +export default function Demo() { + return <> + + + + + + +} + +Demo.Layout = Layout diff --git a/pages/index.tsx b/pages/index.tsx index 1d3072ef7..daabf0cf1 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,18 +1,36 @@ +import { Layout } from 'src/components/common'; +import { HomeBanner, HomeCategories, HomeCollection, HomeCTA, HomeFeature, HomeRecipe, HomeSubscribe, HomeVideo } from 'src/components/modules/home'; +import {SelectCommon} from 'src/components/common' -import { Layout } from 'src/components/common' -import { HomeBanner, HomeCollection, HomeCTA, HomeSubscribe, HomeVideo, HomeCategories, HomeFeature, HomeRecipe } from 'src/components/modules/home'; +const OPTION_SORT = [ + { + name: "By Name" + }, + { + name: "Price (High to Low)" + }, + { + name: "On Sale" + } +] export default function Home() { return ( <> - + {/* + - + */} + Sort By + Sort By + + {/* // todo: uncomment */} + {/* */} ) } diff --git a/pages/product/[slug].tsx b/pages/product/[slug].tsx index c5bcbdba1..c34394af5 100644 --- a/pages/product/[slug].tsx +++ b/pages/product/[slug].tsx @@ -1,76 +1,16 @@ -import { Layout } from '@components/common' -import commerce from '@lib/api/commerce' -import type { - GetStaticPathsContext, - GetStaticPropsContext, - InferGetStaticPropsType -} from 'next' -import { useRouter } from 'next/router' -export async function getStaticProps({ - params, - locale, - locales, - preview, -}: GetStaticPropsContext<{ slug: string }>) { - const config = { locale, locales } - const pagesPromise = commerce.getAllPages({ config, preview }) - const siteInfoPromise = commerce.getSiteInfo({ config, preview }) - const productPromise = commerce.getProduct({ - variables: { slug: params!.slug }, - config, - preview, - }) +import { Layout, RecipeDetail } from 'src/components/common' +import { ProductInfoDetail, RecommendedRecipes, ReleventProducts, ViewedProducts } from 'src/components/modules/product-detail' +import { INGREDIENT_DATA_TEST, RECIPE_DATA_TEST } from 'src/utils/demo-data' - const allProductsPromise = commerce.getAllProducts({ - variables: { first: 4 }, - config, - preview, - }) - const { pages } = await pagesPromise - const { categories } = await siteInfoPromise - const { product } = await productPromise - const { products: relatedProducts } = await allProductsPromise - - if (!product) { - throw new Error(`Product with slug '${params!.slug}' not found`) - } - - return { - props: { - pages, - product, - relatedProducts, - categories, - }, - revalidate: 200, - } -} - -export async function getStaticPaths({ locales }: GetStaticPathsContext) { - const { products } = await commerce.getAllProductPaths() - - return { - paths: locales - ? locales.reduce((arr, locale) => { - // Add a product path for every locale - products.forEach((product: any) => { - arr.push(`/${locale}/product${product.path}`) - }) - return arr - }, []) - : products.map((product: any) => `/product${product.path}`), - fallback: 'blocking', - } -} - -export default function Slug({ - product, - relatedProducts, -}: InferGetStaticPropsType) { - const router = useRouter() - - return
This is product page
+export default function Slug() { + return <> + + + + + + } Slug.Layout = Layout diff --git a/pages/test.tsx b/pages/test.tsx index 90a46681f..970588581 100644 --- a/pages/test.tsx +++ b/pages/test.tsx @@ -1,117 +1,8 @@ import { useState } from 'react' import { ButtonCommon, - Layout, - ModalCommon, - ProductCarousel, + Layout, ModalInfo } from 'src/components/common' -import BreadcrumbCommon from 'src/components/common/BreadcrumbCommon/BreadcrumbCommon' -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 crumbs = [ - { - name: 'Product', - link: '/product', - }, - { - name: 'Detail', - link: '/detail', - }, - { - name: 'more', - link: '/more', - } -] export default function Test() { const [visible, setVisible] = useState(false) const onClose = () => { @@ -122,43 +13,10 @@ export default function Test() { } return ( <> - Lorem ipsum, dolor sit amet consectetur adipisicing elit. Natus tenetur repudiandae assumenda iste enim! Hic voluptas minus quos ipsa reprehenderit. - - - Lorem ipsum, dolor sit amet consectetur adipisicing elit. Natus tenetur repudiandae assumenda iste enim! Hic voluptas minus quos ipsa reprehenderit. open - -
- Lorem ipsum dolor sit amet consectetur adipisicing elit. Consectetur - officiis dolorum ea incidunt. Sint, cum ullam. Labore vero quod - itaque, officia magni molestias! Architecto deserunt soluta laborum - commodi nesciunt delectus similique temporibus distinctio? Facere - eaque minima enim modi magni, laudantium, animi mollitia beatae - repudiandae maxime labore error nesciunt, nisi est? -
-
- + + Lorem, ipsum dolor sit amet consectetur adipisicing elit. Nisi qui, esse eos nobis soluta suscipit aliquid nostrum corporis. Nihil eligendi similique recusandae minus mollitia aliquam, molestias fugit tenetur voluptatibus maiores et. Quaerat labore corporis inventore nostrum, amet autem exercitationem eligendi? + ) } diff --git a/src/components/common/Banner/Banner.module.scss b/src/components/common/Banner/Banner.module.scss index f4b374dd0..e69de29bb 100644 --- a/src/components/common/Banner/Banner.module.scss +++ b/src/components/common/Banner/Banner.module.scss @@ -1,52 +0,0 @@ -@import "../../../styles/utilities"; - -.banner { - @apply bg-primary-light custom-border-radius-lg overflow-hidden; - @screen md { - border: 1px solid var(--primary); - } - &.large { - margin-bottom: 2.8rem; - .inner { - @screen xl { - @apply bg-right-bottom; - background-size: unset; - } - } - } - .inner { - @apply bg-no-repeat; - background-size: 90%; - background-position: right -500% bottom 0%; - .content { - background-image: linear-gradient( - to right, - rgb(227, 242, 233, 0.9), - rgb(227, 242, 233, 0.5) 80%, - rgb(227, 242, 233, 0) - ); - padding: 1.6rem; - max-width: 37rem; - @screen md { - max-width: 49.6rem; - padding: 4.8rem; - } - .top { - .heading { - @apply heading-1 font-heading; - margin-bottom: 1.6rem; - } - .subHeading { - @apply sub-headline; - @screen md { - @apply caption; - } - } - } - - .bottom { - margin-top: 4rem; - } - } - } -} diff --git a/src/components/common/Banner/Banner.tsx b/src/components/common/Banner/Banner.tsx index a953052b6..1dbc04d9f 100644 --- a/src/components/common/Banner/Banner.tsx +++ b/src/components/common/Banner/Banner.tsx @@ -1,47 +1,24 @@ -import classNames from 'classnames' -import Link from 'next/link' import React, { memo } from 'react' -import { IconArrowRight } from 'src/components/icons' -import { ROUTE } from 'src/utils/constanst.utils' -import { LANGUAGE } from 'src/utils/language.utils' -import ButtonCommon from '../ButtonCommon/ButtonCommon' -import s from './Banner.module.scss' +import CarouselCommon from '../CarouselCommon/CarouselCommon' +import BannerItem, { BannerItemProps } from './BannerItem/BannerItem' interface Props { - imgLink: string, - title: string, - subtitle: string, - buttonLabel?: string, - linkButton?: string, - size?: 'small' | 'large', + data: BannerItemProps[], } -const Banner = memo(({ imgLink, title, subtitle, buttonLabel = LANGUAGE.BUTTON_LABEL.SHOP_NOW, linkButton = ROUTE.HOME, size = 'large' }: Props) => { +const option = { + slidesPerView: 1, + breakpoints: {} +} +const Banner = memo(({ data }: Props) => { return ( -
-
-
-
-

- {title} -

-
- {subtitle} -
-
- -
-
-
+ + data={data} + itemKey="banner" + Component={BannerItem} + option={option} + isDot = {true} + /> ) }) diff --git a/src/components/common/Banner/BannerItem/BannerItem.module.scss b/src/components/common/Banner/BannerItem/BannerItem.module.scss new file mode 100644 index 000000000..72690f92d --- /dev/null +++ b/src/components/common/Banner/BannerItem/BannerItem.module.scss @@ -0,0 +1,52 @@ +@import "../../../../styles/utilities"; + +.bannerItem { + @apply bg-primary-light custom-border-radius-lg overflow-hidden; + @screen md { + border: 1px solid var(--primary); + } + &.large { + margin-bottom: 2.8rem; + .inner { + @screen xl { + @apply bg-right-bottom; + background-size: unset; + } + } + } + .inner { + @apply bg-no-repeat; + background-size: 90%; + background-position: right -500% bottom 0%; + .content { + background-image: linear-gradient( + to right, + rgb(227, 242, 233, 0.9), + rgb(227, 242, 233, 0.5) 80%, + rgb(227, 242, 233, 0) + ); + padding: 1.6rem; + max-width: 37rem; + @screen md { + max-width: 49.6rem; + padding: 4.8rem; + } + .top { + .heading { + @apply heading-1 font-heading; + margin-bottom: 1.6rem; + } + .subHeading { + @apply sub-headline; + @screen md { + @apply caption; + } + } + } + + .bottom { + margin-top: 4rem; + } + } + } +} diff --git a/src/components/common/Banner/BannerItem/BannerItem.tsx b/src/components/common/Banner/BannerItem/BannerItem.tsx new file mode 100644 index 000000000..c7516d362 --- /dev/null +++ b/src/components/common/Banner/BannerItem/BannerItem.tsx @@ -0,0 +1,48 @@ +import classNames from 'classnames' +import Link from 'next/link' +import React, { memo } from 'react' +import { IconArrowRight } from 'src/components/icons' +import { ROUTE } from 'src/utils/constanst.utils' +import { LANGUAGE } from 'src/utils/language.utils' +import ButtonCommon from '../../ButtonCommon/ButtonCommon' +import s from './BannerItem.module.scss' + +export interface BannerItemProps { + imgLink: string, + title: string, + subtitle: string, + buttonLabel?: string, + linkButton?: string, + size?: 'small' | 'large', +} + +const BannerItem = memo(({ imgLink, title, subtitle, buttonLabel = LANGUAGE.BUTTON_LABEL.SHOP_NOW, linkButton = ROUTE.HOME, size = 'large' }: BannerItemProps) => { + return ( +
+
+
+
+

+ {title} +

+
+ {subtitle} +
+
+ +
+
+
+ ) +}) + +export default BannerItem diff --git a/src/components/common/ButtonCommon/ButtonCommon.module.scss b/src/components/common/ButtonCommon/ButtonCommon.module.scss index 4cfe737de..c7b9f1ffa 100644 --- a/src/components/common/ButtonCommon/ButtonCommon.module.scss +++ b/src/components/common/ButtonCommon/ButtonCommon.module.scss @@ -7,6 +7,9 @@ align-items: center; padding: 1rem 2rem; @screen md { + padding: 0.8rem 1.6rem; + } + @screen lg { padding: 0.8rem 3.2rem; } &:disabled { @@ -84,11 +87,14 @@ padding: 1rem; } @screen md { - padding: 1.6rem 4.8rem; + padding: 1.6rem 3.2rem; &.onlyIcon { padding: 1.6rem; } } + @screen lg { + padding: 1.6rem 4.8rem; + } &.loading { &::before { width: 2.4rem; diff --git a/src/components/common/CarouselCommon/CarouselCommon.module.scss b/src/components/common/CarouselCommon/CarouselCommon.module.scss index 802c25bb0..da306f38f 100644 --- a/src/components/common/CarouselCommon/CarouselCommon.module.scss +++ b/src/components/common/CarouselCommon/CarouselCommon.module.scss @@ -13,10 +13,16 @@ } @apply absolute top-1/2 bg-background-arrow transform -translate-y-1/2 flex justify-center items-center transition duration-100; &:global(.leftArrow) { - @apply left-0; + @apply hidden left-0; + @screen md { + @apply flex + } } &:global(.rightArrow) { - @apply right-0; + @apply hidden right-0; + @screen md { + @apply flex; + } } &:global(.isDisabledArrow) { @apply hidden; diff --git a/src/components/common/CarouselCommon/CustomArrow/CustomCarouselArrow.module.scss b/src/components/common/CarouselCommon/CustomArrow/CustomCarouselArrow.module.scss index fb174c66c..139597f9c 100644 --- a/src/components/common/CarouselCommon/CustomArrow/CustomCarouselArrow.module.scss +++ b/src/components/common/CarouselCommon/CustomArrow/CustomCarouselArrow.module.scss @@ -1,20 +1,2 @@ -.navigationWrapper{ - :global(.customArrow) { - width: 64px; - height: 64px; - &:focus{ - outline: none; - } - @apply absolute top-1/2 bg-background-arrow transform -translate-y-1/2 flex justify-center items-center transition duration-100; - &.leftArrow{ - @apply left-0; - } - &.rightArrow{ - @apply right-0; - } - &.isDisabled{ - @apply hidden ; - } - } -} + diff --git a/src/components/common/Header/Header.tsx b/src/components/common/Header/Header.tsx index 12d656026..a9926f765 100644 --- a/src/components/common/Header/Header.tsx +++ b/src/components/common/Header/Header.tsx @@ -1,8 +1,9 @@ import classNames from 'classnames' import React, { memo, useEffect, useState } from 'react' -import { useModalCommon } from 'src/components/hooks/useModalCommon' +import { useModalCommon } from 'src/components/hooks' import { isMobile } from 'src/utils/funtion.utils' import ModalAuthenticate from '../ModalAuthenticate/ModalAuthenticate' +import ModalCreateUserInfo from '../ModalCreateUserInfo/ModalCreateUserInfo' import HeaderHighLight from './components/HeaderHighLight/HeaderHighLight' import HeaderMenu from './components/HeaderMenu/HeaderMenu' import HeaderSubMenu from './components/HeaderSubMenu/HeaderSubMenu' @@ -13,6 +14,7 @@ import s from './Header.module.scss' const Header = memo(() => { const [isFullHeader, setIsFullHeader] = useState(true) const { visible: visibleModalAuthen, closeModal: closeModalAuthen, openModal: openModalAuthen } = useModalCommon({ initialValue: false }) + const { visible: visibleModalInfo, closeModal: closeModalInfo, openModal: openModalInfo } = useModalCommon({ initialValue: false }) useEffect(() => { window.addEventListener('scroll', handleScroll) @@ -35,12 +37,15 @@ const Header = memo(() => {
- +
+ ) }) diff --git a/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx b/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx index a5ef71951..969964608 100644 --- a/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx +++ b/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx @@ -11,14 +11,19 @@ interface Props { children?: any, isFull: boolean, openModalAuthen: () => void, + openModalInfo: () => void, } -const HeaderMenu = memo(({ isFull, openModalAuthen }: Props) => { +const HeaderMenu = memo(({ isFull, openModalAuthen, openModalInfo }: Props) => { const optionMenu = useMemo(() => [ { onClick: openModalAuthen, name: 'Login (Demo)', }, + { + onClick: openModalInfo, + name: 'Create User Info (Demo)', + }, { link: ROUTE.ACCOUNT, name: 'Account', diff --git a/src/components/common/ImgWithLink/ImgWithLink.module.scss b/src/components/common/ImgWithLink/ImgWithLink.module.scss new file mode 100644 index 000000000..b1587bfa6 --- /dev/null +++ b/src/components/common/ImgWithLink/ImgWithLink.module.scss @@ -0,0 +1,4 @@ +.imgWithLink { + @apply w-full h-full; + object-fit: cover; +} diff --git a/src/components/common/ImgWithLink/ImgWithLink.tsx b/src/components/common/ImgWithLink/ImgWithLink.tsx new file mode 100644 index 000000000..43ac1caa6 --- /dev/null +++ b/src/components/common/ImgWithLink/ImgWithLink.tsx @@ -0,0 +1,16 @@ +import React from 'react' +import s from './ImgWithLink.module.scss' + +export interface ImgWithLinkProps { + src: string, + alt?: string, +} + +const ImgWithLink = ({ src, alt }: ImgWithLinkProps) => { + return ( + {alt} + + ) +} + +export default ImgWithLink \ No newline at end of file diff --git a/src/components/common/InputCommon/InputCommon.module.scss b/src/components/common/InputCommon/InputCommon.module.scss index 1ef1fdbc7..acfc07647 100644 --- a/src/components/common/InputCommon/InputCommon.module.scss +++ b/src/components/common/InputCommon/InputCommon.module.scss @@ -1,51 +1,94 @@ @import "../../../styles/utilities"; .inputWrap { - @apply flex items-center relative; - .icon { - @apply absolute; - content: ""; - left: 1.6rem; - margin-right: 1.6rem; - svg path { - fill: currentColor; + .inputInner { + @apply flex items-center relative; + .icon { + @apply absolute flex justify-center items-center; + content: ""; + left: 1.6rem; + margin-right: 1.6rem; + svg path { + fill: currentColor; + } } - } - .icon + .inputCommon { - padding-left: 4.8rem; - } - .inputCommon { - @apply block w-full transition-all duration-200 rounded; - padding: 1.2rem 1.6rem; - border: 1px solid var(--border-line); - &:hover, - &:focus, - &:active { - outline: none; - border: 1px solid var(--primary); - @apply shadow-md; + .icon + .inputCommon { + padding-left: 4.8rem; } - &::placeholder { - @apply text-label; - } - - &.custom { - @apply custom-border-radius; - border: 1px solid transparent; - background: var(--gray); + .inputCommon { + @apply block w-full transition-all duration-200 rounded; + padding: 1.2rem 1.6rem; + border: 1px solid var(--border-line); &:hover, &:focus, &:active { + outline: none; border: 1px solid var(--primary); + @apply shadow-md; + } + + &::placeholder { + @apply text-label; + } + + &.custom { + @apply custom-border-radius; + border: 1px solid transparent; + background: var(--gray); + &:hover, + &:focus, + &:active { + border: 1px solid var(--primary); + } + } + &.bgTransparent { + background: rgb(227, 242, 233, 0.3); + color: var(--white); + &::placeholder { + color: var(--white); + } } } - &.bgTransparent { - background: rgb(227, 242, 233, 0.3); - color: var(--white); - &::placeholder { - color: var(--white); + + &.preserve { + @apply flex-row-reverse; + .icon { + left: unset; + right: 1.6rem; + margin-left: 1.6rem; + margin-right: 0; + svg path { + fill: var(--text-label); + } + } + .icon + .inputCommon { + padding-left: 1.6rem; + padding-right: 4.8rem; + } + } + &.success { + .icon { + svg path { + fill: var(--primary); + } + } + } + + &.error { + .icon { + svg path { + fill: var(--negative); + } + } + input { + border-color: var(--negative) !important; } } } + .errorMessage { + @apply caption; + color: var(--negative); + margin-top: 0.4rem; + } } diff --git a/src/components/common/InputCommon/InputCommon.tsx b/src/components/common/InputCommon/InputCommon.tsx index 6a42d5537..943b0a632 100644 --- a/src/components/common/InputCommon/InputCommon.tsx +++ b/src/components/common/InputCommon/InputCommon.tsx @@ -1,5 +1,6 @@ import classNames from 'classnames'; -import React, { forwardRef, useImperativeHandle, useRef } from 'react'; +import React, { forwardRef, useImperativeHandle, useMemo, useRef, useState } from 'react'; +import { IconCheck, IconError, IconPassword, IconPasswordCross } from 'src/components/icons'; import { KEY } from 'src/utils/constanst.utils'; import s from './InputCommon.module.scss'; @@ -14,14 +15,29 @@ interface Props { styleType?: 'default' | 'custom', backgroundTransparent?: boolean, icon?: React.ReactNode, + isIconSuffix?: boolean, + isShowIconSuccess?: boolean, + error?: string, onChange?: (value: string | number) => void, onEnter?: (value: string | number) => void, } const InputCommon = forwardRef(({ value, placeholder, type, styleType = 'default', icon, backgroundTransparent = false, + isIconSuffix, isShowIconSuccess, error, onChange, onEnter }: Props, ref) => { const inputElementRef = useRef(null); + const iconElement = useMemo(() => { + if (error) { + return + } else if (isShowIconSuccess) { + return + } else if (icon) { + return {icon} + } + return <> + }, [icon, error, isShowIconSuccess]) + useImperativeHandle(ref, () => ({ focus: () => { inputElementRef.current?.focus(); @@ -44,23 +60,33 @@ const InputCommon = forwardRef(({ value, placeholder, type, styleTyp } return ( -
+
+
+ {iconElement} + +
{ - icon && {icon} + error &&
{error}
} -
) diff --git a/src/components/common/InputPassword/InputPassword.module.scss b/src/components/common/InputPassword/InputPassword.module.scss new file mode 100644 index 000000000..598620891 --- /dev/null +++ b/src/components/common/InputPassword/InputPassword.module.scss @@ -0,0 +1,10 @@ +.iconPassword { + all: unset; + cursor: pointer; + &:focus { + outline: none; + } + &:focus-visible { + outline: 2px solid var(--text-active); + } +} diff --git a/src/components/common/InputPassword/InputPassword.tsx b/src/components/common/InputPassword/InputPassword.tsx new file mode 100644 index 000000000..83e91cfcc --- /dev/null +++ b/src/components/common/InputPassword/InputPassword.tsx @@ -0,0 +1,40 @@ +import React, { useState } from 'react'; +import { IconPassword, IconPasswordCross } from 'src/components/icons'; +import { Inputcommon } from '..'; +import s from './InputPassword.module.scss'; + +interface Props { + children?: React.ReactNode, + value?: string | number, + placeholder?: string, + styleType?: 'default' | 'custom', + error?: string, + onChange?: (value: string | number) => void, + onEnter?: (value: string | number) => void, +} + +const InputPassword = ({ value, placeholder, styleType = 'default', error, + onChange, onEnter }: Props) => { + const [isShowPassword, setIsShowPassword] = useState(false) + const toggleShowPassword = () => { + setIsShowPassword(!isShowPassword) + } + + return ( + + {isShowPassword ? : } + } + isIconSuffix={true} + onChange={onChange} + onEnter={onEnter} + /> + ) +} + +export default InputPassword diff --git a/src/components/common/ListProductWithInfo/InfoProducts/InfoProducts.module.scss b/src/components/common/ListProductWithInfo/InfoProducts/InfoProducts.module.scss new file mode 100644 index 000000000..c1cd9966e --- /dev/null +++ b/src/components/common/ListProductWithInfo/InfoProducts/InfoProducts.module.scss @@ -0,0 +1,23 @@ +@import "../../../../styles/utilities"; + +.infoProducts { + @apply flex justify-between items-center spacing-horizontal; + + .top { + .sub { + display: none; + } + } + @screen lg { + @apply block; + margin-right: 4rem; + padding: 0; + .top { + margin-bottom: 3.2rem; + .sub { + display: block; + margin-top: 0.4rem; + } + } + } +} diff --git a/src/components/common/ListProductWithInfo/InfoProducts/InfoProducts.tsx b/src/components/common/ListProductWithInfo/InfoProducts/InfoProducts.tsx new file mode 100644 index 000000000..25e18252c --- /dev/null +++ b/src/components/common/ListProductWithInfo/InfoProducts/InfoProducts.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { ROUTE } from 'src/utils/constanst.utils'; +import HeadingCommon from '../../HeadingCommon/HeadingCommon'; +import ViewAllItem from '../../ViewAllItem/ViewAllItem'; +import s from './InfoProducts.module.scss' +interface Props { + title: string, + subtitle?: string, +} + +const InfoProducts = ({ title, subtitle }: Props) => { + return ( +
+
+ {title} +
+ {subtitle} +
+
+ + +
+ ); +}; + +export default InfoProducts; \ No newline at end of file diff --git a/src/components/common/ListProductWithInfo/ListProductWithInfo.module.scss b/src/components/common/ListProductWithInfo/ListProductWithInfo.module.scss new file mode 100644 index 000000000..d2443dccc --- /dev/null +++ b/src/components/common/ListProductWithInfo/ListProductWithInfo.module.scss @@ -0,0 +1,48 @@ +@import "../../../styles/utilities"; + +.listProductWithInfo { + background-color: var(--background); + border-top: 1rem solid var(--gray); + border-bottom: 1rem solid var(--gray); + padding-top: 6rem; + padding-bottom: 6rem; + @screen lg { + @apply flex spacing-horizontal-left; + padding-top: 5.6rem; + padding-bottom: 5.6rem; + border: none; + background-color: #f5f4f2; + } + .productsWrap { + @apply spacing-horizontal-left; + @screen lg { + max-width: 75%; + @apply custom-border-radius-lg bg-white; + padding: 4rem .8rem; + :global(.customArrow) { + @screen lg { + &:global(.leftArrow) { + left: calc(-6.4rem + 3rem); + } + &:global(.rightArrow) { + right: calc(-6.4rem + 3rem); + } + } + } + } + @screen xl { + padding: 4rem 2.4rem; + max-width: 80%; + :global(.customArrow) { + @screen lg { + &:global(.leftArrow) { + left: calc(-6.4rem + 1rem); + } + &:global(.rightArrow) { + right: calc(-6.4rem + 1rem); + } + } + } + } + } +} diff --git a/src/components/common/ListProductWithInfo/ListProductWithInfo.tsx b/src/components/common/ListProductWithInfo/ListProductWithInfo.tsx new file mode 100644 index 000000000..66b8253d1 --- /dev/null +++ b/src/components/common/ListProductWithInfo/ListProductWithInfo.tsx @@ -0,0 +1,51 @@ +import { TOptionsEvents } from 'keen-slider'; +import React from 'react'; +import CarouselCommon from '../CarouselCommon/CarouselCommon'; +import ProductCard, { ProductCardProps } from '../ProductCard/ProductCard'; +import InfoProducts from './InfoProducts/InfoProducts'; +import s from './ListProductWithInfo.module.scss'; + +interface Props { + data: ProductCardProps[], + title: string, + subtitle?: string, +} +const OPTION_DEFAULT: TOptionsEvents = { + slidesPerView: 2, + mode: 'free', + breakpoints: { + '(min-width: 640px)': { + slidesPerView: 3, + }, + '(min-width: 768px)': { + slidesPerView: 4, + }, + '(min-width: 1024px)': { + slidesPerView: 3, + }, + '(min-width: 1280px)': { + slidesPerView: 4.5, + }, + }, +} + +const ListProductWithInfo = ({ data, title, subtitle }: Props) => { + return ( +
+ +
+ + data={data} + Component={ProductCard} + itemKey={title} + option={OPTION_DEFAULT} + /> +
+
+ ); +}; + +export default ListProductWithInfo; \ No newline at end of file diff --git a/src/components/common/MenuDropdown/MenuDropdown.module.scss b/src/components/common/MenuDropdown/MenuDropdown.module.scss index ca79464e1..8fc270b2a 100644 --- a/src/components/common/MenuDropdown/MenuDropdown.module.scss +++ b/src/components/common/MenuDropdown/MenuDropdown.module.scss @@ -78,7 +78,7 @@ @apply block; } &:hover { - @apply bg-primary-lightest; + @apply bg-gray; color: var(--primary); } } diff --git a/src/components/common/ModalAuthenticate/components/FormAuthen.module.scss b/src/components/common/ModalAuthenticate/components/FormAuthen.module.scss index bdfc69387..2ec8bf91f 100644 --- a/src/components/common/ModalAuthenticate/components/FormAuthen.module.scss +++ b/src/components/common/ModalAuthenticate/components/FormAuthen.module.scss @@ -1,17 +1,12 @@ +@import '../../../../styles/utilities'; + .formAuthen { - @apply bg-white w-full; + @apply bg-white w-full u-form; .inner { @screen md { - max-width: 52rem; + width: 60rem; margin: auto; } - .body { - > div { - &:not(:last-child) { - margin-bottom: 1.6rem; - } - } - } .others { @apply font-bold text-center; margin-top: 4rem; diff --git a/src/components/common/ModalAuthenticate/components/FormLogin/FormLogin.tsx b/src/components/common/ModalAuthenticate/components/FormLogin/FormLogin.tsx index 7ef3ec9ba..bedb993f4 100644 --- a/src/components/common/ModalAuthenticate/components/FormLogin/FormLogin.tsx +++ b/src/components/common/ModalAuthenticate/components/FormLogin/FormLogin.tsx @@ -1,12 +1,12 @@ import Link from 'next/link' -import React, { useRef, useEffect } from 'react' -import { Inputcommon, ButtonCommon } from 'src/components/common' +import React, { useEffect, useRef } from 'react' +import { ButtonCommon, Inputcommon } from 'src/components/common' +import InputPassword from 'src/components/common/InputPassword/InputPassword' import { ROUTE } from 'src/utils/constanst.utils' -import SocialAuthen from '../SocialAuthen/SocialAuthen' -import s from '../FormAuthen.module.scss' -import styles from './FormLogin.module.scss' -import classNames from 'classnames' import { CustomInputCommon } from 'src/utils/type.utils' +import s from '../FormAuthen.module.scss' +import SocialAuthen from '../SocialAuthen/SocialAuthen' +import styles from './FormLogin.module.scss' interface Props { isHide: boolean, @@ -23,14 +23,13 @@ const FormLogin = ({ onSwitch, isHide }: Props) => { }, [isHide]) return ( -
+
- - + + {/* */} +
diff --git a/src/components/common/ModalAuthenticate/components/FormRegister/FormRegister.tsx b/src/components/common/ModalAuthenticate/components/FormRegister/FormRegister.tsx index 1624f2c1c..d03dbc39e 100644 --- a/src/components/common/ModalAuthenticate/components/FormRegister/FormRegister.tsx +++ b/src/components/common/ModalAuthenticate/components/FormRegister/FormRegister.tsx @@ -24,12 +24,11 @@ const FormRegister = ({ onSwitch, isHide }: Props) => {
- +
Must contain 8 characters with at least 1 uppercase and 1 lowercase letter and either 1 number or 1 special character.
diff --git a/src/components/common/ModalCommon/ModalCommon.module.scss b/src/components/common/ModalCommon/ModalCommon.module.scss index d4967b04e..87900b1a1 100644 --- a/src/components/common/ModalCommon/ModalCommon.module.scss +++ b/src/components/common/ModalCommon/ModalCommon.module.scss @@ -8,7 +8,7 @@ @apply flex justify-center items-center min-h-screen; .modal{ @apply inline-block align-bottom bg-white relative; - max-width: 60rem; + max-width: 66.4rem; padding: 3.2rem; box-shadow: 0px 8px 16px rgba(0, 0, 0, 0.24); border-radius: 1.2rem; @@ -17,7 +17,7 @@ } .title{ @apply font-heading heading-3; - padding: 0 0.8rem 0 0.8rem; + padding: 0 1.6rem 0 0.8rem; } .close{ @apply absolute; diff --git a/src/components/common/ModalCommon/ModalCommon.tsx b/src/components/common/ModalCommon/ModalCommon.tsx index 2ed90a3b3..75222c162 100644 --- a/src/components/common/ModalCommon/ModalCommon.tsx +++ b/src/components/common/ModalCommon/ModalCommon.tsx @@ -2,7 +2,7 @@ import React, { useRef } from 'react' import { Close } from 'src/components/icons' import { useOnClickOutside } from 'src/utils/useClickOutSide' import s from './ModalCommon.module.scss' -interface Props { +export interface ModalCommonProps { onClose: () => void visible: boolean children: React.ReactNode @@ -10,7 +10,7 @@ interface Props { maxWidth?:string } -const ModalCommon = ({ onClose, visible, children, title="Modal",maxWidth }: Props) => { +const ModalCommon = ({ onClose, visible, children, title="Modal",maxWidth }: ModalCommonProps) => { const modalRef = useRef(null) const clickOutSide = () => { onClose && onClose() diff --git a/src/components/common/ModalConfirm/ModalConfirm.module.scss b/src/components/common/ModalConfirm/ModalConfirm.module.scss new file mode 100644 index 000000000..ac167b2a2 --- /dev/null +++ b/src/components/common/ModalConfirm/ModalConfirm.module.scss @@ -0,0 +1,4 @@ +.footer{ + margin-top: 4rem; + @apply flex justify-end items-center; +} \ No newline at end of file diff --git a/src/components/common/ModalConfirm/ModalConfirm.tsx b/src/components/common/ModalConfirm/ModalConfirm.tsx new file mode 100644 index 000000000..1e425482f --- /dev/null +++ b/src/components/common/ModalConfirm/ModalConfirm.tsx @@ -0,0 +1,34 @@ +import React from 'react' +import ButtonCommon from '../ButtonCommon/ButtonCommon' +import ModalCommon, { ModalCommonProps } from '../ModalCommon/ModalCommon' +import s from './ModalConfirm.module.scss' +interface ModalConfirmProps extends ModalCommonProps { + okText?: String + cancelText?: String + onOk?: () => void + onCancel?: () => void +} + +const ModalConfirm = ({ + okText = 'Ok', + cancelText = 'cancel', + onOk, + onCancel, + children, + title = 'Confirm', + ...props +}: ModalConfirmProps) => { + return ( + + {children} +
+
+ {cancelText} +
+ {okText} +
+
+ ) +} + +export default ModalConfirm diff --git a/src/components/common/ModalCreateUserInfo/ModalCreateUserInfo.module.scss b/src/components/common/ModalCreateUserInfo/ModalCreateUserInfo.module.scss new file mode 100644 index 000000000..199028061 --- /dev/null +++ b/src/components/common/ModalCreateUserInfo/ModalCreateUserInfo.module.scss @@ -0,0 +1,19 @@ +@import "../../../styles/utilities"; + +.formUserInfo { + @apply u-form; + .inner { + @screen md { + width: 60rem; + margin: auto; + } + .bottom { + @apply grid grid-cols-2; + margin-top: 4rem; + grid-gap: 1.6rem; + > button { + @apply w-full; + } + } + } +} diff --git a/src/components/common/ModalCreateUserInfo/ModalCreateUserInfo.tsx b/src/components/common/ModalCreateUserInfo/ModalCreateUserInfo.tsx new file mode 100644 index 000000000..85817c930 --- /dev/null +++ b/src/components/common/ModalCreateUserInfo/ModalCreateUserInfo.tsx @@ -0,0 +1,46 @@ +import classNames from 'classnames'; +import Link from 'next/link'; +import React, { useRef } from 'react'; +import { useModalCommon } from 'src/components/hooks/useModalCommon'; +import { CustomInputCommon } from 'src/utils/type.utils'; +import { Inputcommon } from '..'; +import ButtonCommon from '../ButtonCommon/ButtonCommon'; +import ModalCommon from '../ModalCommon/ModalCommon'; +import s from './ModalCreateUserInfo.module.scss'; + +// todo: remove +interface Props { + demoVisible: boolean, + demoCloseModal: () => void, +} + + +const ModalCreateUserInfo = ({ demoVisible: visible, demoCloseModal: closeModal }: Props) => { + // const { visible, closeModal } = useModalCommon({ initialValue: false}) + const firstInputRef = useRef(null) + + return ( + +
+
+
+ + +
+ {/* todo: select, not input */} + + +
+ +
+
+ Skip + Submit +
+
+
+
+ ); +} + +export default ModalCreateUserInfo; \ No newline at end of file diff --git a/src/components/common/ModalInfo/ModalInfo.module.scss b/src/components/common/ModalInfo/ModalInfo.module.scss new file mode 100644 index 000000000..ac167b2a2 --- /dev/null +++ b/src/components/common/ModalInfo/ModalInfo.module.scss @@ -0,0 +1,4 @@ +.footer{ + margin-top: 4rem; + @apply flex justify-end items-center; +} \ No newline at end of file diff --git a/src/components/common/ModalInfo/ModalInfo.tsx b/src/components/common/ModalInfo/ModalInfo.tsx new file mode 100644 index 000000000..1880d8f63 --- /dev/null +++ b/src/components/common/ModalInfo/ModalInfo.tsx @@ -0,0 +1,27 @@ +import React from 'react' +import ButtonCommon from '../ButtonCommon/ButtonCommon' +import ModalCommon, { ModalCommonProps } from '../ModalCommon/ModalCommon' +import s from './ModalInfo.module.scss' +interface ModalInfoProps extends ModalCommonProps { + okText?: String + onOk?: () => void +} + +const ModalInfo = ({ + okText = 'Ok', + onOk, + children, + title = 'Confirm', + ...props +}: ModalInfoProps) => { + return ( + + {children} +
+ {okText} +
+
+ ) +} + +export default ModalInfo diff --git a/src/components/common/PaginationCommon/PaginationCommon.module.scss b/src/components/common/PaginationCommon/PaginationCommon.module.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/components/common/PaginationCommon/PaginationCommon.tsx b/src/components/common/PaginationCommon/PaginationCommon.tsx new file mode 100644 index 000000000..59bbd3baa --- /dev/null +++ b/src/components/common/PaginationCommon/PaginationCommon.tsx @@ -0,0 +1,15 @@ +import React from 'react' + +interface PaginationCommonProps { + +} + +const PaginationCommon = (props: PaginationCommonProps) => { + return ( +
+ +
+ ) +} + +export default PaginationCommon diff --git a/src/components/common/ProductCard/ProductCard.module.scss b/src/components/common/ProductCard/ProductCard.module.scss index 97dce1794..73be21ab1 100644 --- a/src/components/common/ProductCard/ProductCard.module.scss +++ b/src/components/common/ProductCard/ProductCard.module.scss @@ -2,8 +2,12 @@ max-width: 20.8rem; min-height: 31.8rem; padding: 1.2rem 1.2rem 0 1.2rem; + margin: auto; margin-bottom: 1px; @apply flex flex-col justify-between; + &.notSell { + @apply justify-center; + } .cardTop{ @apply relative; height: 13.8rem; @@ -29,8 +33,6 @@ .cardMidTop{ .productname{ font-weight: bold; - line-height: 2.4rem; - font-size: 1.6rem; color: var(--text-active); &:hover{ cursor: pointer; diff --git a/src/components/common/ProductCard/ProductCard.tsx b/src/components/common/ProductCard/ProductCard.tsx index 7d94be6bc..4f1e3b329 100644 --- a/src/components/common/ProductCard/ProductCard.tsx +++ b/src/components/common/ProductCard/ProductCard.tsx @@ -6,6 +6,7 @@ import ButtonIconBuy from '../ButtonIconBuy/ButtonIconBuy' import ItemWishList from '../ItemWishList/ItemWishList' import LabelCommon from '../LabelCommon/LabelCommon' import s from './ProductCard.module.scss' +import ProductNotSell from './ProductNotSell/ProductNotSell' export interface ProductCardProps extends ProductProps { buttonText?: string @@ -18,7 +19,15 @@ const ProductCard = ({ price, buttonText = 'Buy Now', imageSrc, + isNotSell, }: ProductCardProps) => { + if (isNotSell) { + return
+ +
+ + } + return (
diff --git a/src/components/common/ProductCard/ProductNotSell/ProductNotSell.module.scss b/src/components/common/ProductCard/ProductNotSell/ProductNotSell.module.scss new file mode 100644 index 000000000..4945220a9 --- /dev/null +++ b/src/components/common/ProductCard/ProductNotSell/ProductNotSell.module.scss @@ -0,0 +1,27 @@ +@import "../../../../styles/utilities"; + +.imgWrap { + img { + opacity: 0.5; + } +} + +.name { + @apply text-label cursor-default font-bold; +} + +.info { + @apply flex justify-center items-center custom-border-radius bg-info-light text-center; + padding: .8rem 1.6rem; + margin-top: 1.6rem; + color: var(--info); + svg { + @apply u-icon; + path { + fill: currentColor; + } + } + .text { + margin-left: 0.8rem; + } +} diff --git a/src/components/common/ProductCard/ProductNotSell/ProductNotSell.tsx b/src/components/common/ProductCard/ProductNotSell/ProductNotSell.tsx new file mode 100644 index 000000000..f87d87c43 --- /dev/null +++ b/src/components/common/ProductCard/ProductNotSell/ProductNotSell.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { IconInfo } from 'src/components/icons'; +import ImgWithLink from '../../ImgWithLink/ImgWithLink'; +import s from './ProductNotSell.module.scss'; + +export interface Props { + name: string, + imageSrc: string, +} + +const ProductNotSell = ({ name, imageSrc }: Props) => { + return ( + <> +
+ +
+
{name}
+
+ +
+ Not Sell +
+
+ + ); +}; + +export default ProductNotSell; \ No newline at end of file diff --git a/src/components/common/RecipeCard/RecipeCard.module.scss b/src/components/common/RecipeCard/RecipeCard.module.scss index 1fd6fd65e..19f3eb76a 100644 --- a/src/components/common/RecipeCard/RecipeCard.module.scss +++ b/src/components/common/RecipeCard/RecipeCard.module.scss @@ -6,6 +6,9 @@ width: 100%; max-height: 22rem; border-radius: 2.4rem; + img { + border-radius: 2.4rem; + } &:hover{ cursor: pointer; } diff --git a/src/components/common/RecipeDetail/RecipeDetail.module.scss b/src/components/common/RecipeDetail/RecipeDetail.module.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/components/common/RecipeDetail/RecipeDetail.tsx b/src/components/common/RecipeDetail/RecipeDetail.tsx new file mode 100644 index 000000000..cdec99994 --- /dev/null +++ b/src/components/common/RecipeDetail/RecipeDetail.tsx @@ -0,0 +1,23 @@ +import React from 'react' +import { ProductCardProps } from '../ProductCard/ProductCard' +import RecipeDetailInfo from './components/RecipeDetailInfo/RecipeDetailInfo' +import RecipeIngredient from './components/RecipeIngredient/RecipeIngredient' +import s from './RecipeDetail.module.scss' + + +interface Props { + className?: string + children?: any, + ingredients: ProductCardProps[], +} + +const RecipeDetail = ({ ingredients }: Props) => { + return ( +
+ + +
+ ) +} + +export default RecipeDetail diff --git a/src/components/common/RecipeDetail/components/RecipeBriefInfo/RecipeBriefInfo.module.scss b/src/components/common/RecipeDetail/components/RecipeBriefInfo/RecipeBriefInfo.module.scss new file mode 100644 index 000000000..56f1e6500 --- /dev/null +++ b/src/components/common/RecipeDetail/components/RecipeBriefInfo/RecipeBriefInfo.module.scss @@ -0,0 +1,19 @@ +.recipeBriefInfo { + @apply flex; + .item { + @apply flex; + &:not(:last-child) { + margin-right: 2.4rem; + } + svg { + width: 2rem; + height: 2rem; + path { + fill: var(--text-label); + } + } + .content { + margin-left: 0.8rem; + } + } +} diff --git a/src/components/common/RecipeDetail/components/RecipeBriefInfo/RecipeBriefInfo.tsx b/src/components/common/RecipeDetail/components/RecipeBriefInfo/RecipeBriefInfo.tsx new file mode 100644 index 000000000..d06387914 --- /dev/null +++ b/src/components/common/RecipeDetail/components/RecipeBriefInfo/RecipeBriefInfo.tsx @@ -0,0 +1,29 @@ +import React from 'react' +import { IconLocation, IconPeople, IconTime } from 'src/components/icons' +import s from './RecipeBriefInfo.module.scss' + +interface Props { + className?: string + children?: any, +} + +const RecipeBriefInfo = ({ }: Props) => { + return ( +
+
+ +
15 minutes
+
+
+ +
4 People
+
+
+ +
15 minutes
+
+
+ ) +} + +export default RecipeBriefInfo diff --git a/src/components/common/RecipeDetail/components/RecipeDetailInfo/RecipeDetailInfo.module.scss b/src/components/common/RecipeDetail/components/RecipeDetailInfo/RecipeDetailInfo.module.scss new file mode 100644 index 000000000..86b525083 --- /dev/null +++ b/src/components/common/RecipeDetail/components/RecipeDetailInfo/RecipeDetailInfo.module.scss @@ -0,0 +1,61 @@ +@import "../../../../../styles/utilities"; + +.recipeDetailInfo { + @apply spacing-horizontal; + margin: 5.6rem auto; + @screen md { + @apply flex; + } + .img { + width: fit-content; + margin-top: 0; + + @screen sm-only { + margin-bottom: 2rem; + } + @screen lg { + max-width: 60rem; + } + img { + @apply w-full; + object-fit: contain; + max-height: 64rem; + border-radius: 2.4rem; + @screen md { + max-height: 90rem; + } + } + } + + .recipeInfo { + @screen md { + max-width: 39rem; + margin-left: 4.8rem; + } + @screen lg { + margin-left: 11.2rem; + } + .top { + margin-bottom: 4.8rem; + .name { + @apply heading-1 font-heading; + margin-bottom: 1.6rem; + } + } + .detail { + .item { + &:not(:last-child) { + margin-bottom: 2.4rem; + } + .heading { + @apply heading-3 font-heading; + margin-bottom: 0.8rem; + } + .content { + list-style: disc; + margin-left: 2rem; + } + } + } + } +} diff --git a/src/components/common/RecipeDetail/components/RecipeDetailInfo/RecipeDetailInfo.tsx b/src/components/common/RecipeDetail/components/RecipeDetailInfo/RecipeDetailInfo.tsx new file mode 100644 index 000000000..4d212e10a --- /dev/null +++ b/src/components/common/RecipeDetail/components/RecipeDetailInfo/RecipeDetailInfo.tsx @@ -0,0 +1,59 @@ +import React from 'react' +import RecipeBriefInfo from '../RecipeBriefInfo/RecipeBriefInfo' +import s from './RecipeDetailInfo.module.scss' + + +interface Props { + className?: string + children?: any +} + +const RecipeDetailInfo = ({ }: Props) => { + return ( +
+
+ Recipe +
+
+
+

+ Crispy Fried Calamari +

+ +
+
+
+

Ingredients

+
    +
  • Canola oil for frying
  • +
  • 1 pound clean squid bodies cut in 1/4 inch rings and dried with a paper towel
  • +
  • 2 cups flour
  • +
  • 1/2 teaspoon kosher salt
  • +
  • 1/2 teaspoon garlic powder
  • +
  • 1/8 teaspoon coarse ground black pepper
  • +
  • 1 lemon cut into wedges
  • +
+
+ +
+

Preparation

+
    +
  • 1In a large pot or dutch oven add three inches of oil and bring to 350 degrees.
  • +
  • Add the flour, salt, garlic powder and pepper to a large bowl and stir to combine.
  • +
  • Toss the squid pieces in the flour then into the hot oil.
  • +
  • Fry the squid for 1-2 minutes. You want the color to stay pale like in the pictures.
  • +
  • Remove to a cookie sheet to drain (do not add paper towels as it will steam the calamari and make it soft.)
  • +
  • Serve with lemon wedges.
  • +
+
+ +
+
+
+ ) +} + +export default RecipeDetailInfo diff --git a/src/components/common/RecipeDetail/components/RecipeIngredient/RecipeIngredient.module.scss b/src/components/common/RecipeDetail/components/RecipeIngredient/RecipeIngredient.module.scss new file mode 100644 index 000000000..b1419699d --- /dev/null +++ b/src/components/common/RecipeDetail/components/RecipeIngredient/RecipeIngredient.module.scss @@ -0,0 +1,21 @@ +@import "../../../../../styles/utilities"; + +.recipeIngredient { + padding: 6rem 0; + @screen md { + padding: 5.6rem 0; + } + .top { + @apply flex justify-between items-center spacing-horizontal; + } + .bottom { + @apply flex justify-center items-center spacing-horizontal; + margin-top: 4rem; + button { + width: 100%; + @screen md { + width: 39rem; + } + } + } +} diff --git a/src/components/common/RecipeDetail/components/RecipeIngredient/RecipeIngredient.tsx b/src/components/common/RecipeDetail/components/RecipeIngredient/RecipeIngredient.tsx new file mode 100644 index 000000000..a879f0b72 --- /dev/null +++ b/src/components/common/RecipeDetail/components/RecipeIngredient/RecipeIngredient.tsx @@ -0,0 +1,33 @@ +import React from 'react' +import ButtonCommon from 'src/components/common/ButtonCommon/ButtonCommon' +import HeadingCommon from 'src/components/common/HeadingCommon/HeadingCommon' +import { ProductCardProps } from 'src/components/common/ProductCard/ProductCard' +import ProductCarousel from 'src/components/common/ProductCarousel/ProductCarousel' +import ViewAllItem from 'src/components/common/ViewAllItem/ViewAllItem' +import { ROUTE } from 'src/utils/constanst.utils' +import s from './RecipeIngredient.module.scss' + +interface Props { + className?: string + children?: any, + data: ProductCardProps[], +} + +const RecipeIngredient = ({ data }: Props) => { + return ( +
+
+ Ingredients +
+ +
+
+ +
+ Buy all +
+
+ ) +} + +export default RecipeIngredient diff --git a/src/components/common/ScrollToTop/ScrollTarget.tsx b/src/components/common/ScrollToTop/ScrollTarget.tsx deleted file mode 100644 index 50a839c83..000000000 --- a/src/components/common/ScrollToTop/ScrollTarget.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React, { MutableRefObject } from 'react' - -interface ScrollTargetProps { - refScrollUp: MutableRefObject; -} - -const ScrollTarget = ({ refScrollUp } : ScrollTargetProps) => { - - return ( -
- ) - -} - -export default ScrollTarget diff --git a/src/components/common/ScrollToTop/ScrollToTop.tsx b/src/components/common/ScrollToTop/ScrollToTop.tsx index 98e16168d..d148c8937 100644 --- a/src/components/common/ScrollToTop/ScrollToTop.tsx +++ b/src/components/common/ScrollToTop/ScrollToTop.tsx @@ -5,11 +5,10 @@ import s from './ScrollToTop.module.scss' import ArrowUp from '../../icons/IconArrowUp' interface ScrollToTopProps { - target: MutableRefObject; visibilityHeight?: number; } -const ScrollToTop = ({ target, visibilityHeight=450 }: ScrollToTopProps) => { +const ScrollToTop = ({ visibilityHeight=450 }: ScrollToTopProps) => { const [scrollPosition, setSrollPosition] = useState(0); const [showScrollToTop, setShowScrollToTop] = useState("hide"); @@ -26,7 +25,7 @@ const ScrollToTop = ({ target, visibilityHeight=450 }: ScrollToTopProps) => { }; function handleScrollUp() { - target.current.scrollIntoView({ behavior: "smooth" }); + window.scrollTo(0, 0); } function addEventScroll() { @@ -34,7 +33,7 @@ const ScrollToTop = ({ target, visibilityHeight=450 }: ScrollToTopProps) => { } useEffect(() => { - addEventScroll() + addEventScroll(); }); return ( diff --git a/src/components/common/SelectCommon/SelectCommon.module.scss b/src/components/common/SelectCommon/SelectCommon.module.scss index dcb9120da..d91b1831e 100644 --- a/src/components/common/SelectCommon/SelectCommon.module.scss +++ b/src/components/common/SelectCommon/SelectCommon.module.scss @@ -1,32 +1,69 @@ @import "../../../styles/utilities"; .select{ - @apply rounded-lg border-solid; - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - padding: 1.2rem 1.6rem; + background-color: var(--white); &.base{ - width: 18.6rem; - height: 4.8rem; + width: 20.6rem; + .selectTrigger{ + width: 20.6rem; + padding: 1.2rem 1.6rem; + } } &.large{ width: 34.25rem; - height: 5.6rem; + .selectTrigger{ + width: 34.25rem; + padding: 1.6rem 1.6rem; + } } &.default{ - @apply border; + .selectTrigger{ + @apply border-solid border border-current; + } + } + &.custom{ + .selectTrigger{ + @apply border-2; + border-color: var(--border-line); + color: var(--text-label); + } + } + &.isActive{ + .selectOptionWrapper{ + @apply block; + } + } +} +.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; + } + &.large{ + width: 34.25rem; + } + &.default{ + @apply border-solid border border-current; } &.custom{ @apply border-2; border-color: var(--border-line); color: var(--text-label); } - .option{ - &:hover{ - background-color: black; - } + &.active{ + @apply hidden; } } + + diff --git a/src/components/common/SelectCommon/SelectCommon.tsx b/src/components/common/SelectCommon/SelectCommon.tsx index 8360a700f..5bb3d15d6 100644 --- a/src/components/common/SelectCommon/SelectCommon.tsx +++ b/src/components/common/SelectCommon/SelectCommon.tsx @@ -1,26 +1,75 @@ import s from './SelectCommon.module.scss' import classNames from 'classnames' +import { useState, useRef, useEffect } from 'react' +import { IconVectorDown } from 'src/components/icons' +import SelectOption from './SelectOption/SelectOption' interface Props { - placeHolder? : string, + children? : React.ReactNode, size?: 'base' | 'large', type?: 'default' | 'custom', option: {name: string}[], } -const SelectCommon = ({ type = 'default', size = 'base', option, placeHolder }: Props) => { - return( - + else{ + setActive(false) + } + } + document.addEventListener('click', handleClick) + return () => { + document.removeEventListener('click', handleClick) + } + }, [ref]) + + const changeActiveStatus = () => { + setActive(!isActive) + } + + const changeSelectedName = (item:string) => { + setSelectedName(item) + } + return( + <> +
+
{selectedName}
+ +
+ { + option.map(item => + + ) + } +
+
+ ) } diff --git a/src/components/common/SelectCommon/SelectOption/SelectOption.module.scss b/src/components/common/SelectCommon/SelectOption/SelectOption.module.scss new file mode 100644 index 000000000..5448f9879 --- /dev/null +++ b/src/components/common/SelectCommon/SelectOption/SelectOption.module.scss @@ -0,0 +1,17 @@ +@import "../../../../styles/utilities"; + +.selectOption { + @apply outline-none; + background-color: var(--white); + &.base{ + width: 20.4rem; + padding: 0.8rem 1.6rem; + } + &.large{ + width: 33.75rem; + padding: 0.8rem 1.6rem; + } + &:hover{ + 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 new file mode 100644 index 000000000..54877d5fe --- /dev/null +++ b/src/components/common/SelectCommon/SelectOption/SelectOption.tsx @@ -0,0 +1,25 @@ +import s from './SelectOption.module.scss' +import classNames from 'classnames' + +interface Props{ + onClick: (value: string) => void, + itemName: string, + size: 'base' | 'large', +} + +const SelectOption = ({onClick, itemName, size}: Props) => { + + const changeName = () => { + onClick(itemName) + } + return( +
{itemName}
+ ) +} + +export default SelectOption \ No newline at end of file diff --git a/src/components/common/ViewAllItem/ViewAllItem.module.scss b/src/components/common/ViewAllItem/ViewAllItem.module.scss index 4b8b6fe6d..b4ec26872 100644 --- a/src/components/common/ViewAllItem/ViewAllItem.module.scss +++ b/src/components/common/ViewAllItem/ViewAllItem.module.scss @@ -4,7 +4,7 @@ display: flex; .content { color: var(--primary); - margin: 0.8rem 0.8rem 0.8rem 1.6rem; + margin: 0.8rem 0.8rem 0.8rem 0; font-weight: bold; } .vector { diff --git a/src/components/common/index.ts b/src/components/common/index.ts index dc0288966..77b875765 100644 --- a/src/components/common/index.ts +++ b/src/components/common/index.ts @@ -12,13 +12,13 @@ export { default as ViewAllItem} from './ViewAllItem/ViewAllItem' export { default as ItemWishList} from './ItemWishList/ItemWishList' export { default as Logo} from './Logo/Logo' export { default as Inputcommon} from './InputCommon/InputCommon' +export { default as InputPassword} from './InputPassword/InputPassword' export { default as CheckboxCommon} from './CheckboxCommon/CheckboxCommon' export { default as Author} from './Author/Author' export { default as DateTime} from './DateTime/DateTime' export { default as HeadingCommon } from './HeadingCommon/HeadingCommon' export { default as CollectionHeading } from './CollectionHeading/CollectionHeading' export { default as ScrollToTop } from './ScrollToTop/ScrollToTop' -export { default as ScrollTarget } from './ScrollToTop/ScrollTarget' export { default as InputSearch} from './InputSearch/InputSearch' export { default as ButtonIconBuy} from './ButtonIconBuy/ButtonIconBuy' export { default as Banner} from './Banner/Banner' @@ -28,3 +28,8 @@ export { default as NotiMessage} from './NotiMessage/NotiMessage' export { default as VideoPlayer} from './VideoPlayer/VideoPlayer' 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 ModalCreateUserInfo} from './ModalCreateUserInfo/ModalCreateUserInfo' +export { default as ImgWithLink} from './ImgWithLink/ImgWithLink' +export { default as RecipeDetail} from './RecipeDetail/RecipeDetail' diff --git a/src/components/hooks/index.ts b/src/components/hooks/index.ts new file mode 100644 index 000000000..cf83feb42 --- /dev/null +++ b/src/components/hooks/index.ts @@ -0,0 +1 @@ +export { default as useModalCommon } from './useModalCommon' diff --git a/src/components/hooks/useModalCommon.tsx b/src/components/hooks/useModalCommon.tsx index 02626ce94..41aed648f 100644 --- a/src/components/hooks/useModalCommon.tsx +++ b/src/components/hooks/useModalCommon.tsx @@ -4,7 +4,7 @@ interface Props { initialValue?: boolean, } -export const useModalCommon = ({ initialValue = false }: Props) => { +const useModalCommon = ({ initialValue = false }: Props) => { const [visible, setVisible] = useState(initialValue) const openModal = (e?: any) => { @@ -21,3 +21,5 @@ export const useModalCommon = ({ initialValue = false }: Props) => { visible, openModal, closeModal } }; + +export default useModalCommon \ No newline at end of file diff --git a/src/components/icons/IconCheck.tsx b/src/components/icons/IconCheck.tsx new file mode 100644 index 000000000..cbd1e861c --- /dev/null +++ b/src/components/icons/IconCheck.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +const IconCheck = () => { + return ( + + + + ) +} + +export default IconCheck diff --git a/src/components/icons/IconError.tsx b/src/components/icons/IconError.tsx new file mode 100644 index 000000000..c7c59fb60 --- /dev/null +++ b/src/components/icons/IconError.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +const IconError = () => { + return ( + + + + ) +} + +export default IconError diff --git a/src/components/icons/IconLocation.tsx b/src/components/icons/IconLocation.tsx new file mode 100644 index 000000000..3dc0a81b9 --- /dev/null +++ b/src/components/icons/IconLocation.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +const IconLocation = () => { + return ( + + + + ) +} + +export default IconLocation diff --git a/src/components/icons/IconPassword.tsx b/src/components/icons/IconPassword.tsx new file mode 100644 index 000000000..e07c4dc22 --- /dev/null +++ b/src/components/icons/IconPassword.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +const IconPassword = () => { + return ( + + + + ) +} + +export default IconPassword diff --git a/src/components/icons/IconPasswordCross.tsx b/src/components/icons/IconPasswordCross.tsx new file mode 100644 index 000000000..d05bbd713 --- /dev/null +++ b/src/components/icons/IconPasswordCross.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +const IconPasswordCross = () => { + return ( + + + + ) +} + +export default IconPasswordCross diff --git a/src/components/icons/IconPeople.tsx b/src/components/icons/IconPeople.tsx new file mode 100644 index 000000000..0075b0f75 --- /dev/null +++ b/src/components/icons/IconPeople.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +const IconPeople = () => { + return ( + + + + ) +} + +export default IconPeople diff --git a/src/components/icons/IconTime.tsx b/src/components/icons/IconTime.tsx new file mode 100644 index 000000000..81064df9d --- /dev/null +++ b/src/components/icons/IconTime.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +const IconTime = () => { + return ( + + + + ) +} + +export default IconTime diff --git a/src/components/icons/IconVectorDown.tsx b/src/components/icons/IconVectorDown.tsx new file mode 100644 index 000000000..019fc2806 --- /dev/null +++ b/src/components/icons/IconVectorDown.tsx @@ -0,0 +1,21 @@ + + +const IconVectorDown = ({ ...props }) => { + return ( + + + + ) + } + + export default IconVectorDown \ No newline at end of file diff --git a/src/components/icons/index.ts b/src/components/icons/index.ts index 02b4947cb..1cdb56079 100644 --- a/src/components/icons/index.ts +++ b/src/components/icons/index.ts @@ -9,9 +9,17 @@ export { default as IconHome } from './IconHome' export { default as IconShopping } from './IconShopping' export { default as IconHeart } from './IconHeart' export { default as IconVector } from './IconVector' +export { default as IconVectorDown } from './IconVectorDown' export { default as IconFacebookColor } from './IconFacebookColor' export { default as IconGoogleColor } from './IconGoogleColor' export { default as IconApple } from './IconApple' export { default as ArrowLeft } from './ArrowLeft' export { default as ArrowRight } from './ArrowRight' export { default as Close } from './Close' +export { default as IconPassword } from './IconPassword' +export { default as IconPasswordCross } from './IconPasswordCross' +export { default as IconError } from './IconError' +export { default as IconCheck } from './IconCheck' +export { default as IconTime } from './IconTime' +export { default as IconPeople } from './IconPeople' +export { default as IconLocation } from './IconLocation' diff --git a/src/components/modules/home/HomeBanner/HomeBanner.module.scss b/src/components/modules/home/HomeBanner/HomeBanner.module.scss index 3f41797d0..507558cad 100644 --- a/src/components/modules/home/HomeBanner/HomeBanner.module.scss +++ b/src/components/modules/home/HomeBanner/HomeBanner.module.scss @@ -5,6 +5,7 @@ margin-bottom: 2.8rem; .left { @apply hidden; + margin-bottom: 3rem; } @screen xl { @apply grid; diff --git a/src/components/modules/home/HomeBanner/HomeBanner.tsx b/src/components/modules/home/HomeBanner/HomeBanner.tsx index 8bbf75138..2a3a632fb 100644 --- a/src/components/modules/home/HomeBanner/HomeBanner.tsx +++ b/src/components/modules/home/HomeBanner/HomeBanner.tsx @@ -2,6 +2,7 @@ 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' interface Props { className?: string @@ -13,14 +14,25 @@ const HomeBanner = ({ }: Props) => {
- Freshness
guaranteed + Freshness
guaranteed
) diff --git a/src/components/modules/home/HomeBanner/assets/banner_product.png b/src/components/modules/home/HomeBanner/assets/banner_product.png new file mode 100644 index 000000000..82f1b7fee Binary files /dev/null and b/src/components/modules/home/HomeBanner/assets/banner_product.png differ diff --git a/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.module.scss b/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.module.scss new file mode 100644 index 000000000..645ff7259 --- /dev/null +++ b/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.module.scss @@ -0,0 +1,10 @@ +@import '../../../../styles/utilities'; + +.productInfoDetail { + @apply spacing-horizontal; + padding-bottom: 4rem; + @screen md { + @apply flex; + padding-bottom: 5.6rem; + } +} \ No newline at end of file diff --git a/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx b/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx new file mode 100644 index 000000000..d1047bd3a --- /dev/null +++ b/src/components/modules/product-detail/ProductInfoDetail/ProductInfoDetail.tsx @@ -0,0 +1,20 @@ +import React from 'react' +import ProductImgs from './components/ProductImgs/ProductImgs' +import ProductInfo from './components/ProductInfo/ProductInfo' +import s from './ProductInfoDetail.module.scss' + +interface Props { + className?: string + children?: any +} + +const ProductInfoDetail = ({ }: Props) => { + return ( +
+ + +
+ ) +} + +export default ProductInfoDetail diff --git a/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgs/ProductImgs.module.scss b/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgs/ProductImgs.module.scss new file mode 100644 index 000000000..a10eb5865 --- /dev/null +++ b/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgs/ProductImgs.module.scss @@ -0,0 +1,9 @@ +.productImgs { + @apply w-full flex justify-between items-center; + @screen sm-only { + margin-bottom: 2rem; + } + @screen lg { + max-width: 60rem; + } +} diff --git a/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgs/ProductImgs.tsx b/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgs/ProductImgs.tsx new file mode 100644 index 000000000..325c6b453 --- /dev/null +++ b/src/components/modules/product-detail/ProductInfoDetail/components/ProductImgs/ProductImgs.tsx @@ -0,0 +1,40 @@ +import React from 'react' +import { CarouselCommon, ImgWithLink } from 'src/components/common' +import { ImgWithLinkProps } from 'src/components/common/ImgWithLink/ImgWithLink' +import s from './ProductImgs.module.scss' + +interface Props { + className?: string + children?: any, +} + +const DATA = [ + { + src: 'https://user-images.githubusercontent.com/76729908/130574371-3b75fa72-9552-4605-aba9-a4b31cd9dce7.png', + alt: 'Broccoli', + }, + { + src: 'https://user-images.githubusercontent.com/76729908/130574371-3b75fa72-9552-4605-aba9-a4b31cd9dce7.png', + alt: 'Broccoli', + } +] + +const option = { + slidesPerView: 1, +} + +const ProductImgs = ({ }: Props) => { + return ( +
+ + data={DATA} + itemKey="product-detail-img" + Component={ImgWithLink} + option={option} + isDot={true} + /> +
+ ) +} + +export default ProductImgs diff --git a/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.module.scss b/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.module.scss new file mode 100644 index 000000000..403782c51 --- /dev/null +++ b/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.module.scss @@ -0,0 +1,81 @@ +@import "../../../../../../styles/utilities"; + +.productInfo { + @screen md { + max-width: 39rem; + margin-left: 4.8rem; + } + @screen lg { + margin-left: 11.2rem; + } + .info { + margin-bottom: 3.2rem; + .heading { + @apply heading-2 font-heading; + margin-top: 0.8rem; + } + .price { + margin-top: 0.8rem; + .old { + margin-bottom: 0.8rem; + .number { + margin-right: 0.8rem; + color: var(--text-label); + text-decoration: line-through; + } + } + .current { + @apply text-active font-bold sm-headline; + } + } + .description { + margin-top: 0.8rem; + } + } + .actions { + @screen sm-only { + @apply fixed flex justify-between items-center bg-white w-full; + z-index: 10000; + bottom: 0; + left: 0; + padding: 2rem; + } + } + .bottom { + @screen sm-only { + @apply flex justify-between items-center flex-row-reverse; + margin-left: 1rem; + flex: 1; + button { + &:first-child { + min-width: 13rem; + } + &:nth-child(n + 1) { + margin-left: 0.8rem; + } + } + } + .buttonWithIcon { + @apply flex items-center; + .label { + @apply hidden; + @screen md { + @apply inline-block; + margin-left: 0.8rem; + } + } + } + button { + @apply w-full; + } + + @screen md { + margin-top: 2.4rem; + button { + &:first-child { + margin-bottom: 0.8rem; + } + } + } + } +} diff --git a/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx b/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx new file mode 100644 index 000000000..4abb62568 --- /dev/null +++ b/src/components/modules/product-detail/ProductInfoDetail/components/ProductInfo/ProductInfo.tsx @@ -0,0 +1,46 @@ +import React from 'react' +import { ButtonCommon, LabelCommon, QuanittyInput } from 'src/components/common' +import { IconBuy } from 'src/components/icons' +import { LANGUAGE } from 'src/utils/language.utils' +import s from './ProductInfo.module.scss' + +interface Props { + className?: string + children?: any, +} + +const ProductInfo = ({ }: Props) => { + return ( +
+
+ SEAFOOD +

SeaPAk

+
+
+ Rp 32.000 + -15% +
+
Rp 27.500
+
+
+ In a large non-reactive dish, mix together the orange juice, soy sauce, olive oil, lemon juice, parsley +
+
+
+ +
+ {/* {LANGUAGE.BUTTON_LABEL.PREORDER} */} + {LANGUAGE.BUTTON_LABEL.BUY_NOW} + + + + {LANGUAGE.BUTTON_LABEL.ADD_TO_CARD} + + +
+
+
+ ) +} + +export default ProductInfo diff --git a/src/components/modules/product-detail/RecommendedRecipes/RecommendedRecipes.module.scss b/src/components/modules/product-detail/RecommendedRecipes/RecommendedRecipes.module.scss new file mode 100644 index 000000000..d43e2d58c --- /dev/null +++ b/src/components/modules/product-detail/RecommendedRecipes/RecommendedRecipes.module.scss @@ -0,0 +1,27 @@ +@import "../../../../styles/utilities"; + +.recommendedRecipes { + margin: 6rem auto; + @screen md { + margin: 5.6rem auto; + } + .infoProducts { + @apply flex justify-between items-center spacing-horizontal; + margin-bottom: 3.2rem; + } + .productsWrap { + @apply spacing-horizontal-left; + @screen xl { + :global(.customArrow) { + @screen lg { + &:global(.leftArrow) { + left: calc(-6.4rem - 2rem); + } + &:global(.rightArrow) { + right: calc(-6.4rem - 2rem); + } + } + } + } + } +} diff --git a/src/components/modules/product-detail/RecommendedRecipes/RecommendedRecipes.tsx b/src/components/modules/product-detail/RecommendedRecipes/RecommendedRecipes.tsx new file mode 100644 index 000000000..34950fbab --- /dev/null +++ b/src/components/modules/product-detail/RecommendedRecipes/RecommendedRecipes.tsx @@ -0,0 +1,51 @@ +import { TOptionsEvents } from 'keen-slider'; +import React from 'react'; +import { CarouselCommon, HeadingCommon, RecipeCard, ViewAllItem } from 'src/components/common'; +import { RecipeCardProps } from 'src/components/common/RecipeCard/RecipeCard'; +import { ROUTE } from 'src/utils/constanst.utils'; +import s from './RecommendedRecipes.module.scss'; + +const OPTION_DEFAULT: TOptionsEvents = { + slidesPerView: 1.25, + mode: 'free', + spacing: 24, + breakpoints: { + '(min-width: 640px)': { + slidesPerView: 2, + }, + '(min-width: 1024px)': { + slidesPerView: 2.5, + }, + '(min-width: 1440px)': { + slidesPerView: 3, + }, + '(min-width: 1536px)': { + slidesPerView: 3.5, + }, + }, +} + +interface Props { + data: RecipeCardProps[], +} + +const RecommendedRecipes = ({ data }: Props) => { + return ( +
+
+ Recommended Recipes + +
+
+ + data={data} + Component={RecipeCard} + itemKey="Recommended Recipes" + option={OPTION_DEFAULT} + /> +
+
+ ); +}; + +export default RecommendedRecipes; \ No newline at end of file diff --git a/src/components/modules/product-detail/ReleventProducts/ReleventProducts.tsx b/src/components/modules/product-detail/ReleventProducts/ReleventProducts.tsx new file mode 100644 index 000000000..e11d31065 --- /dev/null +++ b/src/components/modules/product-detail/ReleventProducts/ReleventProducts.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import ListProductWithInfo from 'src/components/common/ListProductWithInfo/ListProductWithInfo'; +import { PRODUCT_DATA_TEST } from 'src/utils/demo-data'; + +const ReleventProducts = () => { + return ( + + ); +}; + +export default ReleventProducts; \ No newline at end of file diff --git a/src/components/modules/product-detail/ViewedProducts/ViewedProducts.tsx b/src/components/modules/product-detail/ViewedProducts/ViewedProducts.tsx new file mode 100644 index 000000000..820af402f --- /dev/null +++ b/src/components/modules/product-detail/ViewedProducts/ViewedProducts.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import ListProductWithInfo from 'src/components/common/ListProductWithInfo/ListProductWithInfo'; +import { PRODUCT_DATA_TEST } from 'src/utils/demo-data'; + +const ViewedProducts = () => { + return ( + + ); +}; + +export default ViewedProducts; \ No newline at end of file diff --git a/src/components/modules/product-detail/index.ts b/src/components/modules/product-detail/index.ts new file mode 100644 index 000000000..ef4461432 --- /dev/null +++ b/src/components/modules/product-detail/index.ts @@ -0,0 +1,4 @@ +export { default as ProductInfoDetail } from './ProductInfoDetail/ProductInfoDetail' +export { default as ViewedProducts } from './ViewedProducts/ViewedProducts' +export { default as ReleventProducts } from './ReleventProducts/ReleventProducts' +export { default as RecommendedRecipes } from './RecommendedRecipes/RecommendedRecipes' diff --git a/src/styles/_base.scss b/src/styles/_base.scss index 67eb96726..e90a6434f 100644 --- a/src/styles/_base.scss +++ b/src/styles/_base.scss @@ -21,7 +21,7 @@ --warning-light: #fef8eb; --negative-dark: #741a06; - --negative: #f34f2b; + --negative: #D1644D; --negative-border-line: #fddfd8; --negative-light: #feefec; @@ -79,5 +79,5 @@ html { } a { - -webkit-tap-highlight-color: var(--text-active); + -webkit-tap-highlight-color: var(--primary); } diff --git a/src/styles/_utilities.scss b/src/styles/_utilities.scss index 93291dc3a..56f9494ec 100644 --- a/src/styles/_utilities.scss +++ b/src/styles/_utilities.scss @@ -80,7 +80,7 @@ font-size: 10px; line-height: 16px; } - + .spacing-horizontal { padding-left: 2rem; padding-right: 2rem; @@ -119,4 +119,27 @@ .font-logo { font-family: var(--font-logo); } + + .u-form { + .body { + > div { + &:not(:last-child) { + margin-bottom: 1.6rem; + } + } + .line { + @apply flex justify-between items-center; + > div { + &:not(:last-child) { + margin-right: 1.6rem; + } + } + } + } + } + + .u-icon { + width: 2rem; + height: 2rem; + } } diff --git a/src/utils/constanst.utils.ts b/src/utils/constanst.utils.ts index c7002a730..c732f6ed6 100644 --- a/src/utils/constanst.utils.ts +++ b/src/utils/constanst.utils.ts @@ -10,6 +10,7 @@ export const ROUTE = { PRODUCTS: '/products', ABOUT: '/about', ACCOUNT: '/account', + RECIPES: '/recipes', BUSSINESS: '/bussiness', CONTACT: '/contact', diff --git a/src/utils/demo-data.ts b/src/utils/demo-data.ts new file mode 100644 index 000000000..b22668e15 --- /dev/null +++ b/src/utils/demo-data.ts @@ -0,0 +1,154 @@ +import { RecipeCardProps } from "src/components/common/RecipeCard/RecipeCard" + +export const PRODUCT_DATA_TEST = [ + { + name: 'Tomato', + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646211-d56b77ac-83f1-4dd2-b55c-e3f1e0ba4e49.png", + }, + { + name: 'Cucumber', + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646211-d56b77ac-83f1-4dd2-b55c-e3f1e0ba4e49.png", + }, + { + name: 'Carrot', + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646217-23b86160-45c9-4845-8dcc-b3e1a4483edd.png", + }, + { + name: 'Salad', + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646221-aaa1d48d-bb80-470f-9400-ae2aa47285b6.png", + }, + { + name: 'Tomato', + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646224-d22dc2e4-6ae8-4bbe-adcf-491ce191f09b.png", + }, + { + name: 'Cucumber', + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646225-2728f192-481b-4142-99b0-dde92f53c6c6.png", + }, + { + name: 'Tomato', + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646227-b5705e64-3b45-47a3-9433-9f4b5ee8d40c.png", + }, + { + name: 'Cucumber', + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646231-2d1c3ad1-4f5b-4a8e-9874-ca731f4ce128.png", + }, +] + +export const INGREDIENT_DATA_TEST = [ + { + name: 'Tomato', + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646211-d56b77ac-83f1-4dd2-b55c-e3f1e0ba4e49.png", + }, + { + name: 'Cucumber', + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646211-d56b77ac-83f1-4dd2-b55c-e3f1e0ba4e49.png", + isNotSell: true, + }, + { + name: 'Carrot', + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646217-23b86160-45c9-4845-8dcc-b3e1a4483edd.png", + }, + { + name: 'Salad', + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646221-aaa1d48d-bb80-470f-9400-ae2aa47285b6.png", + isNotSell: true, + }, + { + name: 'Tomato', + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646224-d22dc2e4-6ae8-4bbe-adcf-491ce191f09b.png", + }, + { + name: 'Cucumber', + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646225-2728f192-481b-4142-99b0-dde92f53c6c6.png", + }, + { + name: 'Tomato', + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646227-b5705e64-3b45-47a3-9433-9f4b5ee8d40c.png", + }, + { + name: 'Cucumber', + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646231-2d1c3ad1-4f5b-4a8e-9874-ca731f4ce128.png", + }, +] + +export const RECIPE_DATA_TEST: RecipeCardProps[] = [ + { + 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:", + imageSrc: 'https://user-images.githubusercontent.com/76729908/132159257-f92574c7-d00d-4142-8ea7-0ca9515fb737.png' + }, + { + 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...", + imageSrc: 'https://user-images.githubusercontent.com/76729908/132159259-ae4c986d-ab53-4758-9137-d06bafdd15d0.png' + }, + { + 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' + }, + { + 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:", + imageSrc: 'https://user-images.githubusercontent.com/76729908/132159257-f92574c7-d00d-4142-8ea7-0ca9515fb737.png' + }, + { + 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...", + imageSrc: 'https://user-images.githubusercontent.com/76729908/132159259-ae4c986d-ab53-4758-9137-d06bafdd15d0.png' + }, + { + 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' + }, +] \ No newline at end of file diff --git a/src/utils/language.utils.ts b/src/utils/language.utils.ts index 3f8d61926..191215aaa 100644 --- a/src/utils/language.utils.ts +++ b/src/utils/language.utils.ts @@ -2,6 +2,8 @@ export const LANGUAGE = { BUTTON_LABEL: { BUY_NOW: 'Buy now', SHOP_NOW: 'Shop now', + ADD_TO_CARD: 'Add to Cart', + PREORDER: 'Pre-Order Now', }, PLACE_HOLDER: { SEARCH: 'Search', diff --git a/src/utils/types.utils.ts b/src/utils/types.utils.ts index 2c99df73a..3d2383495 100644 --- a/src/utils/types.utils.ts +++ b/src/utils/types.utils.ts @@ -4,6 +4,7 @@ export interface ProductProps { weight: string price: string imageSrc: string + isNotSell?: boolean } export interface FeaturedProductProps { diff --git a/tailwind.config.js b/tailwind.config.js index f94c85fd8..894a7ab6e 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -49,17 +49,17 @@ module.exports = { 'background': 'var(--background)', 'white': 'var(--white)', - 'background-arrow':'var(--background-arrow)', + 'background-arrow': 'var(--background-arrow)', + - 'disabled': 'var(--text-disabled)', line: 'var(--border-line)', background: 'var(--background)', white: 'var(--white)', gray: 'var(--gray)', disabled: 'var(--text-disabled)', - 'background-arrow':'var(--background-arrow)', - + 'background-arrow': 'var(--background-arrow)', + // @deprecated (NOT use these variables) 'primary-2': 'var(--primary-2)', secondary: 'var(--secondary)', @@ -93,7 +93,7 @@ module.exports = { label: 'var(--text-label)', placeholder: 'var(--text-placeholder)', primary: 'var(--primary)', - + // @deprecated (NOT use these variables) secondary: 'var(--text-secondary)', }, @@ -109,12 +109,15 @@ module.exports = { rounded: '.8rem', }, screens: { + 'sm-only': {'min': '0', 'max': '767px'}, 'sm': '640px', // => @media (min-width: 640px) { ... } + 'md-only': {'min': '768px', 'max': '1023px'}, 'md': '768px', // => @media (min-width: 768px) { ... } + 'lg-only': {'min': '1024px', 'max': '1279px'}, 'lg': '1024px', // => @media (min-width: 1024px) { ... } @@ -124,8 +127,8 @@ module.exports = { '2xl': '1536px', // => @media (min-width: 1536px) { ... } }, - caroucel:{ - "arrow-height":"64px" + caroucel: { + "arrow-height": "64px" }, }, },