empty data
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
@@ -59,6 +59,8 @@ const CartSummary = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
{!isCartEmpty && (
|
||||||
<>
|
<>
|
||||||
<div className='mt-2'>
|
<div className='mt-2'>
|
||||||
<div className='relative'>
|
<div className='relative'>
|
||||||
@@ -75,11 +77,8 @@ const CartSummary = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div className='fixed bottom-0 left-0 right-0 z-50 bg-white border-t border-border p-4 w-full'>
|
||||||
className={`fixed bottom-0 left-0 right-0 z-50 bg-white border-t border-border p-4 w-full ${isCartEmpty ? 'pointer-events-none opacity-60' : ''}`}
|
|
||||||
>
|
|
||||||
<div className='flex justify-between items-center gap-4'>
|
<div className='flex justify-between items-center gap-4'>
|
||||||
|
|
||||||
<div className='flex flex-col'>
|
<div className='flex flex-col'>
|
||||||
<div className='text-xs text-gray-400'>{t('PayableAmountLabel')}</div>
|
<div className='text-xs text-gray-400'>{t('PayableAmountLabel')}</div>
|
||||||
<div className='text-sm mt-2 font-semibold'>{formatPrice(totalPrice)} تومان</div>
|
<div className='text-sm mt-2 font-semibold'>{formatPrice(totalPrice)} تومان</div>
|
||||||
@@ -88,10 +87,6 @@ const CartSummary = () => {
|
|||||||
<Link
|
<Link
|
||||||
href={'order/checkout/0'}
|
href={'order/checkout/0'}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
if (isCartEmpty) {
|
|
||||||
event.preventDefault();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!isSuccess) {
|
if (!isSuccess) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const redirectUrl = encodeURIComponent(pathname);
|
const redirectUrl = encodeURIComponent(pathname);
|
||||||
@@ -100,11 +95,12 @@ const CartSummary = () => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button className='w-fit! px-10' disabled={isCartEmpty}>{t('ButtonCheckout')}</Button>
|
<Button className='w-fit! px-10'>{t('ButtonCheckout')}</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* {!isCartEmpty && (
|
{/* {!isCartEmpty && (
|
||||||
<div className='flex items-center justify-between rounded-xl border border-border px-4 py-3 text-xs text-muted-foreground'>
|
<div className='flex items-center justify-between rounded-xl border border-border px-4 py-3 text-xs text-muted-foreground'>
|
||||||
|
|||||||
@@ -4,22 +4,37 @@ import React from 'react';
|
|||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { ArrowLeft, Trash } from 'iconsax-react';
|
import { ArrowLeft, Trash } from 'iconsax-react';
|
||||||
|
import Image from 'next/image';
|
||||||
import { useCart } from './hook/useCart';
|
import { useCart } from './hook/useCart';
|
||||||
import CartItemsList from './components/CartItemsList';
|
|
||||||
import CartSummary from './components/CartSummary';
|
import CartSummary from './components/CartSummary';
|
||||||
import Prompt from '@/components/utils/Prompt';
|
import Prompt from '@/components/utils/Prompt';
|
||||||
import { useGetFoods } from '@/app/[name]/(Main)/hooks/useMenuData';
|
import { useGetFoods } from '@/app/[name]/(Main)/hooks/useMenuData';
|
||||||
import { CartSummarySkeleton } from './components/CartSkeleton';
|
import VerticalScrollView from '@/components/listview/VerticalScrollView';
|
||||||
|
import MenuItem from '@/components/listview/MenuItem';
|
||||||
|
import MenuItemRenderer from '@/components/listview/MenuItemRenderer';
|
||||||
|
import type { Food } from '@/app/[name]/(Main)/types/Types';
|
||||||
|
|
||||||
const CartIndex = () => {
|
const CartIndex = () => {
|
||||||
const { t } = useTranslation('parallels', { keyPrefix: 'Cart' });
|
const { t } = useTranslation('parallels', { keyPrefix: 'Cart' });
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { clearCart } = useCart();
|
const { clearCart, items } = useCart();
|
||||||
const [showClearConfirm, setShowClearConfirm] = React.useState(false);
|
const [showClearConfirm, setShowClearConfirm] = React.useState(false);
|
||||||
const { data: foodsResponse, isFetching } = useGetFoods();
|
const { data: foodsResponse, isFetching } = useGetFoods();
|
||||||
const foods = React.useMemo(() => foodsResponse?.data ?? [], [foodsResponse?.data]);
|
const foods = React.useMemo(() => foodsResponse?.data ?? [], [foodsResponse?.data]);
|
||||||
const isLoading = isFetching && !foods.length;
|
const isLoading = isFetching && !foods.length;
|
||||||
|
|
||||||
|
const cartFoods = React.useMemo(() => {
|
||||||
|
if (!foods.length) return [];
|
||||||
|
return Object.entries(items)
|
||||||
|
.filter(([, detail]) => detail?.quantity && detail.quantity > 0)
|
||||||
|
.map(([id]) =>
|
||||||
|
foods.find((foodItem) => String(foodItem.id) === String(id))
|
||||||
|
)
|
||||||
|
.filter((food): food is Food => Boolean(food));
|
||||||
|
}, [foods, items]);
|
||||||
|
|
||||||
|
const isCartEmpty = cartFoods.length === 0;
|
||||||
|
|
||||||
const handleClearCart = (e: React.MouseEvent) => {
|
const handleClearCart = (e: React.MouseEvent) => {
|
||||||
e?.preventDefault();
|
e?.preventDefault();
|
||||||
e?.stopPropagation();
|
e?.stopPropagation();
|
||||||
@@ -34,14 +49,18 @@ const CartIndex = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='bg-inherit flex flex-col h-full'>
|
<div className='overflow-y-auto h-full noscrollbar flex flex-col'>
|
||||||
<div className='grid grid-cols-3 items-center py-4'>
|
<div className='grid grid-cols-3 items-center'>
|
||||||
|
{isCartEmpty ? (
|
||||||
|
<span></span>
|
||||||
|
) : (
|
||||||
<Trash
|
<Trash
|
||||||
className='cursor-pointer place-self-start'
|
className='cursor-pointer place-self-start'
|
||||||
size='24'
|
size='24'
|
||||||
color='currentColor'
|
color='currentColor'
|
||||||
onClick={() => setShowClearConfirm(true)}
|
onClick={() => setShowClearConfirm(true)}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
<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
|
<ArrowLeft
|
||||||
className='cursor-pointer place-self-end'
|
className='cursor-pointer place-self-end'
|
||||||
@@ -51,9 +70,40 @@ const CartIndex = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='flex overflow-y-auto noscrollbar flex-col h-full pt-4 gap-4 pb-24' dir='rtl'>
|
<div className="mt-8 flex-1 h-full">
|
||||||
<CartItemsList />
|
{isLoading ? (
|
||||||
{isLoading ? <CartSummarySkeleton /> : <CartSummary />}
|
<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>در حال دریافت سبد خرید...</p>
|
||||||
|
</div>
|
||||||
|
) : isCartEmpty ? (
|
||||||
|
<div className='flex flex-col items-center justify-center gap-4 h-full'>
|
||||||
|
<Image
|
||||||
|
src='/assets/images/cart.png'
|
||||||
|
alt='cart'
|
||||||
|
width={120}
|
||||||
|
height={120}
|
||||||
|
className='object-contain'
|
||||||
|
/>
|
||||||
|
<div className='flex flex-col items-center gap-2 text-sm2 text-muted-foreground'>
|
||||||
|
<p>{t('EmptyStateTitle', { defaultValue: 'سبد خرید شما خالی است' })}</p>
|
||||||
|
<p className='text-xs'>
|
||||||
|
{t('EmptyStateDescription', {
|
||||||
|
defaultValue: 'برای افزودن غذا، به منوی رستوران برگردید.',
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<VerticalScrollView className="overflow-y-auto h-full pb-24">
|
||||||
|
{cartFoods.map((food) => (
|
||||||
|
<MenuItemRenderer key={food.id}>
|
||||||
|
<MenuItem food={food} />
|
||||||
|
</MenuItemRenderer>
|
||||||
|
))}
|
||||||
|
<CartSummary />
|
||||||
|
</VerticalScrollView>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={showClearConfirm ? 'fixed inset-0 z-1001' : 'pointer-events-none fixed inset-0 z-1001'}>
|
<div className={showClearConfirm ? 'fixed inset-0 z-1001' : 'pointer-events-none fixed inset-0 z-1001'}>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { ef } from '@/lib/helpers/utfNumbers';
|
|||||||
import { ArrowLeft, Trash } from 'iconsax-react';
|
import { ArrowLeft, Trash } from 'iconsax-react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import Image from 'next/image';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useGetNotifications, useDeleteNotification } from './hooks/useNotificationData';
|
import { useGetNotifications, useDeleteNotification } from './hooks/useNotificationData';
|
||||||
import type { Notification } from './types/Types';
|
import type { Notification } from './types/Types';
|
||||||
@@ -30,7 +31,7 @@ const formatTime = (dateString: string): string => {
|
|||||||
export default function NotificationsIndex({ }: Props) {
|
export default function NotificationsIndex({ }: Props) {
|
||||||
const { t } = useTranslation('notifications')
|
const { t } = useTranslation('notifications')
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { data, isLoading, isError } = useGetNotifications();
|
const { data, isLoading } = useGetNotifications();
|
||||||
const { mutate: deleteNotification } = useDeleteNotification();
|
const { mutate: deleteNotification } = useDeleteNotification();
|
||||||
|
|
||||||
const notifications = React.useMemo(() => {
|
const notifications = React.useMemo(() => {
|
||||||
@@ -41,10 +42,9 @@ export default function NotificationsIndex({ }: Props) {
|
|||||||
deleteNotification(id);
|
deleteNotification(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isLoading) {
|
|
||||||
return (
|
return (
|
||||||
<div className='h-full bg-inherit relative flex flex-col lg:gap-4'>
|
<div className='overflow-y-auto h-full noscrollbar flex flex-col'>
|
||||||
<div className='grid grid-cols-3 items-center py-4 '>
|
<div className='grid grid-cols-3 items-center'>
|
||||||
<span></span>
|
<span></span>
|
||||||
<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
|
<ArrowLeft
|
||||||
@@ -54,47 +54,27 @@ export default function NotificationsIndex({ }: Props) {
|
|||||||
onClick={() => { router.back() }}
|
onClick={() => { router.back() }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-8 flex-1 h-full">
|
||||||
|
{isLoading ? (
|
||||||
<div className='flex flex-col items-center justify-center gap-2 py-12 text-sm2 text-muted-foreground'>
|
<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>
|
<span className='h-4 w-4 animate-spin rounded-full border border-dashed border-foreground border-t-transparent'></span>
|
||||||
<p>در حال دریافت اعلانها...</p>
|
<p>در حال دریافت اعلانها...</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
) : notifications.length === 0 ? (
|
||||||
);
|
<div className='flex flex-col items-center justify-center gap-4 h-full'>
|
||||||
}
|
<Image
|
||||||
|
src='/assets/images/notification.png'
|
||||||
if (isError || !notifications.length) {
|
alt='notification'
|
||||||
return (
|
width={120}
|
||||||
<div className='h-full bg-inherit relative flex flex-col lg:gap-4'>
|
height={120}
|
||||||
<div className='grid grid-cols-3 items-center py-4 '>
|
className='object-contain'
|
||||||
<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>
|
<div className='flex flex-col items-center gap-2 text-sm2 text-muted-foreground'>
|
||||||
<div className='flex flex-col items-center justify-center gap-2 py-12 text-sm2 text-muted-foreground'>
|
|
||||||
<p>اعلانی وجود ندارد</p>
|
<p>اعلانی وجود ندارد</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
) : (
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='h-full bg-inherit relative flex flex-col lg:gap-4'>
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<ul className='flex flex-col gap-4 pb-20'>
|
<ul className='flex flex-col gap-4 pb-20'>
|
||||||
{notifications.map((notification: Notification) => {
|
{notifications.map((notification: Notification) => {
|
||||||
const isNew = !notification.sentAt;
|
const isNew = !notification.sentAt;
|
||||||
@@ -131,6 +111,8 @@ export default function NotificationsIndex({ }: Props) {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
import React, { useMemo } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import { ArrowLeft } from 'iconsax-react'
|
import { ArrowLeft } from 'iconsax-react'
|
||||||
|
import Image from 'next/image'
|
||||||
import { useGetFavorites } from './hooks/useFavoriteData'
|
import { useGetFavorites } from './hooks/useFavoriteData'
|
||||||
import MenuItem from '@/components/listview/MenuItem'
|
import MenuItem from '@/components/listview/MenuItem'
|
||||||
import MenuItemRenderer from '@/components/listview/MenuItemRenderer'
|
import MenuItemRenderer from '@/components/listview/MenuItemRenderer'
|
||||||
@@ -74,12 +75,21 @@ function FavoritePage() {
|
|||||||
<p>در حال دریافت علاقهمندیها...</p>
|
<p>در حال دریافت علاقهمندیها...</p>
|
||||||
</div>
|
</div>
|
||||||
) : foodItems.length === 0 ? (
|
) : foodItems.length === 0 ? (
|
||||||
<div className='flex flex-col items-center justify-center gap-2 py-12 text-sm2 text-muted-foreground'>
|
<div className='flex flex-col items-center justify-center gap-4 h-full'>
|
||||||
|
<Image
|
||||||
|
src='/assets/images/favorite.png'
|
||||||
|
alt='favorite'
|
||||||
|
width={120}
|
||||||
|
height={120}
|
||||||
|
className='object-contain'
|
||||||
|
/>
|
||||||
|
<div className='flex flex-col items-center gap-2 text-sm2 text-muted-foreground'>
|
||||||
<p>شما هیچ مورد علاقهمندی ثبت نکردهاید</p>
|
<p>شما هیچ مورد علاقهمندی ثبت نکردهاید</p>
|
||||||
<p className='text-xs'>
|
<p className='text-xs'>
|
||||||
برای افزودن غذا به علاقهمندیها، به صفحه جزئیات غذا بروید
|
برای افزودن غذا به علاقهمندیها، به صفحه جزئیات غذا بروید
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<VerticalScrollView className="overflow-y-auto h-full">
|
<VerticalScrollView className="overflow-y-auto h-full">
|
||||||
{foodItems.map((food) => (
|
{foodItems.map((food) => (
|
||||||
|
|||||||
Reference in New Issue
Block a user