align center and favorite

This commit is contained in:
hamid zarghami
2025-12-22 10:00:15 +03:30
parent 59f79f2a3e
commit 7fef7fe56c
5 changed files with 104 additions and 9 deletions
@@ -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,
});
};
+64 -4
View File
@@ -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<boolean>(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 (
<div className='flex items-center justify-center min-h-[400px]'>
@@ -104,8 +157,15 @@ function FoodPage({ }: Props) {
<h5 className="text-base font-bold">
{foodName}
</h5>
<button className='p-2 bg-[#EAECF0] dark:bg-neutral-600 rounded-lg'>
<Heart variant='Bold' size={24} className='fill-primary dark:fill-foreground' />
<button
onClick={handleToggleFavorite}
className='p-2 bg-[#EAECF0] dark:bg-neutral-600 rounded-lg'
>
<Heart
variant={isFavorite ? 'Bold' : 'Outline'}
size={24}
className={isFavorite ? 'fill-primary dark:fill-foreground' : 'stroke-primary dark:stroke-foreground'}
/>
</button>
</div>
@@ -5,3 +5,13 @@ export const getFood = async (id: string): Promise<FoodResponse> => {
const { data } = await api.get<FoodResponse>(`/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;
};
@@ -107,7 +107,7 @@ function TransactionsIndex() {
کپی کد
</Button>
</div>
<div className='w-14'>
<div className='w-14 h-full flex flex-1 justify-center items-center'>
<p className='text-sm2 transform -rotate-90 text-[#B2B2B2] font-medium' aria-label="کد تخفیف">
{coupon.code}
</p>
+16 -3
View File
@@ -20,14 +20,24 @@ export type CategoriesResponse = BaseResponse<Category[]>;
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;