add: checkout page
This commit is contained in:
@@ -6,7 +6,7 @@ import React from 'react'
|
||||
function DialogsLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<ClientSideWrapper>
|
||||
<main className='h-full w-full bg-container lg:bg-background pt-4 pb-6 px-6'>
|
||||
<main className='h-full w-full overflow-y-auto noscrollbar bg-container lg:bg-background pt-4 pb-6 px-6'>
|
||||
{children}
|
||||
</main>
|
||||
</ClientSideWrapper>
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
'use client';
|
||||
|
||||
import AnimatedBottomSheet from '@/components/bottomsheet/AnimatedBottomSheet';
|
||||
import Button from '@/components/button/PrimaryButton';
|
||||
import Combobox, { ComboboxOption } from '@/components/combobox/Combobox';
|
||||
import InputField from '@/components/input/InputField';
|
||||
import clsx from 'clsx';
|
||||
import { motion } from 'framer-motion';
|
||||
import { ArrowLeft, Box, Card, Cup, Icon, Shop, Ticket, TicketDiscount, TruckTick, Wallet2 } from 'iconsax-react';
|
||||
import { ChevronLeft, MinusIcon, PlusIcon } from 'lucide-react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
type Params = {
|
||||
id: string
|
||||
}
|
||||
|
||||
|
||||
function OrderDetailInex() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const params = useParams<Params>();
|
||||
const { t } = useTranslation('parallels', { keyPrefix: 'OrderDetail' });
|
||||
const router = useRouter();
|
||||
const [deliveryType, setDeliveryType] = React.useState<string>('0');
|
||||
const [paymentType, setPaymentType] = React.useState<string>('0');
|
||||
const [couponType, setCouponType] = React.useState<string>('0');
|
||||
const [couponCode, setCouponCode] = React.useState<string>('');
|
||||
const [cartModal, setCartModal] = React.useState<boolean>(false);
|
||||
const [couponCodeError, setCouponCodeError] = React.useState<string>(''); // TODO: handle coupon code error
|
||||
const [tableNumber, setTableNumber] = useState(0) // TODO: must be set to table number
|
||||
const incrementTableNumber = () => setTableNumber((prev) => prev + 1); // TODO: must be set to table number
|
||||
const decrementTableNumber = () => setTableNumber((prev) => prev - 1); // TODO: must be set to table number
|
||||
const address = "اراک، مصطفی خمینی، خیابان سینا کوچه چمران ساختمان شهرزاد"
|
||||
|
||||
const deliveryOptions: Array<ComboboxOption> = [
|
||||
{ id: '0', title: t("SectionShipping.InputDeliveryType.Options.Delivery"), icon: TruckTick },
|
||||
{ id: '1', title: t("SectionShipping.InputDeliveryType.Options.Serve"), icon: Shop },
|
||||
{ id: '2', title: t("SectionShipping.InputDeliveryType.Options.Pickup"), icon: Box },
|
||||
];
|
||||
|
||||
const paymentOptions: Array<{ id: string, label: string, icon: Icon }> = [
|
||||
{ id: '0', label: t("SectionPayment.InputPaymentType.Options.Online"), icon: Card },
|
||||
{ id: '1', label: t("SectionPayment.InputPaymentType.Options.CashOnDelivery"), icon: Wallet2 },
|
||||
];
|
||||
|
||||
const couponOptions: Array<{ id: string, label: string, icon: Icon }> = [
|
||||
{ id: '0', label: t("SectionCoupon.InputCouponType.Options.Discount"), icon: Cup },
|
||||
{ id: '1', label: t("SectionCoupon.InputCouponType.Options.GiftCard"), icon: Ticket },
|
||||
];
|
||||
|
||||
const couponDropdownOptions: Array<ComboboxOption> = [
|
||||
{ id: '0', title: t("SectionCoupon.InputCouponCode.Options.Default") },
|
||||
{ id: '1', title: "Something" },
|
||||
];
|
||||
|
||||
const changeDeliveryType = useCallback((id: string) => {
|
||||
setDeliveryType(id);
|
||||
}, [])
|
||||
|
||||
const changePaymentType = useCallback((id: string) => {
|
||||
setPaymentType(id);
|
||||
}, []);
|
||||
|
||||
const changeCouponType = useCallback((id: string) => {
|
||||
setCouponCode('');
|
||||
setCouponCodeError('');
|
||||
setCouponType(id);
|
||||
}, []);
|
||||
|
||||
const changeCouponCode = useCallback((id: string) => {
|
||||
if (id === '0') {
|
||||
setCouponCode('');
|
||||
return;
|
||||
}
|
||||
setCouponCode(id);
|
||||
}, []);
|
||||
|
||||
const toggleCartModal = useCallback(() => {
|
||||
setCartModal((prev) => !prev);
|
||||
}, []);
|
||||
|
||||
const addressSection = () => {
|
||||
if (deliveryType !== '0') {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<section
|
||||
className="bg-container rounded-container box-shadow-normal p-4">
|
||||
<div className="py-3">
|
||||
<div className='w-full flex justify-between items-center gap-2'>
|
||||
<h3 className="text-sm2 font-medium leading-5 inline-block">{t("SectionAddress.Title")}</h3>
|
||||
<button
|
||||
className='text-sm2 text-primary cursor-pointer'
|
||||
onClick={() => { /* Handle address change */ }}
|
||||
>
|
||||
{t("SectionAddress.ButtonChangeAddress")}
|
||||
<ChevronLeft className='inline-block mr-1 mb-0.5 stroke-primary' size='16' />
|
||||
</button>
|
||||
</div>
|
||||
<p className='mt-6 text-sm2'>
|
||||
{address}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
const tableSection = () => {
|
||||
if (deliveryType !== '1') {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<section
|
||||
className="bg-container rounded-container box-shadow-normal p-4 py-2">
|
||||
<div className="py-3">
|
||||
<div className='w-full grid grid-cols-2 justify-between items-center gap-2'>
|
||||
<h3 className="text-sm2 font-medium leading-5 inline-block">{t("SectionTable.Title")}</h3>
|
||||
|
||||
<div className='w-full flex justify-end'>
|
||||
<motion.div
|
||||
whileTap={{ scale: 1.05 }}
|
||||
className="bg-background active:drop-shadow-xs max-w-[132px] rounded-md w-full h-8 inline-flex p-1 justify-between items-center gap-2"
|
||||
>
|
||||
<button
|
||||
onClick={() => incrementTableNumber()}
|
||||
className="bg-white hover:bg-white/60 size-6 place-items-center active:bg-white/30 rounded-sm"
|
||||
>
|
||||
<PlusIcon size={16} />
|
||||
</button>
|
||||
<motion.div
|
||||
key={tableNumber}
|
||||
initial={{ scale: 1 }}
|
||||
animate={{ scale: [1.2, 0.95, 1] }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className="text-sm2 pt-0.5 font-semibold"
|
||||
>
|
||||
{tableNumber}
|
||||
</motion.div>
|
||||
<button
|
||||
onClick={() => decrementTableNumber()}
|
||||
className="bg-white hover:bg-white/60 size-6 place-items-center active:bg-white/30 rounded-sm"
|
||||
>
|
||||
<MinusIcon size={16} />
|
||||
</button>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='h-full bg-inherit flex flex-col gap-5'>
|
||||
<div className='grid grid-cols-3 items-center py-4 '>
|
||||
<span></span>
|
||||
<h1 className='text-sm2 place-self-center font-medium'>{t("Heading")}</h1>
|
||||
<ArrowLeft
|
||||
className='cursor-pointer place-self-end'
|
||||
size='24'
|
||||
color='currentColor'
|
||||
onClick={() => { router.back() }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<section
|
||||
className="bg-container rounded-container box-shadow-normal p-4">
|
||||
<div className="py-3">
|
||||
<h3 className="text-sm2 font-medium leading-5">{t("SectionShipping.Title")}</h3>
|
||||
<Combobox
|
||||
className='relative mt-6'
|
||||
icon={Box}
|
||||
title=''
|
||||
searchable={false}
|
||||
options={deliveryOptions}
|
||||
selectedId={deliveryType}
|
||||
onSelectionChange={(e, i) => changeDeliveryType(String(i))}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{addressSection()}
|
||||
{tableSection()}
|
||||
|
||||
<section
|
||||
className="bg-container rounded-container box-shadow-normal p-4">
|
||||
<div className="py-3">
|
||||
<h3 className="text-sm2 font-medium leading-5">{t("SectionPayment.Title")}</h3>
|
||||
|
||||
<div className='flex flex-col gap-5 mt-6'>
|
||||
{paymentOptions.map(({ id, label, icon: Icon }) => (
|
||||
<div key={id} className='flex items-center'>
|
||||
|
||||
<label className='flex items-center gap-2 w-full' htmlFor={`paymentMethod${id}`}>
|
||||
<Icon
|
||||
size={16}
|
||||
color='currentColor'
|
||||
className='mr-2'
|
||||
/>
|
||||
<span className='text-xs mt-0.5'>{label}</span>
|
||||
</label>
|
||||
<input
|
||||
checked={paymentType === id}
|
||||
onChange={() => changePaymentType(id)}
|
||||
type='radio'
|
||||
name='paymentMethod'
|
||||
id={`paymentMethod${id}`}
|
||||
className='size-4 accent-primary' />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
className="bg-container rounded-container box-shadow-normal p-4">
|
||||
<div className="py-3">
|
||||
<h3 className="text-sm2 font-medium leading-5">{t("SectionCoupon.Title")}</h3>
|
||||
|
||||
<div className='flex flex-col gap-5 mt-6'>
|
||||
{couponOptions.map(({ id, label, icon: Icon }) => (
|
||||
<div key={id} className='flex items-center'>
|
||||
|
||||
<label className='flex items-center gap-2 w-full' htmlFor={`couponType${id}`}>
|
||||
<Icon
|
||||
size={16}
|
||||
color='currentColor'
|
||||
className='mr-2'
|
||||
/>
|
||||
<span className='text-xs mt-0.5'>{label}</span>
|
||||
</label>
|
||||
<input
|
||||
checked={couponType === id}
|
||||
onChange={() => changeCouponType(id)}
|
||||
type='radio'
|
||||
name='couponType'
|
||||
id={`couponType${id}`}
|
||||
className='size-4 accent-primary' />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Combobox
|
||||
className={clsx(
|
||||
'relative mt-6',
|
||||
couponType === '0' ? 'block' : 'hidden',
|
||||
couponCode.length === 0 && 'text-border **:stroke-border'
|
||||
)}
|
||||
icon={TicketDiscount}
|
||||
placeholder={t("SectionCoupon.InputCouponCode.Placeholder")}
|
||||
title=''
|
||||
searchable={false}
|
||||
options={couponDropdownOptions}
|
||||
selectedId={couponCode}
|
||||
onSelectionChange={(e, i) => changeCouponCode(String(i))}
|
||||
/>
|
||||
|
||||
<InputField
|
||||
autoComplete='off'
|
||||
className={clsx(
|
||||
'relative mt-6',
|
||||
couponType === '1' ? '' : 'hidden!',
|
||||
couponCodeError.trim() === 'valid' && 'text-emerald-400 **:stroke-emerald-400 ring ring-emerald-400'
|
||||
)}
|
||||
placeholder={t("SectionCoupon.InputCouponCode.Placeholder")}
|
||||
htmlFor={'couponCode'}
|
||||
onChange={(e) => changeCouponCode(e.target.value)}
|
||||
value={couponCode}
|
||||
/>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
className="">
|
||||
<div className="py-3 pb-10">
|
||||
<div className='w-full flex justify-between items-center gap-2'>
|
||||
<h3 className="text-sm2 font-medium leading-5 inline-block">{t("SectionSummary.Title")}</h3>
|
||||
<button
|
||||
className='text-sm2 text-primary cursor-pointer'
|
||||
onClick={toggleCartModal}
|
||||
>
|
||||
{t("SectionSummary.ButtonViewCart")}
|
||||
<ChevronLeft className='inline-block mr-1 mb-0.5 stroke-primary' size='16' />
|
||||
</button>
|
||||
</div>
|
||||
<div className='mt-6 text-sm2 grid grid-cols-2 gap-4'>
|
||||
<span className=''>{t("SectionSummary.SumOfItemsLabel")}</span>
|
||||
<span className='font-medium place-self-end '>100,000 T</span>
|
||||
<span className=''>{t("SectionSummary.DeliveryLabel")}</span>
|
||||
<span className='font-medium place-self-end '>20,000 T</span>
|
||||
<span className='text-emerald-600'>{t("SectionSummary.DiscountLabel")}</span>
|
||||
<span className='font-medium place-self-end text-emerald-600'>10,000 T</span>
|
||||
<span className='font-medium '>{t("SectionSummary.TotalLabel")}</span>
|
||||
<span className='font-bold place-self-end'>110,000 T</span>
|
||||
</div>
|
||||
<Button className='mt-6'>
|
||||
{t("ButtonSubmit")}
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<AnimatedBottomSheet
|
||||
title={t("CartModal.Title")}
|
||||
visible={cartModal}
|
||||
onClick={toggleCartModal}
|
||||
>
|
||||
<div></div>
|
||||
</AnimatedBottomSheet>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default OrderDetailInex
|
||||
Reference in New Issue
Block a user