mirror of
https://github.com/vercel/commerce.git
synced 2025-07-22 04:14:18 +00:00
✨ feat: Account Page
This commit is contained in:
parent
a2d2b45de3
commit
efe6ecf005
@ -0,0 +1,22 @@
|
||||
@import '../../../../styles/utilities';
|
||||
|
||||
.accountPage {
|
||||
@apply flex spacing-horizontal;
|
||||
background-color: #F5F4F2;
|
||||
margin-top: -3.2rem;
|
||||
padding-bottom: 3.2rem;
|
||||
|
||||
.pageLeft {
|
||||
padding-top: 5.6rem;
|
||||
margin-right: 12.4rem;
|
||||
|
||||
.accNavi{
|
||||
margin-top: 3.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
.pageRight {
|
||||
padding-top: 5.6rem;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
134
src/components/modules/account/AccountPage/AccountPage.tsx
Normal file
134
src/components/modules/account/AccountPage/AccountPage.tsx
Normal file
@ -0,0 +1,134 @@
|
||||
import React, { useEffect, 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'
|
||||
|
||||
interface AccountPageProps {
|
||||
|
||||
}
|
||||
|
||||
const AccountPage = ({} : AccountPageProps) => {
|
||||
const waiting = [
|
||||
{
|
||||
id: "NO 123456",
|
||||
products: ["Tomato", "Fish", "Pork", "Onion"],
|
||||
totalPrice : 1000
|
||||
},
|
||||
{
|
||||
id: "NO 123456",
|
||||
products: ["Tomato", "Fish", "Pork", "Onion"],
|
||||
totalPrice : 1000
|
||||
},
|
||||
{
|
||||
id: "NO 123456",
|
||||
products: ["Tomato", "Fish", "Pork", "Onion"],
|
||||
totalPrice : 1000
|
||||
}
|
||||
]
|
||||
|
||||
const delivering = [
|
||||
{
|
||||
id: "NO 123456",
|
||||
products: ["Tomato", "Fish", "Pork", "Onion"],
|
||||
totalPrice : 1000
|
||||
},
|
||||
{
|
||||
id: "NO 123456",
|
||||
products: ["Tomato", "Fish", "Pork", "Onion"],
|
||||
totalPrice : 1000
|
||||
},
|
||||
{
|
||||
id: "NO 123456",
|
||||
products: ["Tomato", "Fish", "Pork", "Onion"],
|
||||
totalPrice : 1000
|
||||
}
|
||||
]
|
||||
|
||||
const delivered = [
|
||||
{
|
||||
id: "NO 123456",
|
||||
products: ["Tomato", "Fish", "Pork", "Onion"],
|
||||
totalPrice : 1000
|
||||
},
|
||||
{
|
||||
id: "NO 123456",
|
||||
products: ["Tomato", "Fish", "Pork", "Onion"],
|
||||
totalPrice : 1000
|
||||
},
|
||||
{
|
||||
id: "NO 123456",
|
||||
products: ["Tomato", "Fish", "Pork", "Onion"],
|
||||
totalPrice : 1000
|
||||
}
|
||||
]
|
||||
|
||||
const account = {
|
||||
name: "vu duong",
|
||||
email: "vuduong@gmail.com",
|
||||
address: "234 Dien Bien Phu Bis, Dakao ward, District 1, HCMC",
|
||||
postalCode: "700000",
|
||||
phoneNumber: "(+84) 937 937 195"
|
||||
}
|
||||
|
||||
const [accountInfoActive, setAccountInfoActive] = useState(false);
|
||||
const [orderInfoActive, setOrderInfoActive] = useState(true);
|
||||
const [favoritesActive, setFavoritesActive] = useState(false);
|
||||
|
||||
function accountActive() {
|
||||
setAccountInfoActive(true);
|
||||
setOrderInfoActive(false);
|
||||
setFavoritesActive(false);
|
||||
}
|
||||
|
||||
function orderActive() {
|
||||
setAccountInfoActive(false);
|
||||
setOrderInfoActive(true);
|
||||
setFavoritesActive(false);
|
||||
}
|
||||
|
||||
function favActive() {
|
||||
setAccountInfoActive(false);
|
||||
setOrderInfoActive(false);
|
||||
setFavoritesActive(true);
|
||||
}
|
||||
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
|
||||
function showEditForm() {
|
||||
setModalVisible(true);
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
setModalVisible(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className={s.accountPage}>
|
||||
<div className={s.pageLeft}>
|
||||
<HeadingCommon>Account</HeadingCommon>
|
||||
<div className={s.accNavi}>
|
||||
<AccountNavigation setAccountActive={accountActive} setOrderActive={orderActive} setFavActive={favActive} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={s.pageRight}>
|
||||
<AccountInfomation active={accountInfoActive} account={account} clickShowEditForm={showEditForm} />
|
||||
<OrderInfomation active={orderInfoActive} waiting={waiting} delivering={delivering} delivered={delivered} />
|
||||
|
||||
{/* Thieu cai favorite */}
|
||||
{/* <FavoriteProduct active={favoritesActive} favProducts={favProducts} /> */}
|
||||
</div>
|
||||
|
||||
|
||||
</section>
|
||||
<EditInfoModal closeModal={closeModal} visible={modalVisible} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default AccountPage
|
BIN
src/components/modules/account/AccountPage/assets/avatar.png
Normal file
BIN
src/components/modules/account/AccountPage/assets/avatar.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
@ -0,0 +1,49 @@
|
||||
@import '../../../../../../styles/utilities';
|
||||
|
||||
.accountInfomation {
|
||||
transition: opacity 6s;
|
||||
|
||||
.avatar {
|
||||
height: 22rem;
|
||||
width: 22rem;
|
||||
border-radius: 50%;
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
.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;
|
||||
margin-top: 2.4rem;
|
||||
margin-bottom: 2.4rem;
|
||||
padding: .8rem 1.6rem;
|
||||
color: #141414;
|
||||
border: 1px solid #141414;
|
||||
max-width: 8.8rem;
|
||||
border-radius: 25%;
|
||||
|
||||
&:hover {
|
||||
@apply cursor-pointer;
|
||||
background-color: #FBFBFB;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
import React, { useState } from "react"
|
||||
import s from './AccountInfomation.module.scss'
|
||||
|
||||
import Image from "next/image"
|
||||
import avatar from '../../assets/avatar.png';
|
||||
|
||||
interface AccountInfomationProps {
|
||||
account: {name: string, email: string, address: string, postalCode: string, phoneNumber: string};
|
||||
active: boolean;
|
||||
clickShowEditForm: ()=>void;
|
||||
}
|
||||
|
||||
const AccountInfomation = ({ account, active=false, clickShowEditForm } : AccountInfomationProps) => {
|
||||
return (
|
||||
<section className={s.accountInfomation}>
|
||||
{
|
||||
active && <div>
|
||||
<div className={s.avatar}>
|
||||
<Image src={avatar} alt="avatar" />
|
||||
</div>
|
||||
|
||||
<div className={s.accountName}>
|
||||
{account.name}
|
||||
</div>
|
||||
<div className={s.accountEmail}>
|
||||
{account.email}
|
||||
</div>
|
||||
|
||||
<div className={s.horizontalSeparator}></div>
|
||||
|
||||
<div className={s.shippingInfo}>Shipping Infomation</div>
|
||||
|
||||
<div className={s.accountAddress}>
|
||||
{account.address + `, ${account.postalCode}`}
|
||||
</div>
|
||||
|
||||
<div className={s.accountPhoneNumber}>
|
||||
{account.phoneNumber}
|
||||
</div>
|
||||
|
||||
<div onClick={clickShowEditForm} className={s.editInfoBtn}>Edit</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
export default AccountInfomation
|
@ -0,0 +1,67 @@
|
||||
@import '../../../../../../styles/utilities';
|
||||
|
||||
.editInfoModal {
|
||||
.input {
|
||||
@apply bg-white;
|
||||
margin-bottom: 1.6rem;
|
||||
width: 100%;
|
||||
border: 2px solid #EBEBEB;
|
||||
border-radius: .8rem;
|
||||
padding: 1.6rem;
|
||||
}
|
||||
|
||||
.inputState {
|
||||
@apply bg-white;
|
||||
margin-bottom: 1.6rem;
|
||||
margin-right: 1.6rem;
|
||||
border: 2px solid #EBEBEB;
|
||||
border-radius: .8rem;
|
||||
padding: 1.6rem;
|
||||
}
|
||||
|
||||
.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;
|
||||
color: #141414;
|
||||
border: 1px solid #141414;
|
||||
border-radius: 2.5rem;
|
||||
padding: 1.6rem;
|
||||
margin-right: 1.6rem;
|
||||
|
||||
&:hover {
|
||||
@apply cursor-pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.buttonSave {
|
||||
@apply text-center font-bold;
|
||||
background-color: var(--primary);
|
||||
color: white;
|
||||
border-radius: 2.5rem;
|
||||
padding: 1.6rem;
|
||||
|
||||
&:hover {
|
||||
@apply cursor-pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
import classNames from "classnames"
|
||||
import React from "react"
|
||||
import s from './EditInfoModal.module.scss'
|
||||
|
||||
import {ModalCommon, MenuDropdown} from '../../../../../common'
|
||||
|
||||
interface EditInfoModalProps {
|
||||
visible: boolean;
|
||||
closeModal: () => void;
|
||||
}
|
||||
|
||||
const EditInfoModal = ({ visible = false, closeModal }: EditInfoModalProps) => {
|
||||
|
||||
function saveInfo() {
|
||||
console.log("saved !!!");
|
||||
|
||||
closeModal();
|
||||
}
|
||||
|
||||
const options = [
|
||||
{name: "hihi"},
|
||||
{name: "hihi"},
|
||||
{name: "hihi"}
|
||||
]
|
||||
|
||||
return (
|
||||
<ModalCommon onClose={closeModal} visible={visible} title="Edit Infomation">
|
||||
<section className={s.editInfoModal}>
|
||||
<div><input className={s.input} type="text" name="" placeholder="Name" /></div>
|
||||
<div><input className={s.input} type="text" name="" placeholder="Email" /></div>
|
||||
<div><input className={s.input} type="text" name="" placeholder="Address" /></div>
|
||||
<div><input className={s.input} type="text" name="" placeholder="City" /></div>
|
||||
|
||||
<div>
|
||||
{/* <MenuDropdown options={options} isHasArrow={false} > */}
|
||||
<input className={s.inputState} type="text" name="" placeholder="State" />
|
||||
{/* </MenuDropdown> */}
|
||||
<input className={s.inputPostalCode} type="text" name="" placeholder="hehe" />
|
||||
</div>
|
||||
|
||||
<div><input className={s.inputPhoneNumber} type="text" name="" placeholder="Phone number" /></div>
|
||||
|
||||
<div className={s.buttons}>
|
||||
<div onClick={closeModal} className={s.buttonCancel}>Cancel</div>
|
||||
<div onClick={saveInfo} className={s.buttonSave}>Save</div>
|
||||
</div>
|
||||
</section>
|
||||
</ModalCommon>
|
||||
)
|
||||
}
|
||||
|
||||
export default EditInfoModal
|
@ -0,0 +1,16 @@
|
||||
@import '../../../../../../styles/utilities';
|
||||
|
||||
.orderInformation {
|
||||
.title {
|
||||
@apply heading-3 font-heading;
|
||||
margin-top: 1.6rem;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
margin-top: 3.2rem;
|
||||
}
|
||||
|
||||
.tabPanes {
|
||||
margin-top: 2.4rem;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
import React, {useState} from "react"
|
||||
import s from './OrderInformation.module.scss'
|
||||
|
||||
import { TabCommon } from '../../../../../common'
|
||||
import TabPane from '../../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, active=true } : OrderInformationProps) => {
|
||||
const [activeTabPane, setActiveTabPane] = useState("waiting");
|
||||
|
||||
function changeTabPane(tab: string) {
|
||||
setActiveTabPane(tab);
|
||||
}
|
||||
|
||||
return (
|
||||
<section className={s.orderInformation}>
|
||||
{
|
||||
active && <div>
|
||||
<div className={s.title}>Order Information</div>
|
||||
|
||||
<div className={s.tabs}>
|
||||
<TabCommon changeTabPane={changeTabPane} />
|
||||
|
||||
<div className={s.tabPanes}>
|
||||
<TabPane active={activeTabPane==="waiting" ? `active` : ""}>
|
||||
{
|
||||
waiting.map((order, i) => {
|
||||
return (
|
||||
<DeliveryItem key={i} id={order.id} status="waiting" products={order.products} totalPrice={order.totalPrice} />
|
||||
)
|
||||
})
|
||||
}
|
||||
</TabPane>
|
||||
<TabPane active={activeTabPane==="delivering" ? `active` : ""}>
|
||||
{
|
||||
delivering.map((order, i) => {
|
||||
return (
|
||||
<DeliveryItem key={i} id={order.id} status="delivering" products={order.products} totalPrice={order.totalPrice} />
|
||||
)
|
||||
})
|
||||
}
|
||||
</TabPane>
|
||||
<TabPane active={activeTabPane==="delivered" ?`active` : ""}>
|
||||
{
|
||||
delivered.map((order, i) => {
|
||||
return (
|
||||
<DeliveryItem key={i} id={order.id} status="delivered" products={order.products} totalPrice={order.totalPrice} />
|
||||
)
|
||||
})
|
||||
}
|
||||
</TabPane>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
export default OrderInformation
|
@ -0,0 +1,23 @@
|
||||
@import '../../../../../../styles/utilities';
|
||||
|
||||
.tabPane {
|
||||
@apply hidden;
|
||||
animation-duration: 0.6s;
|
||||
animation-name: appear;
|
||||
@keyframes appear {
|
||||
from {
|
||||
margin-left: 100%;
|
||||
width: 200%;
|
||||
}
|
||||
|
||||
to {
|
||||
margin-left: 0%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&.active {
|
||||
@apply block;
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
import classNames from "classnames"
|
||||
import React from "react"
|
||||
import s from './TabPane.module.scss'
|
||||
|
||||
interface TabPaneProps {
|
||||
active: string;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
const TabPane = ({ active="", children } : TabPaneProps) => {
|
||||
return (
|
||||
<section className={classNames(s.tabPane, {
|
||||
[s[active]] : active
|
||||
})}>
|
||||
{children}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
export default TabPane
|
Loading…
x
Reference in New Issue
Block a user