Files
dmenu-admin/src/pages/food/Update.tsx
T
2025-12-17 09:37:53 +03:30

202 lines
6.8 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 { 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 { useNavigate, 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, 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
},
validationSchema: Yup.object().shape({
title: Yup.string().required('نام غذا الزامی است'),
desc: Yup.string().required('توضیحات غذا الزامی است'),
categoryId: Yup.string().required('دسته‌بندی الزامی است'),
price: Yup.number().required('قیمت الزامی است').min(0, 'قیمت باید مثبت باشد'),
prepareTime: Yup.number().required('زمان آماده‌سازی الزامی است').min(0, 'زمان آماده‌سازی باید مثبت باشد'),
discount: Yup.number().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(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 || [],
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
})
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 w-full justify-between items-center'>
<div className='text-lg font-light'>
ویرایش غذا
</div>
<div>
<Button
className='px-5'
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 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