update food

This commit is contained in:
hamid zarghami
2025-11-15 14:45:04 +03:30
parent 0fd87e99f2
commit eaa9ef2a9a
18 changed files with 609 additions and 61 deletions
+219
View File
@@ -0,0 +1,219 @@
import { type FC, useState, useEffect } from 'react'
import { useFormik } from 'formik'
import * as Yup from 'yup'
import { TickCircle } from 'iconsax-react'
import { toast } from 'react-toastify'
import { useParams } from 'react-router-dom'
import Button from '@/components/Button'
import CreateFoodSidebar from './components/CreateFoodSidebar'
import BasicInfoSection from './components/BasicInfoSection'
import FoodContentSection from './components/FoodContentSection'
import MealTimesSection from './components/MealTimesSection'
import WeekDaysSection from './components/WeekDaysSection'
import ServiceOptionsSection from './components/ServiceOptionsSection'
import type { CreateFoodType } from './types/Types'
import { useUpdateFood, useGetFoodDetails, useGetCategories } from './hooks/useFoodData'
import { useMultipleUpload } from '../uploader/hooks/useUploaderData'
import { Pages } from '@/config/Pages'
import type { ErrorType } from '@/helpers/types'
import { extractErrorMessage } from '@/config/func'
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 } = useUpdateFood()
const { mutate: multipleUpload } = useMultipleUpload()
const categories = categoriesData?.data?.map(category => ({
label: category.title,
value: category.id
})) || []
const food = foodData?.data
const formik = useFormik<CreateFoodType>({
initialValues: {
title: '',
desc: '',
content: [],
categoryIds: [],
price: 0,
discount: 0,
points: 0,
prepareTime: 0,
stock: 0,
stockDefault: 0,
breakfast: false,
noon: false,
dinner: false,
mon: false,
tue: false,
wed: false,
thu: false,
fri: false,
sat: false,
sun: false,
pickupServe: false,
inPlaceServe: false,
isActive: true,
images: []
},
validationSchema: Yup.object().shape({
title: Yup.string().required('نام غذا الزامی است'),
desc: Yup.string().required('توضیحات غذا الزامی است'),
categoryIds: Yup.array().min(1, 'حداقل یک دسته‌بندی الزامی است'),
price: Yup.number().required('قیمت الزامی است').min(0, 'قیمت باید مثبت باشد'),
prepareTime: Yup.number().required('زمان آماده‌سازی الزامی است').min(0, 'زمان آماده‌سازی باید مثبت باشد'),
stock: Yup.number().required('موجودی الزامی است').min(0, 'موجودی باید مثبت باشد'),
stockDefault: Yup.number().required('موجودی پیش‌فرض الزامی است').min(0, 'موجودی پیش‌فرض باید مثبت باشد'),
points: Yup.number().min(0, 'امتیاز باید مثبت باشد'),
discount: Yup.number().min(0, 'تخفیف باید مثبت باشد'),
content: 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,
images: allImages,
content: values.content.filter(item => item && item.trim().length > 0)
}
updateFood({ id, params: foodData }, {
onSuccess: () => {
toast.success('غذا با موفقیت به‌روزرسانی شد')
window.location.href = Pages.foods.list
},
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 || [],
categoryIds: food.categories?.map(cat => cat.id) || [],
price: food.price || 0,
discount: food.discount || 0,
points: food.points || 0,
prepareTime: food.prepareTime || 0,
stock: food.stock || 0,
stockDefault: food.stockDefault || 0,
breakfast: food.breakfast || false,
noon: food.noon || false,
dinner: food.dinner || false,
mon: food.mon || false,
tue: food.tue || false,
wed: food.wed || false,
thu: food.thu || false,
fri: food.fri || false,
sat: food.sat || false,
sun: food.sun || false,
pickupServe: food.pickupServe || false,
inPlaceServe: food.inPlaceServe || false,
isActive: food.isActive || false,
images: food.images || []
})
setIsActive(food.isActive || 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 w-full justify-between items-center'>
<div className='text-lg font-light'>
ویرایش غذا
</div>
<div>
<Button
className='px-5'
onClick={() => formik.handleSubmit()}
>
<div className='flex gap-2 items-center'>
<TickCircle className='size-5' color='white' />
<div>ذخیره تغییرات</div>
</div>
</Button>
</div>
</div>
<div className='flex gap-6 mt-6'>
<div className='flex-1'>
<div className='bg-white 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>
<CreateFoodSidebar
isActive={isActive}
isSpecial={isSpecial}
onChangeActive={setIsActive}
onChangeSpecial={setIsSpecial}
onChangeImages={setImageFiles}
existingImages={existingImages}
onChangeExistingImages={setExistingImages}
/>
</div>
</div>
)
}
export default UpdateFood