diff --git a/.gitignore b/.gitignore index 61386b73c..34232cff6 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,5 @@ yarn-error.log* # vercel .vercel + +.eslintrc diff --git a/codegen.bigcommerce.json b/codegen.bigcommerce.json deleted file mode 100644 index 1f14e88ac..000000000 --- a/codegen.bigcommerce.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "schema": { - "https://buybutton.store/graphql": { - "headers": { - "Authorization": "Bearer xzy" - } - } - }, - "documents": [ - { - "./framework/bigcommerce/api/**/*.ts": { - "noRequire": true - } - } - ], - "generates": { - "./framework/bigcommerce/schema.d.ts": { - "plugins": ["typescript", "typescript-operations"] - }, - "./framework/bigcommerce/schema.graphql": { - "plugins": ["schema-ast"] - } - }, - "hooks": { - "afterAllFileWrite": ["prettier --write"] - } -} diff --git a/next-env.d.ts b/next-env.d.ts index c6643fda1..9bc3dd46b 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,3 +1,6 @@ /// /// /// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/next.config.js b/next.config.js index ce9389fb7..27bddfae6 100644 --- a/next.config.js +++ b/next.config.js @@ -13,6 +13,16 @@ const isVendure = provider === 'vendure' module.exports = withCommerceConfig({ commerce, + typescript: { // todo: remove it + // !! WARN !! + // Dangerously allow production builds to successfully complete even if + // your project has type errors. + // !! WARN !! + ignoreBuildErrors: true, + }, + eslint: { + ignoreDuringBuilds: true, + }, images: { // todo: replace domains for images domains: ['user-images.githubusercontent.com'], @@ -42,9 +52,6 @@ module.exports = withCommerceConfig({ }, ].filter(Boolean) }, - eslint: { - ignoreDuringBuilds: true, - } }) // Don't delete this console log, useful to see the commerce config in Vercel deployments diff --git a/pages/checkout.tsx b/pages/checkout.tsx new file mode 100644 index 000000000..f2bc93517 --- /dev/null +++ b/pages/checkout.tsx @@ -0,0 +1,13 @@ +import { Layout } from 'src/components/common'; +import { CheckoutPage } from 'src/components/modules/checkout'; +import { HomeBanner, HomeCategories, HomeCollection, HomeCTA, HomeFeature, HomeRecipe, HomeSubscribe, HomeVideo } from 'src/components/modules/home'; + +export default function Checkout() { + return ( + <> + + + ) +} + +Checkout.Layout = Layout diff --git a/pages/index.tsx b/pages/index.tsx index 7d23ebadd..e7b5cab7d 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -13,7 +13,7 @@ export default function Home() { - {/* // todo: uncomment */} + {/* // todo: uncomment {/* */} ) diff --git a/pages/products.tsx b/pages/products.tsx new file mode 100644 index 000000000..ebc42d063 --- /dev/null +++ b/pages/products.tsx @@ -0,0 +1,17 @@ +import { Layout } from 'src/components/common'; +import ProductListFilter from 'src/components/modules/product-list/ProductListFilter/ProductListFilter'; +import RecipeListBanner from 'src/components/modules/recipes-list/RecipeListBanner/RecipeListBanner'; +import RecipesList from 'src/components/modules/recipes-list/RecipesList/RecipesList'; +import ProductListBanner from '../src/components/modules/product-list/ProductListBanner/ProductListBanner'; + + +export default function Products() { + return ( + <> + + + + ) +} + +Products.Layout = Layout diff --git a/src/components/common/BreadcrumbCommon/BreadcrumbCommon.tsx b/src/components/common/BreadcrumbCommon/BreadcrumbCommon.tsx index cc5733342..32ad88ab0 100644 --- a/src/components/common/BreadcrumbCommon/BreadcrumbCommon.tsx +++ b/src/components/common/BreadcrumbCommon/BreadcrumbCommon.tsx @@ -1,6 +1,7 @@ import React from 'react' import { ROUTE } from 'src/utils/constanst.utils' import s from './BreadcrumbCommon.module.scss' + import BreadcrumbItem from './components/BreadcrumbItem/BreadcrumbItem' import BreadcrumbSeparator from './components/BreadcrumbSeparator/BreadcrumbSeparator' diff --git a/src/components/common/CardItemCheckout/CardItemCheckout.module.scss b/src/components/common/CardItemCheckout/CardItemCheckout.module.scss new file mode 100644 index 000000000..3617cb91f --- /dev/null +++ b/src/components/common/CardItemCheckout/CardItemCheckout.module.scss @@ -0,0 +1,31 @@ +.warpper{ + max-height: 12rem; + padding:1.6rem 0; + @apply flex items-center; + @screen lg { + max-width: 49.9rem; + } + .image{ + width: 13.3rem; + height: 8.8rem; + margin: 0.8rem; + @apply flex justify-center items-center; + img{ + max-width: 100%; + max-height: 100%; + } + } + .right{ + width: 100%; + .name{ + color: var(--text-active); + margin-bottom: 0.5erm; + } + .quantity { + @apply flex justify-between text-label; + .price{ + color: var(--text-base); + } + } + } +} \ No newline at end of file diff --git a/src/components/common/CardItemCheckout/CardItemCheckout.tsx b/src/components/common/CardItemCheckout/CardItemCheckout.tsx new file mode 100644 index 000000000..e67057aa6 --- /dev/null +++ b/src/components/common/CardItemCheckout/CardItemCheckout.tsx @@ -0,0 +1,29 @@ +import React from 'react' +import s from "./CardItemCheckout.module.scss" +import { ProductProps } from 'src/utils/types.utils' +export interface CardItemCheckoutProps extends ProductProps { + quantity:number +} + +const CardItemCheckout = ({imageSrc,name,price,weight,quantity,category}: CardItemCheckoutProps) => { + return ( +
+
+ image +
+
+
+ {`${name} (${weight})`} +
+
+ Quantity: +
+ {`${quantity} x ${price}`} +
+
+
+
+ ) +} + +export default CardItemCheckout diff --git a/src/components/common/CheckboxCommon/CheckboxCommon.tsx b/src/components/common/CheckboxCommon/CheckboxCommon.tsx index d901f91f4..73c69bb24 100644 --- a/src/components/common/CheckboxCommon/CheckboxCommon.tsx +++ b/src/components/common/CheckboxCommon/CheckboxCommon.tsx @@ -8,9 +8,10 @@ interface CheckboxProps extends Omit< >{ onChange?: (value: boolean) => void, defaultChecked?: boolean + text?:string } -const CheckboxCommon = ({onChange,defaultChecked = true,...props}: CheckboxProps) =>{ +const CheckboxCommon = ({onChange,defaultChecked = true,text="Billing address is same as shipping", ...props}: CheckboxProps) =>{ const [value, setValue] = useState(true); @@ -31,7 +32,7 @@ const CheckboxCommon = ({onChange,defaultChecked = true,...props}: CheckboxProps
- +
) diff --git a/src/components/common/CheckoutCollapse/CheckoutCollapse.module.scss b/src/components/common/CheckoutCollapse/CheckoutCollapse.module.scss new file mode 100644 index 000000000..9e8e1f8e5 --- /dev/null +++ b/src/components/common/CheckoutCollapse/CheckoutCollapse.module.scss @@ -0,0 +1,51 @@ +.warpper{ + padding: 2.4rem 0; + @apply border-b border-solid border-line; + .note{ + font-size: 1.2rem; + line-height: 2rem; + letter-spacing: 0.01em; + color: var(--text-label); + padding: 0 5.6rem; + } + .header{ + @apply flex justify-between; + .left{ + @apply flex items-center; + .number{ + width: 3.2rem; + height: 3.2rem; + border-radius: 100%; + border: 1px solid var(--text-active); + color: var(--text-active); + @apply flex justify-center items-center font-bold; + &.visible{ + background-color: var(--text-active); + border: none; + color: var(--white); + } + &.done{ + @apply border-2 border-solid border-primary; + } + } + .title{ + padding-left: 2.4rem; + @apply font-bold select-none cursor-pointer; + color: var(--text-active); + } + } + .edit{ + @apply font-bold cursor-pointer; + text-decoration-line: underline; + margin-right: 5.6rem; + } + } + .body{ + height: 0; + @apply overflow-hidden; + &.show{ + margin-top: 3.2rem; + height: initial; + } + } +} \ No newline at end of file diff --git a/src/components/common/CheckoutCollapse/CheckoutCollapse.tsx b/src/components/common/CheckoutCollapse/CheckoutCollapse.tsx new file mode 100644 index 000000000..077b94a79 --- /dev/null +++ b/src/components/common/CheckoutCollapse/CheckoutCollapse.tsx @@ -0,0 +1,59 @@ +import classNames from 'classnames' +import { divide } from 'lodash' +import React from 'react' +import { IconDoneCheckout } from 'src/components/icons' +import { CheckOutForm } from 'src/utils/types.utils' +import s from './CheckoutCollapse.module.scss' +interface CheckoutCollapseProps { + visible: boolean + id: number + children: React.ReactNode + title: string + isEdit: boolean + onClose?: (id:number) => void + onOpen?: (id:number) => void + onEditClick?:(id:number) => void + note?:string +} + +const CheckoutCollapse = ({ + children, + id, + title, + isEdit, + visible, + note, + onOpen, + onClose, + onEditClick +}: CheckoutCollapseProps) => { + const handleTitleClick = () => { + if(visible){ + onClose && onClose(id) + }else{ + onOpen && onOpen(id) + } + } + const handleEdit = () => { + onEditClick && onEditClick(id) + } + return ( +
+
+
+
+ {isEdit?:id} +
+
+ {title} +
+
+ {isEdit &&
{'Edit'}
} +
+ {(!visible && isEdit) && (
{note}
) } +
{children}
+
+ ) +} + +export default CheckoutCollapse diff --git a/src/components/common/Header/Header.tsx b/src/components/common/Header/Header.tsx index 8bb16a10f..308c9289b 100644 --- a/src/components/common/Header/Header.tsx +++ b/src/components/common/Header/Header.tsx @@ -9,9 +9,11 @@ import HeaderMenu from './components/HeaderMenu/HeaderMenu' import HeaderSubMenu from './components/HeaderSubMenu/HeaderSubMenu' import HeaderSubMenuMobile from './components/HeaderSubMenuMobile/HeaderSubMenuMobile' import s from './Header.module.scss' +interface props { + toggleFilter:()=>void +} - -const Header = memo(() => { +const Header = memo(({toggleFilter}:props) => { const headeFullRef = useRef(null) const [isFullHeader, setIsFullHeader] = useState(true) const { visible: visibleModalAuthen, closeModal: closeModalAuthen, openModal: openModalAuthen } = useModalCommon({ initialValue: false }) @@ -43,6 +45,7 @@ const Header = memo(() => {
@@ -56,6 +59,7 @@ const Header = memo(() => { [s.show]: !isFullHeader })}>
diff --git a/src/components/common/Header/components/HeaderMenu/HeaderMenu.module.scss b/src/components/common/Header/components/HeaderMenu/HeaderMenu.module.scss index 35387094b..09f4dadbc 100644 --- a/src/components/common/Header/components/HeaderMenu/HeaderMenu.module.scss +++ b/src/components/common/Header/components/HeaderMenu/HeaderMenu.module.scss @@ -15,7 +15,16 @@ .left { .top { @apply flex justify-between items-center; + .iconGroup{ + @apply flex justify-between items-center; + } .iconCart { + margin-left: 1.6rem; + } + .iconFilter{ + @screen md { + display: none; + } } } .inputSearch { @@ -76,5 +85,10 @@ } } } + @screen xl { + .iconFilterDesk { + display:none; + } + } } } diff --git a/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx b/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx index 05e0b38fa..56b1e8ee6 100644 --- a/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx +++ b/src/components/common/Header/components/HeaderMenu/HeaderMenu.tsx @@ -3,19 +3,23 @@ import Link from 'next/link' import { memo, useMemo } from 'react' import InputSearch from 'src/components/common/InputSearch/InputSearch' import MenuDropdown from 'src/components/common/MenuDropdown/MenuDropdown' -import { IconBuy, IconHeart, IconHistory, IconUser } from 'src/components/icons' +import { IconBuy, IconFilter, IconHeart, IconHistory, IconUser } from 'src/components/icons' import { ACCOUNT_TAB, QUERY_KEY, ROUTE } from 'src/utils/constanst.utils' import Logo from '../../../Logo/Logo' import s from './HeaderMenu.module.scss' - +import { useRouter } from 'next/router' interface Props { children?: any, isFull: boolean, openModalAuthen: () => void, openModalInfo: () => void, + toggleFilter:() => void, } -const HeaderMenu = memo(({ isFull, openModalAuthen, openModalInfo }: Props) => { +const FILTER_PAGE = [ROUTE.HOME,ROUTE.PRODUCTS] + +const HeaderMenu = memo(({ isFull, openModalAuthen, openModalInfo, toggleFilter }: Props) => { + const router = useRouter() const optionMenu = useMemo(() => [ { onClick: openModalAuthen, @@ -35,15 +39,24 @@ const HeaderMenu = memo(({ isFull, openModalAuthen, openModalInfo }: Props) => { }, ], [openModalAuthen]) - return (
- +
+ { + FILTER_PAGE.includes(router.pathname) && ( + + ) + } + +
+
@@ -72,6 +85,16 @@ const HeaderMenu = memo(({ isFull, openModalAuthen, openModalInfo }: Props) => { + + { + FILTER_PAGE.includes(router.pathname) && ( +
  • + +
  • + ) + }
    ) diff --git a/src/components/common/InputCommon/InputCommon.module.scss b/src/components/common/InputCommon/InputCommon.module.scss index acfc07647..6b12d2bbd 100644 --- a/src/components/common/InputCommon/InputCommon.module.scss +++ b/src/components/common/InputCommon/InputCommon.module.scss @@ -15,9 +15,9 @@ .icon + .inputCommon { padding-left: 4.8rem; } - + .inputCommon { - @apply block w-full transition-all duration-200 rounded; + @apply block w-full transition-all duration-200 rounded bg-white; padding: 1.2rem 1.6rem; border: 1px solid var(--border-line); &:hover, diff --git a/src/components/common/InputCommon/InputCommon.tsx b/src/components/common/InputCommon/InputCommon.tsx index 943b0a632..0389c99b3 100644 --- a/src/components/common/InputCommon/InputCommon.tsx +++ b/src/components/common/InputCommon/InputCommon.tsx @@ -6,6 +6,7 @@ import s from './InputCommon.module.scss'; type Ref = { focus: () => void + getValue: () => string | number } | null; interface Props { children?: React.ReactNode, diff --git a/src/components/common/Layout/Layout.module.scss b/src/components/common/Layout/Layout.module.scss index e495667eb..30e4a077d 100644 --- a/src/components/common/Layout/Layout.module.scss +++ b/src/components/common/Layout/Layout.module.scss @@ -6,3 +6,8 @@ flex: 1; } } +.filter{ + @screen xl { + display: none; + } +} \ No newline at end of file diff --git a/src/components/common/Layout/Layout.tsx b/src/components/common/Layout/Layout.tsx index a808c33ff..204956fbd 100644 --- a/src/components/common/Layout/Layout.tsx +++ b/src/components/common/Layout/Layout.tsx @@ -1,10 +1,13 @@ import { CommerceProvider } from '@framework' import { useRouter } from 'next/router' import { FC } from 'react' +import { FilterProvider } from 'src/components/contexts/FilterContext' import { useModalCommon } from 'src/components/hooks' +import { BRAND, CATEGORY, FEATURED } from 'src/utils/constanst.utils' import { CartDrawer, CustomShapeSvg } from '..' import Footer from '../Footer/Footer' import Header from '../Header/Header' +import MenuNavigationProductList from '../MenuNavigationProductList/MenuNavigationProductList' import s from './Layout.module.scss' interface Props { @@ -16,6 +19,7 @@ interface Props { const Layout: FC = ({ children }) => { const { locale = 'en-US' } = useRouter() const { visible: visibleCartDrawer, openModal, closeModal: closeCartDrawer } = useModalCommon({ initialValue: false }) + const { visible: visibleFilter, openModal: openFilter, closeModal: closeFilter } = useModalCommon({ initialValue: false }) const toggle = () => { if (visibleCartDrawer) { @@ -24,18 +28,27 @@ const Layout: FC = ({ children }) => { openModal() } } + const toggleFilter = () => { + console.log("click") + if (visibleFilter) { + closeFilter() + } else { + openFilter() + } + } return ( -
    -
    -
    {children}
    - - - -
    -
    +
    +
    +
    {children}
    + + + +
    +
    +
    ) diff --git a/src/components/common/MenuFilter/MenuFilter.module.scss b/src/components/common/MenuFilter/MenuFilter.module.scss index c0810c4bd..87a792297 100644 --- a/src/components/common/MenuFilter/MenuFilter.module.scss +++ b/src/components/common/MenuFilter/MenuFilter.module.scss @@ -1,9 +1,7 @@ @import "../../../styles/utilities"; .menuFilterWrapper{ @apply spacing-horizontal; - @screen md { - @apply hidden; - } + .menuFilterHeading{ @apply sub-headline font-bold ; color: var(--text-active); diff --git a/src/components/common/MenuNavigationProductList/MenuNavigationProductList.module.scss b/src/components/common/MenuNavigationProductList/MenuNavigationProductList.module.scss index 3eeda052c..042785c05 100644 --- a/src/components/common/MenuNavigationProductList/MenuNavigationProductList.module.scss +++ b/src/components/common/MenuNavigationProductList/MenuNavigationProductList.module.scss @@ -1,18 +1,17 @@ @import "../../../styles/utilities"; .menuNavigationProductListDesktop{ - @screen sm-only { + @screen sm { @apply hidden; } + + @screen xl { + @apply block; + } } .menuNavigationProductListMobile{ @apply relative transition-all duration-100; - @screen md{ - @apply hidden; - } - @screen xl{ - @apply hidden; - } + &.isShow{ &::after{ content: ""; diff --git a/src/components/common/MenuNavigationProductList/MenuSort/MenuSort.module.scss b/src/components/common/MenuNavigationProductList/MenuSort/MenuSort.module.scss index be232308a..19bd605f8 100644 --- a/src/components/common/MenuNavigationProductList/MenuSort/MenuSort.module.scss +++ b/src/components/common/MenuNavigationProductList/MenuSort/MenuSort.module.scss @@ -1,9 +1,7 @@ @import "../../../../styles/utilities"; .menuSortWrapper{ @apply spacing-horizontal; - @screen md { - @apply hidden; - } + .menuSortHeading{ @apply sub-headline font-bold ; color: var(--text-active); diff --git a/src/components/common/ModalCommon/ModalCommon.tsx b/src/components/common/ModalCommon/ModalCommon.tsx index 75222c162..7f9bc07d8 100644 --- a/src/components/common/ModalCommon/ModalCommon.tsx +++ b/src/components/common/ModalCommon/ModalCommon.tsx @@ -1,6 +1,6 @@ import React, { useRef } from 'react' import { Close } from 'src/components/icons' -import { useOnClickOutside } from 'src/utils/useClickOutSide' +import { useOnClickOutside } from 'src/components/hooks/useClickOutSide' import s from './ModalCommon.module.scss' export interface ModalCommonProps { onClose: () => void diff --git a/src/components/common/TabCommon/TabCommon.module.scss b/src/components/common/TabCommon/TabCommon.module.scss index 9e5fbc1df..d8b5d0f9a 100644 --- a/src/components/common/TabCommon/TabCommon.module.scss +++ b/src/components/common/TabCommon/TabCommon.module.scss @@ -1,15 +1,28 @@ + @import '../../../styles/utilities'; - -.tabCommonOutSide { - @apply spacing-horizontal; - - .tabCommon { +.tabWapper{ + @apply flex flex-col w-full; + .tabHeader{ @apply flex; - position: relative; - border-bottom: 2px solid #FBFBFB; - padding-top: 1.6rem; - padding-bottom: 1.6rem; - width: 100%; + .tabList { + @apply flex; + position: relative; + border-bottom: 2px solid #FBFBFB; + padding: 0.8rem 0; + &.center{ + margin: auto; + } + + .slider { + @apply inline-block; + height: .2rem; + border-radius: 3px; + background-color: var(--primary); + position: absolute; + z-index: 1200; + bottom: 0; + transition: all .25s linear; + } + } } } - diff --git a/src/components/common/TabCommon/TabCommon.tsx b/src/components/common/TabCommon/TabCommon.tsx index d07cf06e8..7214361f7 100644 --- a/src/components/common/TabCommon/TabCommon.tsx +++ b/src/components/common/TabCommon/TabCommon.tsx @@ -1,47 +1,85 @@ -import React, { useState } from "react" -import s from './TabCommon.module.scss' - -import TabItem from './TabItem/TabItem' - -interface TabCommonProps { - -} - -const TabCommon = ({ } : TabCommonProps) => { - const active = "active", unActive = ""; - - const [item1Active, setItem1Active] = useState(active); - const [item2Active, setItem2Active] = useState(unActive); - const [item3Active, setItem3Active] = useState(unActive); - - function toggleItem1():void { - setItem1Active(active) - - setItem2Active(unActive) - setItem3Active(unActive) +import React, { + Children, + PropsWithChildren, + ReactElement, + useEffect, + useRef, + useState, + cloneElement, + } from 'react' + import s from './TabCommon.module.scss' + + import TabItem from './components/TabItem/TabItem' + import { TabPaneProps } from './components/TabPane/TabPane' + import classNames from 'classnames' + + interface TabCommonProps { + defaultActiveTab?: number + children: React.ReactNode + center?:boolean + } + + const TabCommon = ({ + defaultActiveTab = 0, + children, + center + }: TabCommonProps) => { + const [active, setActive] = useState(0) + const slider = useRef(null) + const headerRef = useRef(null) + useEffect(() => { + setActive(defaultActiveTab) + }, []) + + useEffect(() => { + slide(active) + }, [active]) + + function slide(index: number) { + const active = headerRef.current?.children + .item(index) + ?.getBoundingClientRect() + const header = headerRef.current?.getBoundingClientRect() + const current = slider.current + if (current && active && header) { + let width = active.width - 24 <= 0 ? 24 : active.width - 24 + let left = active.left - header.left + current.style.width = width.toString() + 'px' + current.style.left = left.toString() + 'px' + } } - function toggleItem2():void { - setItem2Active(active) - - setItem1Active(unActive) - setItem3Active(unActive) + const onTabClick = (index: number) => { + setActive(index) } - function toggleItem3():void { - setItem3Active(active) - - setItem1Active(unActive) - setItem2Active(unActive) - } - return ( -
    -
    - Wait for Comfirmation - Delivering - Delivered -
    -
    +
    +
    +
      + {Children.map(children, (tab, index) => { + let item = tab as ReactElement> + return ( +
    • + + {item.props.tabName} + +
    • + ) + })} +
      +
    +
    +
    + {Children.map(children, (tab, index) => { + let item = tab as ReactElement> + return cloneElement(item, { active:index===active }); + }) + }
    +
    ) -} - -export default TabCommon; \ No newline at end of file + } + + export default TabCommon diff --git a/src/components/common/TabCommon/TabItem/TabItem.module.scss b/src/components/common/TabCommon/TabItem/TabItem.module.scss index efb10f1f4..bdbb0b66a 100644 --- a/src/components/common/TabCommon/TabItem/TabItem.module.scss +++ b/src/components/common/TabCommon/TabItem/TabItem.module.scss @@ -5,10 +5,16 @@ padding-top: 1.6rem; padding-bottom: 1.6rem; - &.active { - @apply font-bold; - border-bottom: 2px solid var(--primary); + &:hover { + @apply cursor-pointer; } +} + +.tabItemActive { + @apply font-bold; + margin-right: 4.8rem; + padding-top: 1.6rem; + padding-bottom: 1.6rem; &:hover { @apply cursor-pointer; diff --git a/src/components/common/TabCommon/TabItem/TabItem.tsx b/src/components/common/TabCommon/TabItem/TabItem.tsx index a889ee68b..ab9eb69f9 100644 --- a/src/components/common/TabCommon/TabItem/TabItem.tsx +++ b/src/components/common/TabCommon/TabItem/TabItem.tsx @@ -1,18 +1,16 @@ -import classNames from "classnames"; import React from "react" import s from './TabItem.module.scss' interface TabItemProps { - active: string; - target?: string; - children?: string; + active: boolean; + children: string; + onClick: (tabIndex: number, tabPane?: string) => void; } -const TabItem = ({ active = "", children } : TabItemProps) => { +const TabItem = ({ active = false, children, onClick } : TabItemProps) => { + return ( - + {children} ) diff --git a/src/components/common/TabCommon/components/TabItem/TabItem.module.scss b/src/components/common/TabCommon/components/TabItem/TabItem.module.scss new file mode 100644 index 000000000..159a38f57 --- /dev/null +++ b/src/components/common/TabCommon/components/TabItem/TabItem.module.scss @@ -0,0 +1,13 @@ +@import '../../../../../styles/utilities'; + +.tabItem { + margin-right:2.4rem; + padding: 0.8rem 0; + min-width: 2.4rem; + &:hover { + @apply cursor-pointer; + } + &.tabItemActive { + @apply font-bold; + } +} diff --git a/src/components/common/TabCommon/components/TabItem/TabItem.tsx b/src/components/common/TabCommon/components/TabItem/TabItem.tsx new file mode 100644 index 000000000..cc1737e44 --- /dev/null +++ b/src/components/common/TabCommon/components/TabItem/TabItem.tsx @@ -0,0 +1,39 @@ +import classNames from 'classnames' +<<<<<<< HEAD +import React, { RefObject, useRef } from 'react' +======= +import React from 'react' +>>>>>>> 88f90912429447f6ae7bafa77484465965e0ee13 +import s from './TabItem.module.scss' + +interface TabItemProps { + active: boolean + children: string + onClick?: (tabIndex: number) => void + tabIndex: number +} + +const TabItem = ({ + active = false, + children, + onClick, + tabIndex, +}: TabItemProps) => { + const handleClick = () => { + onClick && onClick(tabIndex) + } + return ( + + {children} + + ) +} + +<<<<<<< HEAD +export default TabItem +======= +export default TabItem +>>>>>>> 88f90912429447f6ae7bafa77484465965e0ee13 diff --git a/src/components/common/TabCommon/components/TabPane/TabPane.module.scss b/src/components/common/TabCommon/components/TabPane/TabPane.module.scss new file mode 100644 index 000000000..380472828 --- /dev/null +++ b/src/components/common/TabCommon/components/TabPane/TabPane.module.scss @@ -0,0 +1,23 @@ +@import "../../../../../styles/utilities"; +.tabPane { + @apply hidden; + transition: all 0.6s; + // animation-duration: 0.6s; + // animation-name: appear; + // @keyframes appear { + // from { + // margin-left: 100%; + // width: 200%; + // } + + // to { + // margin-left: 0%; + // width: 100%; + // } + // } + + + &.active { + @apply block; + } +} \ No newline at end of file diff --git a/src/components/common/TabCommon/components/TabPane/TabPane.tsx b/src/components/common/TabCommon/components/TabPane/TabPane.tsx new file mode 100644 index 000000000..c0c7d2efa --- /dev/null +++ b/src/components/common/TabCommon/components/TabPane/TabPane.tsx @@ -0,0 +1,21 @@ +import classNames from "classnames" +import React from "react" +import s from './TabPane.module.scss' + +export interface TabPaneProps { + active?: boolean; + children?: React.ReactNode; + tabName: string +} + +const TabPane = ({ active, children } : TabPaneProps) => { + return ( +
    + {children} +
    + ) +} + +export default TabPane \ No newline at end of file diff --git a/src/components/common/index.ts b/src/components/common/index.ts index 5b821317f..7de333d3a 100644 --- a/src/components/common/index.ts +++ b/src/components/common/index.ts @@ -32,6 +32,7 @@ export { default as ModalConfirm} from "./ModalConfirm/ModalConfirm" export { default as ModalInfo} from "./ModalInfo/ModalInfo" export { default as ProductList} from "./ProductList/ProductList" export { default as ModalCreateUserInfo} from './ModalCreateUserInfo/ModalCreateUserInfo' +export { default as CardItemCheckout} from './CardItemCheckout/CardItemCheckout' export { default as CardBlog} from './CardBlog/CardBlog' export { default as RelevantBlogPosts} from './RelevantBlogPosts/RelevantBlogPosts' export { default as CollapseCommon} from './CollapseCommon/CollapseCommon' @@ -40,6 +41,8 @@ export { default as ImgWithLink} from './ImgWithLink/ImgWithLink' export { default as RecipeDetail} from './RecipeDetail/RecipeDetail' export { default as DrawerCommon} from './DrawerCommon/DrawerCommon' export { default as CartDrawer} from './CartDrawer/CartDrawer' +export { default as TabPane} from './TabCommon/components/TabPane/TabPane' +export { default as TabCommon} from './TabCommon/TabCommon' export { default as StaticImage} from './StaticImage/StaticImage' export { default as EmptyCommon} from './EmptyCommon/EmptyCommon' export { default as CustomShapeSvg} from './CustomShapeSvg/CustomShapeSvg' diff --git a/src/components/contexts/FilterContext.tsx b/src/components/contexts/FilterContext.tsx new file mode 100644 index 000000000..36a10ce9f --- /dev/null +++ b/src/components/contexts/FilterContext.tsx @@ -0,0 +1,43 @@ +import { createContext, ReactNode, useContext, useState } from "react"; +import { filterContextType } from "src/utils/types.utils"; + +const contextDefaultValues: filterContextType = { + visible: false, + open: () => {}, + close: () => {}, +}; + +const FilterContext = createContext(contextDefaultValues); + +export function useAuth() { + return useContext(FilterContext); +} + +type FilterProviderProps = { + children: ReactNode; +}; + +export function FilterProvider({ children }: FilterProviderProps) { + const [visible, setVisible] = useState(false); + + const open = () => { + setVisible(true); + }; + + const close = () => { + setVisible(false); + }; + + const value = { + visible, + open, + close, + }; + return ( + <> + + {children} + + + ); +} \ No newline at end of file diff --git a/src/utils/useClickOutSide.ts b/src/components/hooks/useClickOutSide.ts similarity index 92% rename from src/utils/useClickOutSide.ts rename to src/components/hooks/useClickOutSide.ts index d68e742fb..ff69007a8 100644 --- a/src/utils/useClickOutSide.ts +++ b/src/components/hooks/useClickOutSide.ts @@ -1,5 +1,5 @@ import { RefObject, useEffect } from 'react' -import { MouseAndTouchEvent } from './types.utils' +import { MouseAndTouchEvent } from '../../utils/types.utils' export function useOnClickOutside( ref: RefObject, diff --git a/src/components/icons/IconCirclePlus.tsx b/src/components/icons/IconCirclePlus.tsx new file mode 100644 index 000000000..c59766d89 --- /dev/null +++ b/src/components/icons/IconCirclePlus.tsx @@ -0,0 +1,20 @@ +import React from 'react' + +const IconCirclePlus = () => { + return ( + + + + ) +} + +export default IconCirclePlus diff --git a/src/components/icons/IconDoneCheckout.tsx b/src/components/icons/IconDoneCheckout.tsx new file mode 100644 index 000000000..418472d23 --- /dev/null +++ b/src/components/icons/IconDoneCheckout.tsx @@ -0,0 +1,20 @@ +import React from 'react' + +const IconDoneCheckout = () => { + return ( + + + + ) +} + +export default IconDoneCheckout diff --git a/src/components/icons/IconFilter.tsx b/src/components/icons/IconFilter.tsx new file mode 100644 index 000000000..2c06b9139 --- /dev/null +++ b/src/components/icons/IconFilter.tsx @@ -0,0 +1,22 @@ +import React from 'react' + +interface Props {} + +const IconFilter = (props: Props) => { + return ( + + + + ) +} + +export default IconFilter diff --git a/src/components/icons/Shipping.tsx b/src/components/icons/Shipping.tsx new file mode 100644 index 000000000..2288c142c --- /dev/null +++ b/src/components/icons/Shipping.tsx @@ -0,0 +1,20 @@ +import React from 'react' + +const Shipping = () => { + return ( + + + + ) +} + +export default Shipping diff --git a/src/components/icons/index.ts b/src/components/icons/index.ts index 477d8863c..7dd36b14f 100644 --- a/src/components/icons/index.ts +++ b/src/components/icons/index.ts @@ -22,10 +22,14 @@ 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 Shipping} from './Shipping' export { default as IconTime } from './IconTime' export { default as IconPeople } from './IconPeople' export { default as IconLocation } from './IconLocation' export { default as IconClose } from './IconClose' export { default as IconDelete } from './IconDelete' export { default as IconPlus } from './IconPlus' -export { default as IconMinus } from './IconMinus' \ No newline at end of file +export { default as IconMinus } from './IconMinus' +export { default as IconCirclePlus } from './IconCirclePlus' +export { default as IconDoneCheckout } from './IconDoneCheckout' +export { default as IconFilter } from './IconFilter' diff --git a/src/components/modules/account/AccountNavigation/AccountNavigation.module.scss b/src/components/modules/account/AccountNavigation/AccountNavigation.module.scss index 22c885238..8bece6668 100644 --- a/src/components/modules/account/AccountNavigation/AccountNavigation.module.scss +++ b/src/components/modules/account/AccountNavigation/AccountNavigation.module.scss @@ -1,5 +1,27 @@ @import '../../../../styles/utilities'; .accountNavigation { - @apply spacing-horizontal; + @apply flex; + width: 100%; + + .slider { + @apply inline-block; + width: 0.2rem; + height: 4.8rem; + border-radius: 3px; + background-color: var(--primary); + position: absolute; + left: 11.2rem; + transition: all .2s linear; + } + + .tabList { + margin-top: 3.8rem; + margin-right: 12.4rem; + } + + .tabBody { + margin-top: -4.7rem; + width: 100%; + } } \ No newline at end of file diff --git a/src/components/modules/account/AccountNavigation/AccountNavigation.tsx b/src/components/modules/account/AccountNavigation/AccountNavigation.tsx index fd289edc9..929f386f2 100644 --- a/src/components/modules/account/AccountNavigation/AccountNavigation.tsx +++ b/src/components/modules/account/AccountNavigation/AccountNavigation.tsx @@ -1,48 +1,69 @@ -import React, { useState } from "react" +import React, { useRef, useEffect, Children, ReactElement, PropsWithChildren, useState, cloneElement } from "react" import s from './AccountNavigation.module.scss' -import AccountNavigationItem from './components/AccountNavigationItem' +import AccountNavigationItem from './components/AccountNavigationItem/AccountNavigationItem' +import {TabPaneProps} from '../../../common/TabCommon/components/TabPane/TabPane' interface AccountNavigationProps { - + defaultActiveIndex: number; + children: React.ReactNode } -const AccountNavigation = ({ } : AccountNavigationProps) => { - const active = "active", unActive = ""; +const AccountNavigation = ({ defaultActiveIndex, children } : AccountNavigationProps) => { + const [active, setActive] = useState(defaultActiveIndex) + const sliderRef = useRef(null); + const headerRef = useRef(null) - const [item1Active, setItem1Active] = useState(active); - const [item2Active, setItem2Active] = useState(unActive); - const [item3Active, setItem3Active] = useState(unActive); - - function toggleItem1():void { - setItem1Active(active) - - setItem2Active(unActive) - setItem3Active(unActive) + const onTabClick = (index: number) => { + setActive(index) } - function toggleItem2():void { - setItem2Active(active) - setItem1Active(unActive) - setItem3Active(unActive) - } - function toggleItem3():void { - setItem3Active(active) + function slide(index: number) { + const active = headerRef.current?.children.item(index)?.getBoundingClientRect() + const header = headerRef.current?.getBoundingClientRect() + const current = sliderRef.current - setItem1Active(unActive) - setItem2Active(unActive) + if (current && active && header) { + const top = active.top; + current.style.top = top.toString()+"px"; + } } + + useEffect(() => { + slide(active); + }, [active]) + return (
    -
    - Customer Information -
    -
    - Your Orders -
    -
    - Favourites +
      + { + Children.map(children, (tab, index) => { + let item = tab as ReactElement> + return ( +
    • + + {item.props.tabName} + +
    • + ) + }) + } +
      +
    + +
    + { + Children.map(children, (tab, index) => { + let item = tab as ReactElement> + return cloneElement(item, { active: index === active }); + }) + }
    +
    ) } diff --git a/src/components/modules/account/AccountNavigation/components/AccountNavigationItem.module.scss b/src/components/modules/account/AccountNavigation/components/AccountNavigationItem.module.scss index 01fc0e1cc..12d3e1f02 100644 --- a/src/components/modules/account/AccountNavigation/components/AccountNavigationItem.module.scss +++ b/src/components/modules/account/AccountNavigation/components/AccountNavigationItem.module.scss @@ -1,7 +1,6 @@ -@import '../../../../../styles/utilities'; +@import '../../../../../../styles/utilities'; .accountNavigationItem { - @apply bg-gray; width: 28rem; padding: 1.2rem 0 1.2rem 1.6rem; margin-bottom: 1.2rem; @@ -14,6 +13,5 @@ &.active { background-color: #FBFBFB; border-radius: 0 1.6rem 1.6rem 0; - border-left: 2px solid var(--primary); } } \ No newline at end of file diff --git a/src/components/modules/account/AccountNavigation/components/AccountNavigationItem.tsx b/src/components/modules/account/AccountNavigation/components/AccountNavigationItem.tsx index 47cd537f0..9ac8a387f 100644 --- a/src/components/modules/account/AccountNavigation/components/AccountNavigationItem.tsx +++ b/src/components/modules/account/AccountNavigation/components/AccountNavigationItem.tsx @@ -1,17 +1,22 @@ -import React from "react"; +import React, { RefObject } from "react"; import classNames from "classnames"; import s from './AccountNavigationItem.module.scss' interface AccountNavigationItemProps { children?: string; - active?: string; - target?: string; + active?: boolean; + tabIndex: number + onClick: (index: number) => void; } -const AccountNavigationItem = ({ children, active="" } : AccountNavigationItemProps) => { +const AccountNavigationItem = ({ children, active, tabIndex, onClick } : AccountNavigationItemProps) => { + + const handleClick = () => { + onClick(tabIndex) + } return ( -
    {children}
    diff --git a/src/components/modules/account/AccountPage/AccountPage.module.scss b/src/components/modules/account/AccountPage/AccountPage.module.scss new file mode 100644 index 000000000..3f8307750 --- /dev/null +++ b/src/components/modules/account/AccountPage/AccountPage.module.scss @@ -0,0 +1,26 @@ +@import '../../../../styles/utilities'; + +.accountPage { + @apply spacing-horizontal; + background-color: #F5F4F2; + margin-top: -3.2rem; + padding-top: 3.2rem; + padding-bottom: 3.2rem; + + @screen md { + padding-left: 3.2rem; + padding-right: 3.2rem; + } + + @screen xl { + @apply spacing-horizontal + } + + .header { + margin-bottom: 1.2rem; + + @screen md { + margin-bottom: 3.8rem; + } + } +} \ No newline at end of file diff --git a/src/components/modules/account/AccountPage/AccountPage.tsx b/src/components/modules/account/AccountPage/AccountPage.tsx new file mode 100644 index 000000000..a5a0ef79d --- /dev/null +++ b/src/components/modules/account/AccountPage/AccountPage.tsx @@ -0,0 +1,86 @@ +import React, { useState } from "react" +import s from './AccountPage.module.scss' + +import AccountNavigation from '../AccountNavigation/AccountNavigation' +import HeadingCommon from '../../../common/HeadingCommon/HeadingCommon' +import AccountInfomation from "./components/AccountInfomation/AccountInfomation" +import OrderInfomation from './components/OrderInformation/OrderInformation' +import EditInfoModal from './components/EditInfoModal/EditInfoModal' +import TabPane from "src/components/common/TabCommon/components/TabPane/TabPane" + +const waiting = [ + { + id: "NO 123456", + products: ["Tomato", "Fish", "Pork", "Onion"], + totalPrice : 1000 + } +] + +const delivering = [ + { + id: "NO 123456", + products: ["Tomato", "Fish", "Pork", "Onion", "Tomato", "Fish", "Pork", "Onion"], + totalPrice : 1000 + } +] + +const delivered = [ + { + id: "NO 123456", + products: ["Tomato", "Fish", "Pork", "Onion", "Tomato", "Fish", "Pork", "Onion"], + totalPrice : 1000 + } +] + +let account = { + name: "vu duong", + email: "vuduong@gmail.com", + address: "234 Dien Bien Phu Bis, Dakao ward", + state: "District 1", + city: "HCMC", + postalCode: "700000", + phoneNumber: "(+84) 937 937 195" +} + +interface AccountPageProps { + defaultActiveContent?: "info" | "orders" | "favorites" +} + +const AccountPage = ({defaultActiveContent="orders"} : AccountPageProps) => { + + const [activeTab] = useState(defaultActiveContent==="info" ? 0 : defaultActiveContent==="orders" ? 1 : 2) + const [modalVisible, setModalVisible] = useState(false); + + function showModal() { + setModalVisible(true); + } + + function closeModal() { + setModalVisible(false); + } + + return ( + <> +
    +
    + Account +
    + + + + + + + + + + {/* */} + + +
    + + + ) +} + +export default AccountPage \ No newline at end of file diff --git a/src/components/modules/account/AccountPage/assets/avatar.png b/src/components/modules/account/AccountPage/assets/avatar.png new file mode 100644 index 000000000..b12cabed4 Binary files /dev/null and b/src/components/modules/account/AccountPage/assets/avatar.png differ diff --git a/src/components/modules/account/AccountPage/components/AccountInfomation/AccountInfomation.module.scss b/src/components/modules/account/AccountPage/components/AccountInfomation/AccountInfomation.module.scss new file mode 100644 index 000000000..442dae2eb --- /dev/null +++ b/src/components/modules/account/AccountPage/components/AccountInfomation/AccountInfomation.module.scss @@ -0,0 +1,67 @@ +@import '../../../../../../styles/utilities'; + +.accountInfomation { + @apply flex justify-center items-center; + text-align: center; + margin-top: 1.6rem; + + @screen md { + @apply block; + text-align: left; + margin-top: 0; + } + + .avatar { + height: 22rem; + width: 22rem; + border-radius: 50%; + margin: auto; + margin-bottom: 4rem; + + + @screen md { + margin-left: 0 + } + } + + .accountName { + @apply heading-3 font-heading; + } + + .horizontalSeparator{ + border: 1px solid var(--disabled); + max-width: 39.2rem; + min-width: 30rem; + margin-top: 2.4rem; + margin-bottom: 2.4rem; + } + + .shippingInfo { + @apply heading-3 font-heading; + } + + .accountAddress { + max-width: 31rem; + min-width: none; + } + + .editInfoBtn { + @apply text-center font-bold custom-border-radius; + margin: auto; + margin-top: 2.4rem; + margin-bottom: 2.4rem; + padding: .8rem 1.6rem; + color: #141414; + border: 1px solid #141414; + max-width: 8.8rem; + + &:hover { + @apply cursor-pointer; + background-color: #FBFBFB; + } + + @screen md { + margin-left: 0; + } + } +} \ No newline at end of file diff --git a/src/components/modules/account/AccountPage/components/AccountInfomation/AccountInfomation.tsx b/src/components/modules/account/AccountPage/components/AccountInfomation/AccountInfomation.tsx new file mode 100644 index 000000000..f24b36216 --- /dev/null +++ b/src/components/modules/account/AccountPage/components/AccountInfomation/AccountInfomation.tsx @@ -0,0 +1,56 @@ +import React from "react" +import s from './AccountInfomation.module.scss' + +import Image from "next/image" +import avatar from '../../assets/avatar.png'; + +interface AccountProps { + name: string, email: string, address: string, state: string, city: string, postalCode: string, phoneNumber: string +} + +interface AccountInfomationProps { + account: AccountProps; + onClick: () => void; +} + +const AccountInfomation = ({ account, onClick } : AccountInfomationProps) => { + + // need to handle call back when edit account information + + const showEditForm = () => onClick() + + return ( +
    + { +
    +
    + avatar +
    + +
    + {account.name} +
    +
    + {account.email} +
    + +
    + +
    Shipping Infomation
    + +
    + {account.address + `, ${account.state}, ${account.city}, ${account.postalCode}`} +
    + +
    + {account.phoneNumber} +
    + +
    Edit
    +
    + } +
    + ) +} + +export default AccountInfomation \ No newline at end of file diff --git a/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.module.scss b/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.module.scss new file mode 100644 index 000000000..be1384ab7 --- /dev/null +++ b/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.module.scss @@ -0,0 +1,81 @@ +@import '../../../../../../styles/utilities'; + +.editInfoModal { + .input { + @apply bg-white; + margin-bottom: 1.6rem; + width: 100%; + border: 2px solid #EBEBEB; + border-radius: .8rem; + padding: 1.6rem; + } + + .inputDisable { + margin-bottom: 1.6rem; + width: 100%; + border: 2px solid #EBEBEB; + border-radius: .8rem; + padding: 1.6rem; + background-color: #EBEBEB; + color: #CCCCCC; + } + + .inputStateWrapper { + @apply bg-white; + margin-bottom: 1.6rem; + margin-right: 1.6rem; + border: 2px solid #EBEBEB; + border-radius: .8rem; + padding: 1.6rem; + + .inputState { + @apply bg-white cursor-pointer; + border: white; + } + } + + .inputPostalCode { + @apply bg-white; + margin-bottom: 1.6rem; + border: 2px solid #EBEBEB; + border-radius: .8rem; + padding: 1.6rem; + } + + .inputPhoneNumber { + @apply bg-white; + margin-bottom: 4rem; + width: 100%; + border: 2px solid #EBEBEB; + border-radius: .8rem; + padding: 1.6rem; + } + + .buttons { + @apply flex; + + .buttonCancel { + @apply bg-white text-center font-bold custom-border-radius-lg; + color: #141414; + border: 1px solid #141414; + padding: 1.6rem; + margin-right: 1.6rem; + width: 100%; + + &:hover { + @apply cursor-pointer; + } + } + + .buttonSave { + @apply text-center font-bold custom-border-radius-lg; + background-color: var(--primary); + color: white; + padding: 1.6rem; + width: 100%; + &:hover { + @apply cursor-pointer; + } + } + } +} \ No newline at end of file diff --git a/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx b/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx new file mode 100644 index 000000000..d2be8b1a1 --- /dev/null +++ b/src/components/modules/account/AccountPage/components/EditInfoModal/EditInfoModal.tsx @@ -0,0 +1,83 @@ +import classNames from "classnames" +import React, { useState } from "react" +import s from './EditInfoModal.module.scss' + +import {ModalCommon, MenuDropdown} from '../../../../../common' + +import {ButtonCommon} from '../../../../../common' + +interface EditInfoModalProps { + accountInfo: {name: string, email: string, address: string, state: string, city: string, postalCode: string, phoneNumber: string}; + visible: boolean; + closeModal: () => void; +} + +const EditInfoModal = ({ accountInfo, visible = false, closeModal }: EditInfoModalProps) => { + + const [name, setName] = useState(accountInfo.name); + const [email, setEmail] = useState(accountInfo.email); + const [address, setAddress] = useState(accountInfo.address); + const [state, setState] = useState(accountInfo.state); + const [city, setCity] = useState(accountInfo.city); + const [postalCode, setPostalCode] = useState(accountInfo.postalCode); + const [phoneNumber, setPhoneNumber] = useState(accountInfo.phoneNumber); + + function saveInfo() { + console.log("saved !!!"); + + closeModal(); + } + + const states = [ + {name: "D1", onClick: () => {setState("D1")}}, + {name: "D2", onClick: () => {setState("D2")}}, + {name: "D3", onClick: () => {setState("D3")}} + ] + + return ( + +
    +
    + {setName(e.target.value)}} /> +
    +
    + {setEmail(e.target.value)}} /> +
    +
    + {setAddress(e.target.value)}}/> +
    +
    + {setCity(e.target.value)}} /> +
    + +
    +
    + + + +
    + + {setPostalCode(e.target.value)}} /> +
    + +
    + {setPhoneNumber(e.target.value)}} /> +
    + +
    +
    Cancel
    +
    Save
    +
    +
    +
    + ) +} + +export default EditInfoModal \ No newline at end of file diff --git a/src/components/modules/account/AccountPage/components/OrderInformation/OrderInformation.module.scss b/src/components/modules/account/AccountPage/components/OrderInformation/OrderInformation.module.scss new file mode 100644 index 000000000..0096a67d7 --- /dev/null +++ b/src/components/modules/account/AccountPage/components/OrderInformation/OrderInformation.module.scss @@ -0,0 +1,16 @@ +@import '../../../../../../styles/utilities'; + +.orderInformation { + .title { + @apply heading-3 font-heading; + margin-top: 1.6rem; + } + + .tabs { + margin-top: 3.2rem; + + .blank { + margin-bottom: 2.4rem; + } + } +} \ No newline at end of file diff --git a/src/components/modules/account/AccountPage/components/OrderInformation/OrderInformation.tsx b/src/components/modules/account/AccountPage/components/OrderInformation/OrderInformation.tsx new file mode 100644 index 000000000..76985b9fd --- /dev/null +++ b/src/components/modules/account/AccountPage/components/OrderInformation/OrderInformation.tsx @@ -0,0 +1,66 @@ +import React from "react" +import s from './OrderInformation.module.scss' + +import { TabCommon } from '../../../../../common' +import TabPane from 'src/components/common/TabCommon/components/TabPane/TabPane' +import DeliveryItem from '../../../DeliveryItem/DeliveryItem' + + +interface OrderInformationProps { + waiting: {id: string, products: string[], totalPrice: number}[], + delivering: {id: string, products: string[], totalPrice: number}[], + delivered: {id: string, products: string[], totalPrice: number}[], + // active?: boolean +} + +const OrderInformation = ({ waiting, delivering, delivered} : OrderInformationProps) => { + + return ( +
    + { +
    +
    Order Information
    + +
    + + +
    + { + waiting.map((order, i) => { + return ( + + ) + }) + } +
    + + +
    + { + delivering.map((order, i) => { + return ( + + ) + }) + } +
    + + +
    + { + delivered.map((order, i) => { + return ( + + ) + }) + } +
    +
    +
    +
    + } +
    + ) +} + +export default OrderInformation \ No newline at end of file diff --git a/src/components/modules/account/DeliveryItem/DeliveryItem.module.scss b/src/components/modules/account/DeliveryItem/DeliveryItem.module.scss new file mode 100644 index 000000000..b83b77fd3 --- /dev/null +++ b/src/components/modules/account/DeliveryItem/DeliveryItem.module.scss @@ -0,0 +1,26 @@ +@import '../../../../styles/utilities'; + +.deliveryItem { + @apply flex bg-white items-center custom-border-radius; + margin-bottom: 1.6rem; + border: 1px solid var(--primary) +} + +.separator { + border-left: 2px dashed #EBEBEB; + max-height: 9.2rem; + min-height: 8.6rem; + + margin-left: .6rem; + margin-right: .6rem; + + @screen md { + margin-left: .8rem; + margin-right: .8rem; + } + + @screen lg { + margin-left: 2.4rem; + margin-right: 2.4rem; + } +} \ No newline at end of file diff --git a/src/components/modules/account/DeliveryItem/DeliveryItem.tsx b/src/components/modules/account/DeliveryItem/DeliveryItem.tsx new file mode 100644 index 000000000..fe8f5cdef --- /dev/null +++ b/src/components/modules/account/DeliveryItem/DeliveryItem.tsx @@ -0,0 +1,30 @@ +import React from "react" +import s from './DeliveryItem.module.scss' + +import IdAndStatus from './components/IdAndStatus/IdAndStatus' +import Products from './components/Products/Products' +import TotalPrice from './components/TotalPrice/TotalPrice' +import ReOrder from './components/ReOrder/ReOrder' + + +interface DeliveryItemProps { + id: string; + status: "waiting" | "delivering" | "delivered"; + products: string[]; + totalPrice: number; + reOrderLink?: string; +} + +const DeliveryItem = ({ id, status, products, totalPrice, reOrderLink } : DeliveryItemProps) => { + return ( +
    + +
    + + + +
    + ) +} + +export default DeliveryItem \ No newline at end of file diff --git a/src/components/modules/account/DeliveryItem/components/IdAndStatus/IdAndStatus.module.scss b/src/components/modules/account/DeliveryItem/components/IdAndStatus/IdAndStatus.module.scss new file mode 100644 index 000000000..d50ecd115 --- /dev/null +++ b/src/components/modules/account/DeliveryItem/components/IdAndStatus/IdAndStatus.module.scss @@ -0,0 +1,75 @@ +@import '../../../../../../styles/utilities'; + +.idAndStatus { + @apply items-center; + padding: 2.4rem 0 2.4rem 1rem; + + @screen md { + padding: 2.4rem 0 2.4rem 1.2rem; + } + + @screen lg { + padding: 2.4rem 0 2.4rem 2.4rem; + } + + .id { + @apply font-bold; + margin-bottom: .8rem; + } + + .deliveryStatus { + @apply font-bold text-white; + font-size: 1.2rem; + line-height: 2rem; + padding: 0 .8rem; + border-radius: 0.5rem; + width: fit-content; + + &.waiting { + background-color: #D9A645; + } + &.delivering { + background-color: var(--info-dark); + } + &.delivered { + background-color: var(--primary); + } + } +}@import '../../../../../../styles/utilities'; + +.idAndStatus { + @apply items-center; + padding: 2.4rem 0 2.4rem 1rem; + + @screen md { + padding: 2.4rem 0 2.4rem 1.2rem; + } + + @screen lg { + padding: 2.4rem 0 2.4rem 2.4rem; + } + + .id { + @apply font-bold; + margin-bottom: .8rem; + } + + .deliveryStatus { + @apply font-bold text-white; + font-size: 1.2rem; + line-height: 2rem; + padding: 0 .8rem; + border-radius: 0.5rem; + width: fit-content; + + &.waiting { + background-color: #D9A645; + } + &.delivering { + background-color: var(--info-dark); + } + &.delivered { + background-color: var(--primary); + } + } +} \ No newline at end of file diff --git a/src/components/modules/account/DeliveryItem/components/IdAndStatus/IdAndStatus.tsx b/src/components/modules/account/DeliveryItem/components/IdAndStatus/IdAndStatus.tsx new file mode 100644 index 000000000..841dd530f --- /dev/null +++ b/src/components/modules/account/DeliveryItem/components/IdAndStatus/IdAndStatus.tsx @@ -0,0 +1,25 @@ +import classNames from "classnames" +import React from "react" +import s from './IdAndStatus.module.scss' + + +interface IdAndStatusProps { + id?: string; + status: "waiting" | "delivering" | "delivered"; +} + +const IdAndStatus = ({ id, status="waiting" } : IdAndStatusProps) => { + return ( +
    +
    + {id} +
    +
    {status} +
    +
    + ) +} + +export default IdAndStatus \ No newline at end of file diff --git a/src/components/modules/account/DeliveryItem/components/Products/Products.module.scss b/src/components/modules/account/DeliveryItem/components/Products/Products.module.scss new file mode 100644 index 000000000..f05d6395b --- /dev/null +++ b/src/components/modules/account/DeliveryItem/components/Products/Products.module.scss @@ -0,0 +1,12 @@ +@import '../../../../../../styles/utilities'; + +.products { + margin-top: .8rem; + max-width: 32%; + min-width: none; + + @screen lg { + margin-top: 0; + margin-bottom: 0; + } +} \ No newline at end of file diff --git a/src/components/modules/account/DeliveryItem/components/Products/Products.tsx b/src/components/modules/account/DeliveryItem/components/Products/Products.tsx new file mode 100644 index 000000000..fdbba2c73 --- /dev/null +++ b/src/components/modules/account/DeliveryItem/components/Products/Products.tsx @@ -0,0 +1,29 @@ +import React from "react" +import s from './Products.module.scss' + +interface ProductsProps { + products: string[]; +} + +const Products = ({ products } : ProductsProps) => { + + function toString(products:string[]): string { + let strProducts = ""; + products.map((prod, i) => { + if (i === 0) { + strProducts += prod; + } else { + strProducts += `, ${prod}` + } + }); + return strProducts; + } + + return ( +
    + {toString(products)} +
    + ) +} + +export default Products \ No newline at end of file diff --git a/src/components/modules/account/DeliveryItem/components/ReOrder/ReOrder.module.scss b/src/components/modules/account/DeliveryItem/components/ReOrder/ReOrder.module.scss new file mode 100644 index 000000000..b46b528e1 --- /dev/null +++ b/src/components/modules/account/DeliveryItem/components/ReOrder/ReOrder.module.scss @@ -0,0 +1,27 @@ +@import '../../../../../../styles/utilities'; + +.reOrder { + @apply text-white custom-border-radius hidden font-bold; + padding: .4rem .6rem; + margin-right: 1rem; + background-color: var(--primary); + + @screen md { + padding: .4rem .6rem; + margin-right: 1.2rem; + } + + @screen lg { + padding: .8rem 1.2rem; + margin-right: 2.4rem; + } + + &.show { + @apply block; + } + + &:hover { + @apply cursor-pointer; + } + +} \ No newline at end of file diff --git a/src/components/modules/account/DeliveryItem/components/ReOrder/ReOrder.tsx b/src/components/modules/account/DeliveryItem/components/ReOrder/ReOrder.tsx new file mode 100644 index 000000000..2fbc546f4 --- /dev/null +++ b/src/components/modules/account/DeliveryItem/components/ReOrder/ReOrder.tsx @@ -0,0 +1,23 @@ +import classNames from "classnames" +import React from "react" +import s from './ReOrder.module.scss' +import Link from 'next/link' + +interface ReOrderProps { + show: boolean; + href?: string; +} + +const ReOrder = ({ show=false, href="#" } : ReOrderProps) => { + return ( +
    + + Re-Order + +
    + ) +} + +export default ReOrder \ No newline at end of file diff --git a/src/components/modules/account/DeliveryItem/components/TotalPrice/TotalPrice.module.scss b/src/components/modules/account/DeliveryItem/components/TotalPrice/TotalPrice.module.scss new file mode 100644 index 000000000..9a4f795b3 --- /dev/null +++ b/src/components/modules/account/DeliveryItem/components/TotalPrice/TotalPrice.module.scss @@ -0,0 +1,26 @@ +@import '../../../../../../styles/utilities'; + +.totalPrice { + margin-left: auto; + margin-right: 1rem; + + @screen md { + margin-right: 1.2rem; + } + + @screen lg { + margin-right: 2.4rem; + } + + .price { + @apply font-bold ; + + @screen md { + @apply topline + } + + @screen lg { + @apply sub-headline; + } + } +} \ No newline at end of file diff --git a/src/components/modules/account/DeliveryItem/components/TotalPrice/TotalPrice.tsx b/src/components/modules/account/DeliveryItem/components/TotalPrice/TotalPrice.tsx new file mode 100644 index 000000000..153149e85 --- /dev/null +++ b/src/components/modules/account/DeliveryItem/components/TotalPrice/TotalPrice.tsx @@ -0,0 +1,18 @@ +import React from "react" +import s from './TotalPrice.module.scss' + + +interface TotalPriceProps { + totalPrice: number; +} + +const TotalPrice = ({ totalPrice } : TotalPriceProps) => { + return ( +
    +
    Total
    +
    Rp {totalPrice}
    +
    + ) +} + +export default TotalPrice \ No newline at end of file diff --git a/src/components/modules/account/index.ts b/src/components/modules/account/index.ts new file mode 100644 index 000000000..42753b0b5 --- /dev/null +++ b/src/components/modules/account/index.ts @@ -0,0 +1,3 @@ +export { default as AccountNavigation } from './AccountNavigation/AccountNavigation' +export { default as DeliveryItem } from './DeliveryItem/DeliveryItem' +export { default as AccountPage } from './AccountPage/AccountPage' \ No newline at end of file diff --git a/src/components/modules/checkout/CheckoutBill/CheckoutBill.module.scss b/src/components/modules/checkout/CheckoutBill/CheckoutBill.module.scss new file mode 100644 index 000000000..403bdb76b --- /dev/null +++ b/src/components/modules/checkout/CheckoutBill/CheckoutBill.module.scss @@ -0,0 +1,38 @@ +.warpper { + padding: 3.2rem; + min-width: 100%; + @screen lg { + max-width: 56.3rem; + @apply flex justify-between flex-col border-l-2 border-solid border-line; + } + .title { + display: none; + font-weight: bold; + font-size: 2rem; + line-height: 2.8rem; + @screen md { + display: block; + } + } + .list { + min-height: 52.8rem; + } + .bot { + .promo { + // padding: 3.2rem; + @apply bg-gray flex justify-between items-center; + min-height: 6.4rem; + } + .price { + margin-top: 3.2rem; + .line { + @apply flex justify-between items-center text-label; + .total { + font-weight: bold; + font-size: 2rem; + line-height: 2.8rem; + } + } + } + } +} diff --git a/src/components/modules/checkout/CheckoutBill/CheckoutBill.tsx b/src/components/modules/checkout/CheckoutBill/CheckoutBill.tsx new file mode 100644 index 000000000..259397980 --- /dev/null +++ b/src/components/modules/checkout/CheckoutBill/CheckoutBill.tsx @@ -0,0 +1,46 @@ +import React from 'react' +import s from './CheckoutBill.module.scss' +import { CardItemCheckout } from '../../../common' +import { CardItemCheckoutProps } from '../../../common/CardItemCheckout/CardItemCheckout' +import { IconCirclePlus } from 'src/components/icons' + +interface CheckoutBillProps { + data: CardItemCheckoutProps[] +} + +const CheckoutBill = ({ data }: CheckoutBillProps) => { + return ( +
    +
    + Your cart ({data.length}) +
    +
    + {data.map((item) => { + return + })} +
    +
    +
    + Apply Promotion Code + +
    +
    +
    + Subtotal +
    RP 120.500
    +
    +
    + Shipping +
    Free
    +
    +
    + Estimated Total +
    RP 120.500
    +
    +
    +
    +
    + ) +} + +export default CheckoutBill diff --git a/src/components/modules/checkout/CheckoutInfo/CheckoutInfo.module.scss b/src/components/modules/checkout/CheckoutInfo/CheckoutInfo.module.scss new file mode 100644 index 000000000..cadf9f684 --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/CheckoutInfo.module.scss @@ -0,0 +1,17 @@ +.warpper{ + @apply w-full; + padding: 3.2rem; + .title{ + margin-bottom: 3.2rem; + @apply flex justify-between items-center; + .viewCart{ + margin-right: 5.6rem; + @apply text-primary font-bold; + display: block; + cursor: pointer; + @screen lg { + display: none; + } + } + } +} \ No newline at end of file diff --git a/src/components/modules/checkout/CheckoutInfo/CheckoutInfo.tsx b/src/components/modules/checkout/CheckoutInfo/CheckoutInfo.tsx new file mode 100644 index 000000000..423f92635 --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/CheckoutInfo.tsx @@ -0,0 +1,94 @@ +import React, { useState } from 'react' +import { Logo } from 'src/components/common' +import CheckoutCollapse from 'src/components/common/CheckoutCollapse/CheckoutCollapse' +import { removeItem } from 'src/utils/funtion.utils' +import { CheckOutForm } from 'src/utils/types.utils' +import s from './CheckoutInfo.module.scss' +import CustomerInfoForm from './components/CustomerInfoForm/CustomerInfoForm' +import PaymentInfoForm from './components/PaymentInfoForm/PaymentInfoForm' +import ShippingInfoForm from './components/ShippingInfoForm/ShippingInfoForm' +interface CheckoutInfoProps { + onViewCart:()=>void +} + +const CheckoutInfo = ({onViewCart}: CheckoutInfoProps) => { + const [active, setActive] = useState(1) + const [done, setDone] = useState([]) + const [info, setInfo] = useState({}) + + const onEdit = (id:number) => { + setActive(id) + setDone(removeItem(done,id)) + } + + const onConfirm = (id:number,formInfo:CheckOutForm) => { + if(id+1>formList.length){ + console.log({...info,...formInfo}) + }else{ + if(done.length>0){ + for (let i = id+1; i <= formList.length; i++) { + if(!done.includes(i)){ + setActive(i) + } + } + }else{ + setActive(id+1) + } + setDone([...done,id]) + } + setInfo({...info,...formInfo}) + } + + const getNote = (id:number) => { + switch (id) { + case 1: + return `${info.name}, ${info.email}` + case 2: + return `${info.address}, ${info.state}, ${info.city}, ${info.code}, ${info.phone}, ` + default: + return "" + } + } + + const formList = [ + { + id: 1, + title: 'Customer Information', + form: , + }, + { + id: 2, + title: 'Shipping Information', + form: , + }, + { + id: 3, + title: 'Payment Information', + form: , + }, + ] + return ( +
    +
    + +
    View cart
    +
    + {formList.map((item) => { + let note = getNote(item.id) + return + {item.form} + + })} +
    + ) +} + +export default CheckoutInfo diff --git a/src/components/modules/checkout/CheckoutInfo/components/BankTransfer/BankTransfer.module.scss b/src/components/modules/checkout/CheckoutInfo/components/BankTransfer/BankTransfer.module.scss new file mode 100644 index 000000000..44ac98048 --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/BankTransfer/BankTransfer.module.scss @@ -0,0 +1,15 @@ +.warpper{ + .info{ + .line{ + @apply flex justify-start items-center; + .title{ + margin-right: 3.2rem; + min-width: 19.4rem; + @apply text-label; + } + .hightlight{ + @apply text-active; + } + } + } +} \ No newline at end of file diff --git a/src/components/modules/checkout/CheckoutInfo/components/BankTransfer/BankTransfer.tsx b/src/components/modules/checkout/CheckoutInfo/components/BankTransfer/BankTransfer.tsx new file mode 100644 index 000000000..7de11245c --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/BankTransfer/BankTransfer.tsx @@ -0,0 +1,26 @@ +import React from 'react' +import s from './BankTransfer.module.scss' +interface BankTransferProps {} + +const BankTransfer = ({}: BankTransferProps) => { + return ( +
    +
    +
    +
    Account Name:
    +
    Duong Dinh Vu
    +
    +
    +
    Account Number:
    +
    1234 1234 1234 1234
    +
    +
    +
    Bank Name:
    +
    Techcombank - HCMC
    +
    +
    +
    + ) +} + +export default BankTransfer diff --git a/src/components/modules/checkout/CheckoutInfo/components/CreditCardForm/CreditCardForm.module.scss b/src/components/modules/checkout/CheckoutInfo/components/CreditCardForm/CreditCardForm.module.scss new file mode 100644 index 000000000..62dbbc8d3 --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/CreditCardForm/CreditCardForm.module.scss @@ -0,0 +1,12 @@ +@import "../../../../../../styles/utilities"; +.warpper{ + @apply u-form; + .line{ + >div{ + width: 50%; + } + } + .checkbox{ + margin-top: 1.6rem; + } +} \ No newline at end of file diff --git a/src/components/modules/checkout/CheckoutInfo/components/CreditCardForm/CreditCardForm.tsx b/src/components/modules/checkout/CheckoutInfo/components/CreditCardForm/CreditCardForm.tsx new file mode 100644 index 000000000..d289165e0 --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/CreditCardForm/CreditCardForm.tsx @@ -0,0 +1,27 @@ +import React, { useRef } from 'react' +import { CheckboxCommon, Inputcommon } from 'src/components/common' +import { CustomInputCommon } from 'src/utils/type.utils' +import s from "./CreditCardForm.module.scss" +interface CreditCardFormProps { + +} + +const CreditCardForm = ({}: CreditCardFormProps) => { + const cardNumberRef = useRef(null) + const dateRef = useRef(null) + const cvsRef = useRef(null) + return ( +
    +
    + +
    + + +
    +
    +
    +
    + ) +} + +export default CreditCardForm diff --git a/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/CustomerInfoForm.module.scss b/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/CustomerInfoForm.module.scss new file mode 100644 index 000000000..b0ecf8144 --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/CustomerInfoForm.module.scss @@ -0,0 +1,15 @@ +@import "../../../../../../styles/utilities"; +.warpper{ + @apply u-form; + @screen md { + padding: 0 5.6rem; + } + .bottom{ + margin-top: 2.4rem; + @apply flex justify-between items-center; + .note{ + font-size: 1.2rem; + line-height: 2rem; + } + } +} \ No newline at end of file diff --git a/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/CustomerInfoForm.tsx b/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/CustomerInfoForm.tsx new file mode 100644 index 000000000..8496b119d --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/CustomerInfoForm.tsx @@ -0,0 +1,54 @@ +import Link from 'next/link' +import React, { useRef } from 'react' +import { ButtonCommon, Inputcommon } from 'src/components/common' +import InputCommon from 'src/components/common/InputCommon/InputCommon' +import { CheckOutForm } from 'src/utils/types.utils' +import s from './CustomerInfoForm.module.scss' +interface CustomerInfoFormProps { + onConfirm?: (id: number, formInfo: CheckOutForm) => void + id: number +} + +const CustomerInfoForm = ({ id, onConfirm }: CustomerInfoFormProps) => { + const nameRef = useRef>(null) + const emailRef = useRef>(null) + + const handleConfirmClick = () => { + onConfirm && + onConfirm(id, { + name: nameRef?.current?.getValue().toString(), + email: emailRef.current?.getValue().toString(), + }) + } + + return ( +
    +
    + + +
    +
    +
    + By clicking continue you agree to Casper's{' '} + { + + terms and conditions + + }{' '} + and{' '} + { + + privacy policy + + } + . +
    + + Continue to Shipping + +
    +
    + ) +} + +export default CustomerInfoForm diff --git a/src/components/modules/checkout/CheckoutInfo/components/PaymentInfoForm/PaymentInfoForm.module.scss b/src/components/modules/checkout/CheckoutInfo/components/PaymentInfoForm/PaymentInfoForm.module.scss new file mode 100644 index 000000000..15a70659c --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/PaymentInfoForm/PaymentInfoForm.module.scss @@ -0,0 +1,16 @@ +.wrapper{ + @screen md { + padding: 0 5.6rem; + } + .inner{ + padding: 4rem 0; + } + .bottom{ + margin-top: 2.4rem; + @apply flex justify-between items-center; + .note{ + font-size: 1.2rem; + line-height: 2rem; + } + } +} \ No newline at end of file diff --git a/src/components/modules/checkout/CheckoutInfo/components/PaymentInfoForm/PaymentInfoForm.tsx b/src/components/modules/checkout/CheckoutInfo/components/PaymentInfoForm/PaymentInfoForm.tsx new file mode 100644 index 000000000..dc84fec38 --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/PaymentInfoForm/PaymentInfoForm.tsx @@ -0,0 +1,55 @@ +import React from 'react' +import { ButtonCommon, TabCommon, TabPane } from 'src/components/common' +import { CheckOutForm } from 'src/utils/types.utils' +import BankTransfer from '../BankTransfer/BankTransfer' +import Link from 'next/link' + +import s from './PaymentInfoForm.module.scss' +import CreditCardForm from '../CreditCardForm/CreditCardForm' +interface PaymentInfoFormProps { + onConfirm?: (id: number, formInfo: CheckOutForm) => void + id: number +} + +const PaymentInfoForm = ({onConfirm,id}: PaymentInfoFormProps) => { + const handleConfirmClick = () => { + onConfirm && onConfirm(id,{}) + } + return ( +
    + + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    + By clicking continue you agree to Casper's{' '} + { + + terms and conditions + + }{' '} + and{' '} + { + + privacy policy + + } + . +
    + + Submit Order + +
    +
    + ) +} + +export default PaymentInfoForm diff --git a/src/components/modules/checkout/CheckoutInfo/components/ShippingInfoForm/ShippingInfoForm.module.scss b/src/components/modules/checkout/CheckoutInfo/components/ShippingInfoForm/ShippingInfoForm.module.scss new file mode 100644 index 000000000..c0c8b2795 --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/ShippingInfoForm/ShippingInfoForm.module.scss @@ -0,0 +1,39 @@ +@import "../../../../../../styles/utilities"; + +.warpper{ + @apply u-form; + @screen md { + padding: 0 5.6rem; + } + .bottom{ + margin-top: 2.4rem; + @apply flex justify-between items-center; + .note{ + font-size: 1.2rem; + line-height: 2rem; + } + } + .line{ + >div{ + width: 50%; + } + } + .method{ + width: 100%; + height: 5.6rem; + padding: 1.6rem; + border-radius: 0.8rem; + @apply flex justify-between items-center border border-solid border-line bg-gray; + .left{ + @apply flex; + .name{ + margin-left: 1.6rem; + color: var(--text-active); + } + } + .price{ + font-weight: bold; + color: var(--text-active); + } + } +} \ No newline at end of file diff --git a/src/components/modules/checkout/CheckoutInfo/components/ShippingInfoForm/ShippingInfoForm.tsx b/src/components/modules/checkout/CheckoutInfo/components/ShippingInfoForm/ShippingInfoForm.tsx new file mode 100644 index 000000000..ac4bc8af5 --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/ShippingInfoForm/ShippingInfoForm.tsx @@ -0,0 +1,97 @@ +import React, { useRef } from 'react' +import { ButtonCommon, Inputcommon, SelectCommon } from 'src/components/common' +import s from './ShippingInfoForm.module.scss' +import Link from 'next/link' +import { CustomInputCommon } from 'src/utils/type.utils' +import { Shipping } from 'src/components/icons' +import { CheckOutForm } from 'src/utils/types.utils' + +interface ShippingInfoFormProps { + onConfirm?: (id:number,formInfo:CheckOutForm)=>void + id:number +} + +const option = [ + { + name: 'Hồ Chí Minh', + }, + { + name: 'Hà Nội', + }, +] + +const ShippingInfoForm = ({onConfirm,id}: ShippingInfoFormProps) => { + const addressRef = useRef(null) + const cityRef = useRef(null) + const stateRef = useRef(null) + const codeRef = useRef(null) + const phoneRef = useRef(null) + const handleConfirmClick = () => { + onConfirm && onConfirm(id,{ + address: addressRef?.current?.getValue().toString(), + city: cityRef.current?.getValue().toString(), + state: stateRef?.current?.getValue().toString(), + code: Number(codeRef.current?.getValue()), + phone: Number(phoneRef?.current?.getValue()), + }) + } + + return ( +
    +
    + + +
    + State + +
    + +
    +
    +
    + +
    +
    + Standard Delivery Method +
    +
    +
    +
    + Free +
    +
    +
    +
    +
    +
    + By clicking continue you agree to Casper's{' '} + { + + terms and conditions + + }{' '} + and{' '} + { + + privacy policy + + } + . +
    + + Continue to Payment + +
    +
    + ) +} + +export default ShippingInfoForm diff --git a/src/components/modules/checkout/CheckoutPage/CheckoutPage.module.scss b/src/components/modules/checkout/CheckoutPage/CheckoutPage.module.scss new file mode 100644 index 000000000..1661f243c --- /dev/null +++ b/src/components/modules/checkout/CheckoutPage/CheckoutPage.module.scss @@ -0,0 +1,56 @@ +@import "../../../../styles/utilities"; +.warrper{ + @apply flex; + .right{ + display: none; + @screen lg { + display: block; + min-width: 45rem; + } + @screen xl { + min-width: 56.3rem; + } + } + .left{ + @apply w-full; + } + .mobile{ + @apply hidden; + &.isShow{ + @apply block; + @screen lg { + @apply hidden; + } + } + .modal{ + 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: 6.4rem ; + 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/modules/checkout/CheckoutPage/CheckoutPage.tsx b/src/components/modules/checkout/CheckoutPage/CheckoutPage.tsx new file mode 100644 index 000000000..8cfcc31f3 --- /dev/null +++ b/src/components/modules/checkout/CheckoutPage/CheckoutPage.tsx @@ -0,0 +1,37 @@ +import classNames from 'classnames' +import React, { useState } from 'react' +import IconHide from 'src/components/icons/IconHide' +import { CHECKOUT_BILL_DATA } from 'src/utils/demo-data' +import { CheckoutBill, CheckoutInfo } from '..' +import s from "./CheckoutPage.module.scss" +interface CheckoutPageProps { +} + +const CheckoutPage = ({}: CheckoutPageProps) => { + const [isShow, setIsShow] = useState(false) + const onClose = () => { + setIsShow(false) + } + const onViewCart =() => { + setIsShow(true) + } + return ( +
    +
    +
    +
    +
    +
    +
    +

    Your Cart({CHECKOUT_BILL_DATA.length})

    +
    +
    + +
    +
    +
    +
    + ) +} + +export default CheckoutPage diff --git a/src/components/modules/checkout/index.ts b/src/components/modules/checkout/index.ts new file mode 100644 index 000000000..736375e4c --- /dev/null +++ b/src/components/modules/checkout/index.ts @@ -0,0 +1,3 @@ +export { default as CheckoutInfo } from './CheckoutInfo/CheckoutInfo' +export { default as CheckoutPage } from './CheckoutPage/CheckoutPage' +export { default as CheckoutBill } from './CheckoutBill/CheckoutBill' diff --git a/src/components/modules/product-list/ProductListBanner/ProductListBanner.module.scss b/src/components/modules/product-list/ProductListBanner/ProductListBanner.module.scss new file mode 100644 index 000000000..a3452e797 --- /dev/null +++ b/src/components/modules/product-list/ProductListBanner/ProductListBanner.module.scss @@ -0,0 +1,8 @@ +@import "../../../../styles/_utilities"; + +.productListBanner{ + @apply spacing-horizontal; + @screen md { + padding:0 3.2rem; + } +} \ No newline at end of file diff --git a/src/components/modules/product-list/ProductListBanner/ProductListBanner.tsx b/src/components/modules/product-list/ProductListBanner/ProductListBanner.tsx new file mode 100644 index 000000000..17d48d637 --- /dev/null +++ b/src/components/modules/product-list/ProductListBanner/ProductListBanner.tsx @@ -0,0 +1,27 @@ +import React from 'react' +import { Banner } from 'src/components/common' +import BannerRight from './assets/bannerrecipes.png' +import s from './ProductListBanner.module.scss' + +interface Props { +} + +const ProductListBanner = ({ }: Props) => { + return ( +
    + +
    + ) +} + +export default ProductListBanner diff --git a/src/components/modules/product-list/ProductListBanner/assets/bannerrecipes.png b/src/components/modules/product-list/ProductListBanner/assets/bannerrecipes.png new file mode 100644 index 000000000..91271cbd2 Binary files /dev/null and b/src/components/modules/product-list/ProductListBanner/assets/bannerrecipes.png differ diff --git a/src/components/modules/product-list/ProductListFilter/ProductListFilter.module.scss b/src/components/modules/product-list/ProductListFilter/ProductListFilter.module.scss new file mode 100644 index 000000000..b30b9e1a6 --- /dev/null +++ b/src/components/modules/product-list/ProductListFilter/ProductListFilter.module.scss @@ -0,0 +1,88 @@ +@import "../../../../styles/_utilities"; + +.warpper { + @apply spacing-horizontal; + @screen md{ + padding:0 3.2rem; + padding-bottom:5.6rem; + } + .breadcrumb{ + padding:1rem 0; + } + .main{ + @screen md { + @apply flex; + } + .categories{ + @apply hidden; + @screen md { + @apply hidden; + } + @screen xl{ + @apply block; + width:25%; + } + } + .list{ + @screen md { + @apply flex justify-between flex-wrap w-full; + margin: 1rem 0; + } + @screen xl { + width:75%; + } + .inner{ + @screen md { + @apply flex flex-col items-center justify-center; + } + .boxItem { + @screen md { + @apply flex justify-between flex-wrap; + margin: 1rem 0; + } + .item { + @screen md { + width: calc(97% / 2); + margin-top:1rem; + } + @screen lg{ + width: calc(97% / 3); + margin-top:1rem; + } + } + } + } + + .boxSelect{ + @apply w-auto; + // padding: 2.5rem 0; + display: none; + + @screen xl { + @apply block; + width: auto; + padding:0; + } + .categorySelectCate{ + @screen xl { + @apply hidden; + } + } + label{ + @apply font-bold topline ; + color:var(--text-active); + @screen xl { + @apply hidden; + } + } + .select{ + margin-top: 1rem; + } + } + + } + + } + + +} diff --git a/src/components/modules/product-list/ProductListFilter/ProductListFilter.tsx b/src/components/modules/product-list/ProductListFilter/ProductListFilter.tsx new file mode 100644 index 000000000..5315283dc --- /dev/null +++ b/src/components/modules/product-list/ProductListFilter/ProductListFilter.tsx @@ -0,0 +1,66 @@ +import React from 'react' +import { HeadingCommon, ProductList, SelectCommon } from 'src/components/common' +import BreadcrumbCommon from 'src/components/common/BreadcrumbCommon/BreadcrumbCommon' +import MenuNavigation from 'src/components/common/MenuNavigation/MenuNavigation' +import { BRAND, CATEGORY, FEATURED} from 'src/utils/constanst.utils' +import { PRODUCT_DATA_TEST_PAGE } from 'src/utils/demo-data' +import s from './ProductListFilter.module.scss' + +interface ProductListFilterProps {} + +const BREADCRUMB = [ + { + name: 'Products', + link: `#`, + }, +] +const OPTIONSLECT = [ + { + name: 'Most Viewed', + value: 'most-viewed', + }, + { + name: 'Lastest Products', + value: 'lastest-products', + }, + { + name: 'Recent Products', + value: 'recent-products', + }, +] + +const onModalClose = () => { + +} + +const ProductListFilter = (props: ProductListFilterProps) => { + return ( +
    +
    + +
    +
    +
    + + + +
    + +
    + SPECIAL RECIPES + +
    +
    +
    + +
    +
    +
    + +
    +
    +
    + ) +} + +export default ProductListFilter diff --git a/src/utils/constanst.utils.ts b/src/utils/constanst.utils.ts index e91fb17f6..3757feb1e 100644 --- a/src/utils/constanst.utils.ts +++ b/src/utils/constanst.utils.ts @@ -53,4 +53,67 @@ export const KEY = { export const OPTION_ALL = 'all'; export const DEFAULT_PAGE_SIZE=20; + + +export const CATEGORY = [ + { + name: 'All', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=${OPTION_ALL}`, + }, + { + name: 'Veggie', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=veggie`, + }, + { + name: 'Seafood', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=seafood`, + }, + { + name: 'Frozen', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=frozen`, + }, + { + name: 'Coffee Bean', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=coffee_bean`, + }, + { + name: 'Sauce', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=sauce`, + }, + ] + + export const BRAND = [ + { + name: 'Maggi', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=maggi`, + }, + { + name: 'Chomilex', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=chomilex`, + }, + { + name: 'Chinsu', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=chinsu`, + }, + ] + +export const FEATURED = [ + { + name: 'Best Sellers', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.FEATURED}=best_sellers`, + }, + { + name: 'Sales', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.FEATURED}=sales`, + }, + { + name: 'New Item', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.FEATURED}=new_item`, + }, + { + name: 'Viewed', + link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.FEATURED}=viewed`, + }, + ] + export const DEFAULT_BLOG_PAGE_SIZE=6; diff --git a/src/utils/demo-data.ts b/src/utils/demo-data.ts index edc4eee6a..aad6653b5 100644 --- a/src/utils/demo-data.ts +++ b/src/utils/demo-data.ts @@ -1,4 +1,5 @@ import { BlogCardProps } from "src/components/common/CardBlog/CardBlog" +import { CardItemCheckoutProps } from "src/components/common/CardItemCheckout/CardItemCheckout" import { RecipeCardProps } from "src/components/common/RecipeCard/RecipeCard" export const PRODUCT_DATA_TEST = [ @@ -260,4 +261,34 @@ export const BLOGS_DATA_TEST: BlogCardProps[] = [ imageSrc: 'https://user-images.githubusercontent.com/76729908/132159262-f28a9fb9-4852-47e6-80b5-d600521b548a.png', slug:"the-best-recipe-of-beef-noodle-soup" }, -]; \ No newline at end of file +]; +export const CHECKOUT_BILL_DATA:CardItemCheckoutProps[] = [ + { + name: 'Tomato', + slug: "tomato", + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646227-b5705e64-3b45-47a3-9433-9f4b5ee8d40c.png", + quantity:10 + }, + { + name: 'Carrot', + slug: "carrot", + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646217-23b86160-45c9-4845-8dcc-b3e1a4483edd.png", + quantity:1 + }, + { + name: 'Salad', + slug:"salad", + weight: '250g', + category: 'VEGGIE', + price: 'Rp 27.500', + imageSrc: "https://user-images.githubusercontent.com/76729908/131646221-aaa1d48d-bb80-470f-9400-ae2aa47285b6.png", + quantity:2 + }, + ] +export const PRODUCT_DATA_TEST_PAGE = [...PRODUCT_DATA_TEST, ...PRODUCT_DATA_TEST, ...PRODUCT_DATA_TEST, ...PRODUCT_DATA_TEST, ...PRODUCT_DATA_TEST] diff --git a/src/utils/funtion.utils.ts b/src/utils/funtion.utils.ts index b1e7b5536..619e9ae30 100644 --- a/src/utils/funtion.utils.ts +++ b/src/utils/funtion.utils.ts @@ -1,3 +1,11 @@ export function isMobile() { return window.innerWidth <= 768 +} + +export function removeItem(arr: Array, value: T): Array { + const index = arr.indexOf(value); + if (index > -1) { + arr.splice(index, 1); + } + return [...arr]; } \ No newline at end of file diff --git a/src/utils/types.utils.ts b/src/utils/types.utils.ts index 90fa547c3..e2ce516d4 100644 --- a/src/utils/types.utils.ts +++ b/src/utils/types.utils.ts @@ -32,4 +32,22 @@ export interface BlogProps { imageSrc: string } -export type MouseAndTouchEvent = MouseEvent | TouchEvent \ No newline at end of file +export interface CheckOutForm { + name?: string + email?:string + address?: string + city?:string + state?:string + code?:number + phone?:number + method?:string + shipping_fee?:number +} + +export type MouseAndTouchEvent = MouseEvent | TouchEvent + +export type filterContextType = { + visible: boolean; + open: () => void; + close: () => void; +}; \ No newline at end of file