cart dynamic
This commit is contained in:
@@ -1,131 +1,135 @@
|
||||
'use client';
|
||||
|
||||
import Button from '@/components/button/PrimaryButton';
|
||||
import MenuItem from '@/components/listview/MenuItem';
|
||||
import MenuItemRenderer from '@/components/listview/MenuItemRenderer';
|
||||
import { useReceiptStore } from '@/zustand/receiptStore';
|
||||
import { motion } from 'framer-motion';
|
||||
import { ArrowLeft, Trash } from 'iconsax-react';
|
||||
import { PlusIcon, MinusIcon } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import React from 'react'
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Add, ArrowLeft, Minus, Trash } from 'iconsax-react';
|
||||
import { useGetFoods } from '@/app/[name]/(Main)/hooks/useMenuData';
|
||||
import type { Food } from '@/app/[name]/(Main)/types/Types';
|
||||
|
||||
type Props = object
|
||||
|
||||
const CartIndex = ({ }: Props) => {
|
||||
const { t } = useTranslation('parallels', {
|
||||
keyPrefix: 'Cart'
|
||||
});
|
||||
const CartIndex = () => {
|
||||
const { data: foodsResponse, isFetching } = useGetFoods();
|
||||
const foods = React.useMemo(() => foodsResponse?.data ?? [], [foodsResponse?.data]);
|
||||
const { t } = useTranslation('parallels', { keyPrefix: 'Cart' });
|
||||
const router = useRouter();
|
||||
const quantity = useReceiptStore(state => state.items[0]?.quantity || 0);
|
||||
const increment = useReceiptStore(state => state.increment);
|
||||
const decrement = useReceiptStore(state => state.decrement);
|
||||
const receiptItems = useReceiptStore((state) => state.items);
|
||||
const clear = useReceiptStore((state) => state.clear);
|
||||
|
||||
const cartFoods = React.useMemo(() => {
|
||||
if (!foods.length) return [];
|
||||
return Object.entries(receiptItems)
|
||||
.filter(([, detail]) => detail?.quantity)
|
||||
.map(([id]) =>
|
||||
foods.find((foodItem) => String(foodItem.id) === String(id))
|
||||
)
|
||||
.filter((food): food is Food => Boolean(food));
|
||||
}, [foods, receiptItems]);
|
||||
|
||||
const totalPrice = React.useMemo(() => {
|
||||
return cartFoods.reduce((sum, food) => {
|
||||
const qty = receiptItems[String(food.id)]?.quantity ?? 0;
|
||||
return sum + (food.price ?? 0) * qty;
|
||||
}, 0);
|
||||
}, [cartFoods, receiptItems]);
|
||||
|
||||
const isCartEmpty = cartFoods.length === 0;
|
||||
const formatPrice = React.useCallback(
|
||||
(value: number) => value.toLocaleString('fa-IR'),
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className='bg-inherit flex flex-col h-full'>
|
||||
<div className='grid grid-cols-3 items-center py-4 '>
|
||||
<div className='grid grid-cols-3 items-center py-4'>
|
||||
<Trash
|
||||
className='cursor-pointer place-self-start'
|
||||
size='24'
|
||||
color='currentColor'
|
||||
onClick={() => { router.back() }}
|
||||
onClick={clear}
|
||||
/>
|
||||
<h1 className='text-sm2 place-self-center font-medium'>{t("Heading")}</h1>
|
||||
<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() }}
|
||||
onClick={() => router.back()}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='flex overflow-y-auto noscrollbar flex-col h-full pt-4' dir='rtl'>
|
||||
|
||||
<ul className="pb-10 flex-1">
|
||||
<li className=''>
|
||||
<div className='grid grid-cols-2 justify-between'>
|
||||
<div className='text-sm'>کباب چوبی ژیوان (سیخ چوبی)</div>
|
||||
<div className='text-sm2 font-medium text-end'>69.000 T</div>
|
||||
<div className='flex overflow-y-auto noscrollbar flex-col h-full pt-4 gap-6' dir='rtl'>
|
||||
<div className='flex-1 space-y-4 pb-6'>
|
||||
{isFetching && !foods.length ? (
|
||||
<div className='flex flex-col items-center justify-center gap-2 py-12 text-sm2 text-muted-foreground'>
|
||||
<span className='h-4 w-4 animate-spin rounded-full border border-dashed border-foreground border-t-transparent'></span>
|
||||
<p>{t('LoadingCart', { defaultValue: 'در حال دریافت سبد خرید...' })}</p>
|
||||
</div>
|
||||
<div className='mt-6 flex justify-between items-center'>
|
||||
<motion.div
|
||||
whileTap={{ scale: 1.05 }}
|
||||
className="bg-background active:drop-shadow-xs max-w-[115px] rounded-md w-full h-8 inline-flex p-1 justify-between items-center gap-2"
|
||||
>
|
||||
{quantity <= 0 ? (
|
||||
<button
|
||||
onClick={() => increment(0)}
|
||||
className="inline-flex w-full justify-center items-center gap-2"
|
||||
>
|
||||
<PlusIcon size={16} />
|
||||
<span className="text-sm2 pt-0.5 font-medium">افزودن</span>
|
||||
</button>
|
||||
) : (
|
||||
<>
|
||||
<button
|
||||
onClick={() => increment(0)}
|
||||
className="bg-container hover:bg-container/60 active:bg-container/30 rounded-sm p-1"
|
||||
>
|
||||
<PlusIcon size={16} />
|
||||
</button>
|
||||
<motion.div
|
||||
key={quantity}
|
||||
initial={{ scale: 1 }}
|
||||
animate={{ scale: [1.2, 0.95, 1] }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className="text-sm2 pt-0.5 font-semibold"
|
||||
>
|
||||
{quantity}
|
||||
</motion.div>
|
||||
<button
|
||||
onClick={() => decrement(0)}
|
||||
className="bg-container hover:bg-container/60 active:bg-container/30 rounded-sm p-1"
|
||||
>
|
||||
{quantity > 1 ? <MinusIcon size={16} /> : <Trash className='stroke-foreground' size={16} />} {/* Use PlusIcon for decrement if quantity is 1 or less */}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</motion.div>
|
||||
) : isCartEmpty ? (
|
||||
<div className='flex flex-col items-center justify-center gap-2 py-12 text-sm2 text-muted-foreground'>
|
||||
<p>{t('EmptyStateTitle', { defaultValue: 'سبد خرید شما خالی است' })}</p>
|
||||
<p className='text-xs'>
|
||||
{t('EmptyStateDescription', {
|
||||
defaultValue: 'برای افزودن غذا، به منوی رستوران برگردید.',
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
<hr className='my-4 border-1 border-border' />
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
) : (
|
||||
cartFoods.map((food) => (
|
||||
<MenuItemRenderer key={food.id}>
|
||||
<MenuItem food={food} />
|
||||
</MenuItemRenderer>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className='relative'>
|
||||
<h3 className='text-sm'>
|
||||
{t('InputDescription.Label')}
|
||||
</h3>
|
||||
<h3 className='text-sm'>{t('InputDescription.Label')}</h3>
|
||||
<textarea
|
||||
className='w-full px-4 py-2.5 mt-4 text-sm2 leading-6 outline-0 border border-border rounded-normal resize-none focus:ring-0'
|
||||
placeholder={t('InputDescription.Placeholder')}
|
||||
id='description'
|
||||
name='description'
|
||||
></textarea>
|
||||
<span className='absolute top-4 right-2 px-2 bg-background text-foreground text-xs'>
|
||||
|
||||
</span>
|
||||
<span className='absolute top-4 right-2 px-2 bg-background text-foreground text-xs'></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='grid grid-cols-2 pt-4'>
|
||||
<div className='grid grid-rows-2'>
|
||||
<div className='text-xs'>{t('SumOfItemsLabel')}</div>
|
||||
<div className="text-sm font-medium">{t('SumOfItemsValue').replace('{price}', '560.000')}</div>
|
||||
<div className='grid grid-cols-2 items-end gap-4'>
|
||||
<div>
|
||||
<div className='text-sm font-semibold'>
|
||||
{`جمع خرید: ${formatPrice(totalPrice)} تومان`}
|
||||
</div>
|
||||
</div>
|
||||
<Link
|
||||
href={'order/checkout/0'}>
|
||||
<Button>
|
||||
{t('ButtonCheckout')}
|
||||
</Button>
|
||||
href={'order/checkout/0'}
|
||||
onClick={(event) => {
|
||||
if (isCartEmpty) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}}
|
||||
className={isCartEmpty ? 'pointer-events-none opacity-60' : ''}
|
||||
>
|
||||
<Button disabled={isCartEmpty}>{t('ButtonCheckout')}</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{!isCartEmpty && (
|
||||
<div className='flex items-center justify-between rounded-xl border border-border px-4 py-3 text-xs text-muted-foreground'>
|
||||
<span>{t('CartControlsHint', { defaultValue: 'برای ویرایش تعداد، از دکمههای هر آیتم استفاده کنید.' })}</span>
|
||||
<div className='flex items-center gap-1 text-foreground'>
|
||||
<Add size={16} />
|
||||
<Minus size={16} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default CartIndex
|
||||
export default CartIndex;
|
||||
Reference in New Issue
Block a user