Files
dmenu-admin/src/pages/food/Update.tsx
T
hamid zarghami 9f18e33ef6 navigate back
2026-07-04 15:21:31 +03:30

208 lines
7.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Button from "@/components/Button";
import { extractErrorMessage } from "@/config/func";
import type { ErrorType } from "@/helpers/types";
import { useFormik } from "formik";
import { TickCircle } from "iconsax-react";
import { type FC, useEffect, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { toast } from "react-toastify";
import * as Yup from "yup";
import { useMultipleUpload } from "../uploader/hooks/useUploaderData";
import BasicInfoSection from "./components/BasicInfoSection";
import CreateFoodSidebar from "./components/CreateFoodSidebar";
import FoodContentSection from "./components/FoodContentSection";
import MealTimesSection from "./components/MealTimesSection";
import ServiceOptionsSection from "./components/ServiceOptionsSection";
import WeekDaysSection from "./components/WeekDaysSection";
import { useGetCategories, useGetFoodDetails, useUpdateFood } from "./hooks/useFoodData";
import type { CreateFoodType } from "./types/Types";
const UpdateFood: FC = () => {
const { id } = useParams<{ id: string }>();
const { data: foodData, isLoading } = useGetFoodDetails(id || "");
const { data: categoriesData } = useGetCategories();
const [isActive, setIsActive] = useState<boolean>(true);
const [isSpecial, setIsSpecial] = useState<boolean>(false);
const [imageFiles, setImageFiles] = useState<File[]>([]);
const [existingImages, setExistingImages] = useState<string[]>([]);
const { mutate: updateFood, isPending } = useUpdateFood();
const { mutate: multipleUpload, isPending: isUploading } = useMultipleUpload();
const navigate = useNavigate();
const categories =
categoriesData?.data?.map((category) => ({
label: category.title,
value: category.id,
})) || [];
const food = foodData?.data;
const formik = useFormik<CreateFoodType>({
initialValues: {
title: "",
desc: "",
content: [],
categoryId: "",
price: 0,
discount: 0,
prepareTime: 0,
weekDays: [],
mealTypes: [],
pickupServe: false,
inPlaceServe: false,
isActive: true,
images: [],
isSpecialOffer: false,
dailyStock: 0,
availableStock: 0,
order: 0,
},
validationSchema: Yup.object().shape({
title: Yup.string().required("نام غذا الزامی است"),
categoryId: Yup.string().required("دسته‌بندی الزامی است"),
price: Yup.number().required("قیمت الزامی است").min(0, "قیمت باید مثبت باشد"),
prepareTime: Yup.number().required("زمان آماده‌سازی الزامی است").min(0, "زمان آماده‌سازی باید مثبت باشد"),
discount: Yup.number().min(0, "تخفیف باید مثبت باشد"),
dailyStock: Yup.number().required("موجودی روزانه الزامی است").min(0, "موجودی روزانه باید مثبت باشد"),
availableStock: Yup.number().required("موجودی فعلی الزامی است").min(0, "موجودی فعلی باید مثبت باشد"),
content: Yup.array().of(Yup.string()),
weekDays: Yup.array().of(Yup.number()),
mealTypes: Yup.array().of(Yup.string()),
}),
onSubmit: (values) => {
if (!id) {
toast.error("شناسه غذا یافت نشد");
return;
}
const submitFood = (newImageUrls: string[] = []) => {
const allImages = [...values.images, ...newImageUrls];
const foodData: CreateFoodType = {
...values,
isActive,
isSpecialOffer: isSpecial,
images: allImages,
content: values.content.filter((item) => item && item.trim().length > 0),
};
updateFood(
{ id, params: foodData },
{
onSuccess: () => {
toast.success("غذا با موفقیت به‌روزرسانی شد");
navigate(-1);
},
onError: (error: ErrorType) => {
toast.error(extractErrorMessage(error));
},
},
);
};
if (imageFiles.length > 0) {
multipleUpload(imageFiles, {
onSuccess: (response) => {
const imageUrls = response?.data?.map((item) => item.url) || [];
submitFood(imageUrls);
},
onError: (error: ErrorType) => {
toast.error(error?.response?.data?.error?.message[0] || "خطا در آپلود تصاویر");
},
});
} else {
submitFood();
}
},
});
useEffect(() => {
if (food) {
formik.setValues({
title: food.title || "",
desc: food.desc || "",
content: food.content || [],
categoryId: food.category?.id || "",
price: food.price || 0,
discount: food.discount || 0,
prepareTime: food.prepareTime || 0,
weekDays: food.weekDays || [],
mealTypes: food.mealTypes || [],
pickupServe: food.pickupServe || false,
inPlaceServe: food.inPlaceServe || false,
isActive: food.isActive || false,
images: food.images || [],
isSpecialOffer: food.isSpecialOffer || false,
dailyStock: food.inventory?.totalStock || 0,
availableStock: food.inventory?.availableStock || 0,
order: food.order || 0,
});
setIsActive(food.isActive || false);
setIsSpecial(food.isSpecialOffer || false);
setExistingImages(food.images || []);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [food]);
useEffect(() => {
formik.setFieldValue("images", existingImages);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [existingImages]);
if (isLoading) {
return (
<div className="w-full mt-4 flex justify-center items-center">
<div>در حال بارگذاری...</div>
</div>
);
}
if (!food) {
return (
<div className="w-full mt-4 flex justify-center items-center">
<div>غذا یافت نشد</div>
</div>
);
}
return (
<div className="w-full mt-4">
<div className="flex flex-col sm:flex-row w-full justify-between items-start sm:items-center gap-4">
<div className="text-lg font-light">ویرایش غذا</div>
<div>
<Button className="px-5 w-full sm:w-auto" onClick={() => formik.handleSubmit()} isloading={isPending || isUploading}>
<div className="flex gap-2 items-center">
<TickCircle className="size-5" color="white" />
<div>ذخیره تغییرات</div>
</div>
</Button>
</div>
</div>
<div className="flex flex-col lg:flex-row gap-6 mt-6">
<div className="flex-1">
<div className="bg-white py-6 sm:py-8 xl:px-10 px-4 rounded-3xl">
<BasicInfoSection formik={formik} categories={categories} />
<FoodContentSection formik={formik} />
<MealTimesSection formik={formik} />
<WeekDaysSection formik={formik} />
<ServiceOptionsSection formik={formik} />
</div>
</div>
<div className="w-full lg:w-auto">
<CreateFoodSidebar
isActive={isActive}
isSpecial={isSpecial}
onChangeActive={setIsActive}
onChangeSpecial={setIsSpecial}
onChangeImages={setImageFiles}
existingImages={existingImages}
onChangeExistingImages={setExistingImages}
/>
</div>
</div>
</div>
);
};
export default UpdateFood;