diff --git a/src/app/[name]/(Main)/[id]/hooks/useFoodData.ts b/src/app/[name]/(Main)/[id]/hooks/useFoodData.ts index 81514f7..9dfa4e3 100644 --- a/src/app/[name]/(Main)/[id]/hooks/useFoodData.ts +++ b/src/app/[name]/(Main)/[id]/hooks/useFoodData.ts @@ -1,4 +1,4 @@ -import { useQuery } from "@tanstack/react-query"; +import { useMutation, useQuery } from "@tanstack/react-query"; import * as api from "../service/Service"; export const useGetFood = (id: string) => { @@ -7,3 +7,15 @@ export const useGetFood = (id: string) => { queryFn: () => api.getFood(id), }); }; + +export const useAddToFavorite = () => { + return useMutation({ + mutationFn: api.addToFavorite, + }); +}; + +export const useRemoveFromFavorite = () => { + return useMutation({ + mutationFn: api.removeFromFavorite, + }); +}; diff --git a/src/app/[name]/(Main)/[id]/page.tsx b/src/app/[name]/(Main)/[id]/page.tsx index faae84b..6d07e7b 100644 --- a/src/app/[name]/(Main)/[id]/page.tsx +++ b/src/app/[name]/(Main)/[id]/page.tsx @@ -8,9 +8,12 @@ import { motion } from 'framer-motion' import { ArrowLeft, Clock, Cup, Heart, TruckTick } from 'iconsax-react' import Image from 'next/image' import { useParams, useRouter } from 'next/navigation' -import React, { useMemo } from 'react' -import { useGetFood } from './hooks/useFoodData' +import React, { useEffect, useMemo, useState } from 'react' +import { useAddToFavorite, useGetFood, useRemoveFromFavorite } from './hooks/useFoodData' import { useGetAbout } from '../about/hooks/useAboutData' +import { useGetProfile } from '../../(Profile)/profile/hooks/userProfileData' +import { toast } from '@/components/Toast' +import { getToken } from '@/lib/api/func' type Props = object @@ -18,9 +21,13 @@ function FoodPage({ }: Props) { const { id } = useParams(); const router = useRouter(); + const { isSuccess } = useGetProfile(); const { data: food, isLoading } = useGetFood(id as string); const { data: about } = useGetAbout(); const { items, addToCart, removeFromCart } = useCart(); + const [isFavorite, setIsFavorite] = useState(false); + const { mutate: addToFavorite } = useAddToFavorite(); + const { mutate: removeFromFavorite } = useRemoveFromFavorite(); const foodId = food?.data?.id || id as string; const quantity = useMemo(() => { @@ -43,6 +50,52 @@ function FoodPage({ }: Props) { } }; + const handleToggleFavorite = async () => { + if (!foodId) return; + + const token = await getToken(); + if (!token || !isSuccess) { + toast('ابتدا لاگین کنید', 'error'); + return; + } + + // به‌روزرسانی خوش‌بینانه: تغییر state قبل از ارسال درخواست + const previousFavorite = isFavorite; + setIsFavorite(!isFavorite); + + if (previousFavorite) { + removeFromFavorite(foodId, { + onSuccess: () => { + // تایید تغییر در صورت موفقیت + }, + onError: () => { + // بازگرداندن به حالت قبلی در صورت خطا + setIsFavorite(previousFavorite); + toast('خطا در حذف از علاقه‌مندی‌ها', 'error'); + }, + }); + } else { + addToFavorite(foodId, { + onSuccess: () => { + // تایید تغییر در صورت موفقیت + }, + onError: () => { + // بازگرداندن به حالت قبلی در صورت خطا + setIsFavorite(previousFavorite); + toast('خطا در افزودن به علاقه‌مندی‌ها', 'error'); + }, + }); + } + }; + + useEffect(() => { + if (food?.data?.isFavorite) { + setIsFavorite(true); + } else { + setIsFavorite(false); + } + }, [food?.data?.isFavorite]); + if (isLoading) { return (
@@ -104,8 +157,15 @@ function FoodPage({ }: Props) {
{foodName}
-
diff --git a/src/app/[name]/(Main)/[id]/service/Service.ts b/src/app/[name]/(Main)/[id]/service/Service.ts index f5eef7e..0197371 100644 --- a/src/app/[name]/(Main)/[id]/service/Service.ts +++ b/src/app/[name]/(Main)/[id]/service/Service.ts @@ -5,3 +5,13 @@ export const getFood = async (id: string): Promise => { const { data } = await api.get(`/public/foods/${id}`); return data; }; + +export const addToFavorite = async (foodId: string) => { + const { data } = await api.post(`/public/foods/favorite/${foodId}`); + return data; +}; + +export const removeFromFavorite = async (foodId: string) => { + const { data } = await api.delete(`/public/foods/favorite/${foodId}`); + return data; +}; diff --git a/src/app/[name]/(Main)/transactions/discount/page.tsx b/src/app/[name]/(Main)/transactions/discount/page.tsx index 9dee35b..731559e 100644 --- a/src/app/[name]/(Main)/transactions/discount/page.tsx +++ b/src/app/[name]/(Main)/transactions/discount/page.tsx @@ -107,7 +107,7 @@ function TransactionsIndex() { کپی کد -
+

{coupon.code}

diff --git a/src/app/[name]/(Main)/types/Types.ts b/src/app/[name]/(Main)/types/Types.ts index fc358d6..25d0027 100644 --- a/src/app/[name]/(Main)/types/Types.ts +++ b/src/app/[name]/(Main)/types/Types.ts @@ -20,14 +20,24 @@ export type CategoriesResponse = BaseResponse; export type FoodImage = string | { url: string; alt?: string | null }; +export interface RestaurantRef { + id: string; +} + +export interface InventoryRef { + id: string; +} + +export type MealType = "breakfast" | "lunch" | "dinner" | "snack"; + export interface Food { id: string; createdAt: string; updatedAt: string; deletedAt: string | null; - restaurant: string; + restaurant: RestaurantRef; category: Category; - inventory: string; + inventory: InventoryRef; title: string; desc: string; content: string[]; @@ -35,7 +45,7 @@ export interface Food { order: number | null; prepareTime: number | null; weekDays: number[]; - mealTypes: unknown[]; + mealTypes: MealType[]; isActive: boolean; images: string[]; inPlaceServe: boolean; @@ -43,6 +53,9 @@ export interface Food { score: number; discount: number; isSpecialOffer: boolean; + reviews: unknown[]; + favorites: unknown[]; + isFavorite: boolean; // فیلدهای قدیمی برای سازگاری با سایر بخش‌های کد name?: string; foodName?: string;