diff --git a/src/app/[name]/(Main)/[id]/page.tsx b/src/app/[name]/(Main)/[id]/page.tsx index 83d611b..919df6e 100644 --- a/src/app/[name]/(Main)/[id]/page.tsx +++ b/src/app/[name]/(Main)/[id]/page.tsx @@ -3,7 +3,7 @@ import { useCart } from "@/app/[name]/(Main)/cart/hook/useCart"; import MinusIcon from "@/components/icons/MinusIcon"; import PlusIcon from "@/components/icons/PlusIcon"; -import { toast } from "@/components/Toast"; +import { toast, toastLoginRequired } from "@/components/Toast"; import { getToken } from "@/lib/api/func"; import { ef } from "@/lib/helpers/utfNumbers"; import { motion } from "framer-motion"; @@ -52,7 +52,7 @@ function FoodPage({}: Props) { const token = await getToken(); if (!token || !isSuccess) { - toast("ابتدا لاگین کنید", "error"); + toastLoginRequired(() => router.push(`/${name}/auth`), "error"); return; } diff --git a/src/components/Toast.tsx b/src/components/Toast.tsx index 8a83b89..a7c4cf6 100644 --- a/src/components/Toast.tsx +++ b/src/components/Toast.tsx @@ -2,11 +2,17 @@ import { CloseCircle, InfoCircle, TickCircle } from 'iconsax-react'; import React, { useState, useEffect } from 'react'; +interface ToastAction { + label: string; + onClick: () => void; +} + interface Toast { id: string; message: string; type?: 'success' | 'error' | 'info'; isExiting?: boolean; + action?: ToastAction; } let addToast: (toast: Toast) => void; @@ -18,7 +24,8 @@ const ToastContainer: React.FC = () => { const showToast = (toast: Toast) => { setToasts((prev) => [...prev, toast]); - // حذف خودکار بعد از ۳ ثانیه + const dismissAfter = toast.action ? 6000 : 3000; + setTimeout(() => { setToasts((prev) => prev.map(t => t.id === toast.id ? { ...t, isExiting: true } : t @@ -28,7 +35,16 @@ const ToastContainer: React.FC = () => { setTimeout(() => { setToasts((prev) => prev.filter((t) => t.id !== toast.id)); }, 300); // مدت زمان انیمیشن خروج - }, 3000); + }, dismissAfter); + }; + + const dismissToast = (id: string) => { + setToasts((prev) => prev.map((t) => + t.id === id ? { ...t, isExiting: true } : t + )); + setTimeout(() => { + setToasts((prev) => prev.filter((t) => t.id !== id)); + }, 300); }; // تخصیص تابع نمایش toast به متغیر سراسری @@ -38,36 +54,76 @@ const ToastContainer: React.FC = () => { return (
- {toasts.map((toast) => ( -
{ + const handleAction = () => { + toast.action?.onClick(); + dismissToast(toast.id); + }; + + return ( +
{ + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + handleAction(); + } + } : undefined} + className={`px-4 flex items-center gap-2 backdrop-blur-2xl h-16 min-w-[300px] rounded-2xl shadow-md ${toast.isExiting ? 'animate-slide-out-right' : 'animate-slide-in-right'} ${toast.type === 'success' ? 'bg-white/70 text-black' : toast.type === 'error' ? 'bg-white/70 text-black' : 'bg-white/70 text-black' - }`} - style={{ - animationFillMode: 'forwards', - animationDuration: '0.3s', - animationTimingFunction: 'ease-out' - }} - > - { - toast.type === 'success' ? : - toast.type === 'error' ? : - - } - {toast.message} -
- ))} + } ${toast.action ? 'cursor-pointer active:scale-[0.98] transition-transform' : ''}`} + style={{ + animationFillMode: 'forwards', + animationDuration: '0.3s', + animationTimingFunction: 'ease-out' + }} + > +
+ { + toast.type === 'success' ? : + toast.type === 'error' ? : + + } + {toast.message} +
+ {toast.action && ( + + {toast.action.label} + + )} +
+ ); + })}
); }; -export const toast = (message?: string, type: 'success' | 'error' | 'info' = 'info') => { - addToast({ id: Date.now().toString(), message: message || '', type }); +type ToastOptions = { + action?: ToastAction; +}; + +export const toast = ( + message?: string, + type: 'success' | 'error' | 'info' = 'info', + options?: ToastOptions +) => { + addToast({ id: Date.now().toString(), message: message || '', type, action: options?.action }); +}; + +export const toastLoginRequired = ( + onLogin: () => void, + type: 'success' | 'error' | 'info' = 'info' +) => { + toast('ابتدا لاگین کنید', type, { + action: { label: 'ورود', onClick: onLogin }, + }); }; export default ToastContainer; \ No newline at end of file diff --git a/src/components/menu/SideMenu.tsx b/src/components/menu/SideMenu.tsx index ec1f926..cae2e4c 100644 --- a/src/components/menu/SideMenu.tsx +++ b/src/components/menu/SideMenu.tsx @@ -18,7 +18,7 @@ import useToggle from '@/hooks/helpers/useToggle'; import { useGetAbout } from '@/app/[name]/(Main)/about/hooks/useAboutData'; import Image from 'next/image'; import { useGetProfile } from '@/app/[name]/(Profile)/profile/hooks/userProfileData'; -import { toast } from '../Toast'; +import { toast, toastLoginRequired } from '../Toast'; type MenuItemType = { href: string | undefined; @@ -203,7 +203,7 @@ function SideMenu({ menuState, toggleMenuState, nightModeState, togglenightModeS const handleNotificationClick = (e: React.MouseEvent) => { e.preventDefault(); if (!isLoggedIn) { - toast('ابتدا لاگین کنید', 'info'); + toastLoginRequired(() => router.push(`/${name}/auth`), 'info'); } else { router.push(`/${name}/notifications`); } diff --git a/src/components/navigation/BottomNavBar.tsx b/src/components/navigation/BottomNavBar.tsx index 0183765..aafa1a7 100644 --- a/src/components/navigation/BottomNavBar.tsx +++ b/src/components/navigation/BottomNavBar.tsx @@ -14,7 +14,7 @@ import { useCart } from '@/app/[name]/(Main)/cart/hook/useCart'; import { Building } from 'iconsax-react'; import clsx from 'clsx'; import { useGetProfile } from '@/app/[name]/(Profile)/profile/hooks/userProfileData'; -import { toast } from '../Toast'; +import { toastLoginRequired } from '../Toast'; type BottomNavBarProps = { onPagerClick?: () => void; @@ -49,8 +49,7 @@ function BottomNavBar({ onPagerClick }: BottomNavBarProps) { router.push(`/${name}/favorite`); } else { e.stopPropagation(); - toast('ابتدا لاگین کنید', 'error'); - router.replace(`/${name}/auth`); + toastLoginRequired(() => router.push(`/${name}/auth`), 'error'); } } diff --git a/src/components/topbar/TopBar.tsx b/src/components/topbar/TopBar.tsx index 610852e..74d03dc 100644 --- a/src/components/topbar/TopBar.tsx +++ b/src/components/topbar/TopBar.tsx @@ -12,7 +12,7 @@ import useToggle from '@/hooks/helpers/useToggle' import LogoutPrompt from '@/features/general/LogoutPrompt' import { useGetProfile } from '@/app/[name]/(Profile)/profile/hooks/userProfileData' import { useGetNotificationsCount } from '@/app/[name]/(Main)/hooks/useMenuData' -import { toast } from '../Toast' +import { toastLoginRequired } from '../Toast' type Props = { profileDropState: boolean, @@ -40,7 +40,7 @@ function TopBar({ profileDropState, toggleProfileDropState, toggleMenuState }: P const handleNotificationClick = (e: React.MouseEvent) => { e.preventDefault(); if (!isLoggedIn) { - toast('ابتدا لاگین کنید', 'info'); + toastLoginRequired(() => router.push(`/${name}/auth`), 'info'); } else { router.push(`/${name}/notifications`); }