navigate back
This commit is contained in:
+149
-171
@@ -1,49 +1,47 @@
|
|||||||
import { type FC, useState } from 'react'
|
import Button from "@/components/Button";
|
||||||
import { useFormik } from 'formik'
|
import Input from "@/components/Input";
|
||||||
import * as Yup from 'yup'
|
import Select from "@/components/Select";
|
||||||
import { TickCircle } from 'iconsax-react'
|
import Textarea from "@/components/Textarea";
|
||||||
import { toast } from 'react-toastify'
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
import Input from '@/components/Input'
|
import type { ErrorType } from "@/helpers/types";
|
||||||
import Select from '@/components/Select'
|
import { useFormik } from "formik";
|
||||||
import Textarea from '@/components/Textarea'
|
import { TickCircle } from "iconsax-react";
|
||||||
import Button from '@/components/Button'
|
import { type FC, useState } from "react";
|
||||||
import { Checkbox } from '@/components/ui/checkbox'
|
import { useNavigate } from "react-router-dom";
|
||||||
import CreateFoodSidebar from './components/CreateFoodSidebar'
|
import { toast } from "react-toastify";
|
||||||
import WeekDaysSection from './components/WeekDaysSection'
|
import * as Yup from "yup";
|
||||||
import MealTimesSection from './components/MealTimesSection'
|
import { useMultipleUpload } from "../uploader/hooks/useUploaderData";
|
||||||
import type { CreateFoodType } from './types/Types'
|
import CreateFoodSidebar from "./components/CreateFoodSidebar";
|
||||||
import { useCreateFood, useGetCategories } from './hooks/useFoodData'
|
import MealTimesSection from "./components/MealTimesSection";
|
||||||
import { useMultipleUpload } from '../uploader/hooks/useUploaderData'
|
import WeekDaysSection from "./components/WeekDaysSection";
|
||||||
import { Pages } from '@/config/Pages'
|
import { useCreateFood, useGetCategories } from "./hooks/useFoodData";
|
||||||
import type { ErrorType } from '@/helpers/types'
|
import type { CreateFoodType } from "./types/Types";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const CreateFood: FC = () => {
|
const CreateFood: FC = () => {
|
||||||
|
|
||||||
const { data } = useGetCategories();
|
const { data } = useGetCategories();
|
||||||
const [isActive, setIsActive] = useState<boolean>(true)
|
const [isActive, setIsActive] = useState<boolean>(true);
|
||||||
const [isSpecial, setIsSpecial] = useState<boolean>(false)
|
const [isSpecial, setIsSpecial] = useState<boolean>(false);
|
||||||
const [imageFiles, setImageFiles] = useState<File[]>([])
|
const [imageFiles, setImageFiles] = useState<File[]>([]);
|
||||||
const { mutate: createFood, isPending } = useCreateFood()
|
const { mutate: createFood, isPending } = useCreateFood();
|
||||||
const { mutate: multipleUpload, isPending: isUploading } = useMultipleUpload()
|
const { mutate: multipleUpload, isPending: isUploading } = useMultipleUpload();
|
||||||
|
const navigate = useNavigate();
|
||||||
const categories = data?.data?.map(category => ({
|
const categories =
|
||||||
|
data?.data?.map((category) => ({
|
||||||
label: category.title,
|
label: category.title,
|
||||||
value: category.id
|
value: category.id,
|
||||||
})) || []
|
})) || [];
|
||||||
|
|
||||||
const formik = useFormik<CreateFoodType>({
|
const formik = useFormik<CreateFoodType>({
|
||||||
initialValues: {
|
initialValues: {
|
||||||
title: '',
|
title: "",
|
||||||
desc: '',
|
desc: "",
|
||||||
content: [],
|
content: [],
|
||||||
categoryId: '',
|
categoryId: "",
|
||||||
price: 0,
|
price: 0,
|
||||||
discount: 0,
|
discount: 0,
|
||||||
prepareTime: 0,
|
prepareTime: 0,
|
||||||
weekDays: [0, 1, 2, 3, 4, 5, 6],
|
weekDays: [0, 1, 2, 3, 4, 5, 6],
|
||||||
mealTypes: ['breakfast', 'lunch', 'dinner'],
|
mealTypes: ["breakfast", "lunch", "dinner"],
|
||||||
pickupServe: true,
|
pickupServe: true,
|
||||||
inPlaceServe: true,
|
inPlaceServe: true,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
@@ -51,21 +49,19 @@ const CreateFood: FC = () => {
|
|||||||
isSpecialOffer: false,
|
isSpecialOffer: false,
|
||||||
dailyStock: 0,
|
dailyStock: 0,
|
||||||
availableStock: 0,
|
availableStock: 0,
|
||||||
order: 0
|
order: 0,
|
||||||
},
|
},
|
||||||
validationSchema: Yup.object().shape({
|
validationSchema: Yup.object().shape({
|
||||||
title: Yup.string().required('نام غذا الزامی است'),
|
title: Yup.string().required("نام غذا الزامی است"),
|
||||||
categoryId: Yup.string().required('دستهبندی الزامی است'),
|
categoryId: Yup.string().required("دستهبندی الزامی است"),
|
||||||
price: Yup.number().required('قیمت الزامی است').min(0, 'قیمت باید مثبت باشد'),
|
price: Yup.number().required("قیمت الزامی است").min(0, "قیمت باید مثبت باشد"),
|
||||||
prepareTime: Yup.number().required('زمان آمادهسازی الزامی است').min(0, 'زمان آمادهسازی باید مثبت باشد'),
|
prepareTime: Yup.number().required("زمان آمادهسازی الزامی است").min(0, "زمان آمادهسازی باید مثبت باشد"),
|
||||||
discount: Yup.number().min(0, 'تخفیف باید مثبت باشد'),
|
discount: Yup.number().min(0, "تخفیف باید مثبت باشد"),
|
||||||
dailyStock: Yup.number().required('موجودی روزانه الزامی است').min(0, 'موجودی روزانه باید مثبت باشد'),
|
dailyStock: Yup.number().required("موجودی روزانه الزامی است").min(0, "موجودی روزانه باید مثبت باشد"),
|
||||||
availableStock: Yup.number()
|
availableStock: Yup.number().required("موجودی فعلی الزامی است").min(0, "موجودی فعلی باید مثبت باشد"),
|
||||||
.required('موجودی فعلی الزامی است')
|
|
||||||
.min(0, 'موجودی فعلی باید مثبت باشد'),
|
|
||||||
content: Yup.array().of(Yup.string()),
|
content: Yup.array().of(Yup.string()),
|
||||||
weekDays: Yup.array().of(Yup.number()),
|
weekDays: Yup.array().of(Yup.number()),
|
||||||
mealTypes: Yup.array().of(Yup.string())
|
mealTypes: Yup.array().of(Yup.string()),
|
||||||
}),
|
}),
|
||||||
onSubmit: (values) => {
|
onSubmit: (values) => {
|
||||||
const submitFood = (imageUrls: string[] = []) => {
|
const submitFood = (imageUrls: string[] = []) => {
|
||||||
@@ -74,182 +70,176 @@ const CreateFood: FC = () => {
|
|||||||
isActive,
|
isActive,
|
||||||
isSpecialOffer: isSpecial,
|
isSpecialOffer: isSpecial,
|
||||||
images: imageUrls,
|
images: imageUrls,
|
||||||
content: values.content.filter(item => item && item.trim().length > 0)
|
content: values.content.filter((item) => item && item.trim().length > 0),
|
||||||
}
|
};
|
||||||
|
|
||||||
createFood(foodData, {
|
createFood(foodData, {
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
toast.success('غذا با موفقیت ایجاد شد')
|
toast.success("غذا با موفقیت ایجاد شد");
|
||||||
window.location.href = Pages.foods.list
|
navigate(-1);
|
||||||
},
|
},
|
||||||
onError: (error: ErrorType) => {
|
onError: (error: ErrorType) => {
|
||||||
toast.error(error?.response?.data?.error?.message[0] || 'خطا در ایجاد غذا')
|
toast.error(error?.response?.data?.error?.message[0] || "خطا در ایجاد غذا");
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
if (imageFiles.length > 0) {
|
if (imageFiles.length > 0) {
|
||||||
multipleUpload(imageFiles, {
|
multipleUpload(imageFiles, {
|
||||||
onSuccess: (response) => {
|
onSuccess: (response) => {
|
||||||
const imageUrls = response?.data?.map(item => item.url) || []
|
const imageUrls = response?.data?.map((item) => item.url) || [];
|
||||||
submitFood(imageUrls)
|
submitFood(imageUrls);
|
||||||
},
|
},
|
||||||
onError: (error: ErrorType) => {
|
onError: (error: ErrorType) => {
|
||||||
toast.error(error?.response?.data?.error?.message[0] || 'خطا در آپلود تصاویر')
|
toast.error(error?.response?.data?.error?.message[0] || "خطا در آپلود تصاویر");
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
submitFood()
|
submitFood();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full mt-4'>
|
<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="flex flex-col sm:flex-row w-full justify-between items-start sm:items-center gap-4">
|
||||||
<div className='text-lg font-light'>
|
<div className="text-lg font-light">غذای جدید</div>
|
||||||
غذای جدید
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button className="px-5 w-full sm:w-auto" onClick={() => formik.handleSubmit()} isloading={isPending || isUploading}>
|
||||||
className='px-5 w-full sm:w-auto'
|
<div className="flex gap-2 items-center">
|
||||||
onClick={() => formik.handleSubmit()}
|
<TickCircle className="size-5" color="white" />
|
||||||
isloading={isPending || isUploading}
|
|
||||||
>
|
|
||||||
<div className='flex gap-2 items-center'>
|
|
||||||
<TickCircle className='size-5' color='white' />
|
|
||||||
<div>ثبت غذا</div>
|
<div>ثبت غذا</div>
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='flex flex-col lg:flex-row gap-6 mt-6'>
|
<div className="flex flex-col lg:flex-row gap-6 mt-6">
|
||||||
<div className='flex-1'>
|
<div className="flex-1">
|
||||||
<div className='bg-white py-6 sm:py-8 xl:px-10 px-4 rounded-3xl'>
|
<div className="bg-white py-6 sm:py-8 xl:px-10 px-4 rounded-3xl">
|
||||||
<Input
|
<Input
|
||||||
label='نام غذا'
|
label="نام غذا"
|
||||||
name='title'
|
name="title"
|
||||||
placeholder=''
|
placeholder=""
|
||||||
value={formik.values.title}
|
value={formik.values.title}
|
||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
error_text={formik.touched.title && formik.errors.title ? formik.errors.title : ''}
|
error_text={formik.touched.title && formik.errors.title ? formik.errors.title : ""}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className='mt-5'>
|
<div className="mt-5">
|
||||||
<Select
|
<Select
|
||||||
items={categories}
|
items={categories}
|
||||||
label='دسته بندی'
|
label="دسته بندی"
|
||||||
placeholder='انتخاب کنید'
|
placeholder="انتخاب کنید"
|
||||||
name='categoryId'
|
name="categoryId"
|
||||||
value={formik.values.categoryId}
|
value={formik.values.categoryId}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const value = e.target.value
|
const value = e.target.value;
|
||||||
formik.setFieldValue('categoryId', value)
|
formik.setFieldValue("categoryId", value);
|
||||||
}}
|
}}
|
||||||
error_text={formik.touched.categoryId && formik.errors.categoryId ? String(formik.errors.categoryId) : ''}
|
error_text={formik.touched.categoryId && formik.errors.categoryId ? String(formik.errors.categoryId) : ""}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-4 mt-5'>
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-4 mt-5">
|
||||||
<Input
|
<Input
|
||||||
name='price'
|
name="price"
|
||||||
label='قیمت'
|
label="قیمت"
|
||||||
placeholder='تومان'
|
placeholder="تومان"
|
||||||
type='number'
|
type="number"
|
||||||
seprator={true}
|
seprator={true}
|
||||||
value={formik.values.price}
|
value={formik.values.price}
|
||||||
onChange={(e) => formik.setFieldValue('price', Number(e.target.value))}
|
onChange={(e) => formik.setFieldValue("price", Number(e.target.value))}
|
||||||
error_text={formik.touched.price && formik.errors.price ? formik.errors.price : ''}
|
error_text={formik.touched.price && formik.errors.price ? formik.errors.price : ""}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
name='discount'
|
name="discount"
|
||||||
label='تخفیف'
|
label="تخفیف"
|
||||||
placeholder='تومان'
|
placeholder="تومان"
|
||||||
type='number'
|
type="number"
|
||||||
seprator={true}
|
seprator={true}
|
||||||
value={formik.values.discount}
|
value={formik.values.discount}
|
||||||
onChange={(e) => formik.setFieldValue('discount', Number(e.target.value))}
|
onChange={(e) => formik.setFieldValue("discount", Number(e.target.value))}
|
||||||
error_text={formik.touched.discount && formik.errors.discount ? formik.errors.discount : ''}
|
error_text={formik.touched.discount && formik.errors.discount ? formik.errors.discount : ""}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
name='prepareTime'
|
name="prepareTime"
|
||||||
label='زمان آماده سازی'
|
label="زمان آماده سازی"
|
||||||
placeholder='دقیقه'
|
placeholder="دقیقه"
|
||||||
type='number'
|
type="number"
|
||||||
value={formik.values.prepareTime}
|
value={formik.values.prepareTime}
|
||||||
onChange={(e) => formik.setFieldValue('prepareTime', Number(e.target.value))}
|
onChange={(e) => formik.setFieldValue("prepareTime", Number(e.target.value))}
|
||||||
error_text={formik.touched.prepareTime && formik.errors.prepareTime ? formik.errors.prepareTime : ''}
|
error_text={formik.touched.prepareTime && formik.errors.prepareTime ? formik.errors.prepareTime : ""}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
name='dailyStock'
|
name="dailyStock"
|
||||||
label='موجودی روزانه'
|
label="موجودی روزانه"
|
||||||
placeholder='عدد'
|
placeholder="عدد"
|
||||||
type='number'
|
type="number"
|
||||||
seprator={true}
|
seprator={true}
|
||||||
value={formik.values.dailyStock}
|
value={formik.values.dailyStock}
|
||||||
onChange={(e) => formik.setFieldValue('dailyStock', Number(e.target.value))}
|
onChange={(e) => formik.setFieldValue("dailyStock", Number(e.target.value))}
|
||||||
error_text={formik.touched.dailyStock && formik.errors.dailyStock ? formik.errors.dailyStock : ''}
|
error_text={formik.touched.dailyStock && formik.errors.dailyStock ? formik.errors.dailyStock : ""}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
name='availableStock'
|
name="availableStock"
|
||||||
label='موجودی فعلی'
|
label="موجودی فعلی"
|
||||||
placeholder='عدد'
|
placeholder="عدد"
|
||||||
type='number'
|
type="number"
|
||||||
seprator={true}
|
seprator={true}
|
||||||
value={formik.values.availableStock}
|
value={formik.values.availableStock}
|
||||||
onChange={(e) => formik.setFieldValue('availableStock', Number(e.target.value))}
|
onChange={(e) => formik.setFieldValue("availableStock", Number(e.target.value))}
|
||||||
error_text={formik.touched.availableStock && formik.errors.availableStock ? formik.errors.availableStock : ''}
|
error_text={formik.touched.availableStock && formik.errors.availableStock ? formik.errors.availableStock : ""}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='mt-5'>
|
<div className="mt-5">
|
||||||
<Textarea
|
<Textarea
|
||||||
name='desc'
|
name="desc"
|
||||||
label='توضیحات غذا'
|
label="توضیحات غذا"
|
||||||
placeholder=''
|
placeholder=""
|
||||||
value={formik.values.desc}
|
value={formik.values.desc}
|
||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
error_text={formik.touched.desc && formik.errors.desc ? formik.errors.desc : ''}
|
error_text={formik.touched.desc && formik.errors.desc ? formik.errors.desc : ""}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='mt-5'>
|
<div className="mt-5">
|
||||||
<Input
|
<Input
|
||||||
name='order'
|
name="order"
|
||||||
label='اولویت'
|
label="اولویت"
|
||||||
placeholder='عدد'
|
placeholder="عدد"
|
||||||
type='number'
|
type="number"
|
||||||
value={formik.values.order}
|
value={formik.values.order}
|
||||||
onChange={(e) => formik.setFieldValue('order', Number(e.target.value))}
|
onChange={(e) => formik.setFieldValue("order", Number(e.target.value))}
|
||||||
error_text={formik.touched.order && formik.errors.order ? formik.errors.order : ''}
|
error_text={formik.touched.order && formik.errors.order ? formik.errors.order : ""}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='mt-5'>
|
<div className="mt-5">
|
||||||
<div className='text-sm mb-2'>محتوای غذا</div>
|
<div className="text-sm mb-2">محتوای غذا</div>
|
||||||
<div className='space-y-2'>
|
<div className="space-y-2">
|
||||||
{formik.values.content.map((item, index) => (
|
{formik.values.content.map((item, index) => (
|
||||||
<div key={index} className='flex gap-2 items-center'>
|
<div key={index} className="flex gap-2 items-center">
|
||||||
<Input
|
<Input
|
||||||
placeholder='متن محتوا'
|
placeholder="متن محتوا"
|
||||||
value={item}
|
value={item}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const newContent = [...formik.values.content]
|
const newContent = [...formik.values.content];
|
||||||
newContent[index] = e.target.value
|
newContent[index] = e.target.value;
|
||||||
formik.setFieldValue('content', newContent)
|
formik.setFieldValue("content", newContent);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
type='button'
|
type="button"
|
||||||
className='px-3 bg-red-500 hover:bg-red-600 w-auto'
|
className="px-3 bg-red-500 hover:bg-red-600 w-auto"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const newContent = formik.values.content.filter((_, i) => i !== index)
|
const newContent = formik.values.content.filter((_, i) => i !== index);
|
||||||
formik.setFieldValue('content', newContent)
|
formik.setFieldValue("content", newContent);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
حذف
|
حذف
|
||||||
@@ -257,10 +247,10 @@ const CreateFood: FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<Button
|
<Button
|
||||||
type='button'
|
type="button"
|
||||||
className='w-full bg-gray-200 text-gray-700 hover:bg-gray-300'
|
className="w-full bg-gray-200 text-gray-700 hover:bg-gray-300"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
formik.setFieldValue('content', [...formik.values.content, ''])
|
formik.setFieldValue("content", [...formik.values.content, ""]);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
افزودن محتوا
|
افزودن محتوا
|
||||||
@@ -271,40 +261,28 @@ const CreateFood: FC = () => {
|
|||||||
<MealTimesSection formik={formik} />
|
<MealTimesSection formik={formik} />
|
||||||
<WeekDaysSection formik={formik} />
|
<WeekDaysSection formik={formik} />
|
||||||
|
|
||||||
<div className='mt-6'>
|
<div className="mt-6">
|
||||||
<div className='text-sm mb-3'>گزینههای سرویس</div>
|
<div className="text-sm mb-3">گزینههای سرویس</div>
|
||||||
<div className='flex gap-6 flex-wrap'>
|
<div className="flex gap-6 flex-wrap">
|
||||||
<div className='flex items-center gap-2'>
|
<div className="flex items-center gap-2">
|
||||||
<Checkbox
|
<Checkbox checked={formik.values.pickupServe} onCheckedChange={(checked) => formik.setFieldValue("pickupServe", checked)} />
|
||||||
checked={formik.values.pickupServe}
|
<label className="text-xs cursor-pointer"> بیرونبر</label>
|
||||||
onCheckedChange={(checked) => formik.setFieldValue('pickupServe', checked)}
|
|
||||||
/>
|
|
||||||
<label className='text-xs cursor-pointer'> بیرونبر</label>
|
|
||||||
</div>
|
</div>
|
||||||
<div className='flex items-center gap-2'>
|
<div className="flex items-center gap-2">
|
||||||
<Checkbox
|
<Checkbox checked={formik.values.inPlaceServe} onCheckedChange={(checked) => formik.setFieldValue("inPlaceServe", checked)} />
|
||||||
checked={formik.values.inPlaceServe}
|
<label className="text-xs cursor-pointer">سرو در محل</label>
|
||||||
onCheckedChange={(checked) => formik.setFieldValue('inPlaceServe', checked)}
|
|
||||||
/>
|
|
||||||
<label className='text-xs cursor-pointer'>سرو در محل</label>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='w-full lg:w-auto'>
|
<div className="w-full lg:w-auto">
|
||||||
<CreateFoodSidebar
|
<CreateFoodSidebar isActive={isActive} isSpecial={isSpecial} onChangeActive={setIsActive} onChangeSpecial={setIsSpecial} onChangeImages={setImageFiles} />
|
||||||
isActive={isActive}
|
|
||||||
isSpecial={isSpecial}
|
|
||||||
onChangeActive={setIsActive}
|
|
||||||
onChangeSpecial={setIsSpecial}
|
|
||||||
onChangeImages={setImageFiles}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default CreateFood
|
export default CreateFood;
|
||||||
|
|||||||
+96
-101
@@ -1,47 +1,47 @@
|
|||||||
import { type FC, useState, useEffect } from 'react'
|
import Button from "@/components/Button";
|
||||||
import { useFormik } from 'formik'
|
import { extractErrorMessage } from "@/config/func";
|
||||||
import * as Yup from 'yup'
|
import type { ErrorType } from "@/helpers/types";
|
||||||
import { TickCircle } from 'iconsax-react'
|
import { useFormik } from "formik";
|
||||||
import { toast } from 'react-toastify'
|
import { TickCircle } from "iconsax-react";
|
||||||
import { useNavigate, useParams } from 'react-router-dom'
|
import { type FC, useEffect, useState } from "react";
|
||||||
import Button from '@/components/Button'
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import CreateFoodSidebar from './components/CreateFoodSidebar'
|
import { toast } from "react-toastify";
|
||||||
import BasicInfoSection from './components/BasicInfoSection'
|
import * as Yup from "yup";
|
||||||
import FoodContentSection from './components/FoodContentSection'
|
import { useMultipleUpload } from "../uploader/hooks/useUploaderData";
|
||||||
import MealTimesSection from './components/MealTimesSection'
|
import BasicInfoSection from "./components/BasicInfoSection";
|
||||||
import WeekDaysSection from './components/WeekDaysSection'
|
import CreateFoodSidebar from "./components/CreateFoodSidebar";
|
||||||
import ServiceOptionsSection from './components/ServiceOptionsSection'
|
import FoodContentSection from "./components/FoodContentSection";
|
||||||
import type { CreateFoodType } from './types/Types'
|
import MealTimesSection from "./components/MealTimesSection";
|
||||||
import { useUpdateFood, useGetFoodDetails, useGetCategories } from './hooks/useFoodData'
|
import ServiceOptionsSection from "./components/ServiceOptionsSection";
|
||||||
import { useMultipleUpload } from '../uploader/hooks/useUploaderData'
|
import WeekDaysSection from "./components/WeekDaysSection";
|
||||||
import { Pages } from '@/config/Pages'
|
import { useGetCategories, useGetFoodDetails, useUpdateFood } from "./hooks/useFoodData";
|
||||||
import type { ErrorType } from '@/helpers/types'
|
import type { CreateFoodType } from "./types/Types";
|
||||||
import { extractErrorMessage } from '@/config/func'
|
|
||||||
|
|
||||||
const UpdateFood: FC = () => {
|
const UpdateFood: FC = () => {
|
||||||
const { id } = useParams<{ id: string }>()
|
const { id } = useParams<{ id: string }>();
|
||||||
const { data: foodData, isLoading } = useGetFoodDetails(id || '')
|
const { data: foodData, isLoading } = useGetFoodDetails(id || "");
|
||||||
const { data: categoriesData } = useGetCategories()
|
const { data: categoriesData } = useGetCategories();
|
||||||
const [isActive, setIsActive] = useState<boolean>(true)
|
const [isActive, setIsActive] = useState<boolean>(true);
|
||||||
const [isSpecial, setIsSpecial] = useState<boolean>(false)
|
const [isSpecial, setIsSpecial] = useState<boolean>(false);
|
||||||
const [imageFiles, setImageFiles] = useState<File[]>([])
|
const [imageFiles, setImageFiles] = useState<File[]>([]);
|
||||||
const [existingImages, setExistingImages] = useState<string[]>([])
|
const [existingImages, setExistingImages] = useState<string[]>([]);
|
||||||
const { mutate: updateFood, isPending } = useUpdateFood()
|
const { mutate: updateFood, isPending } = useUpdateFood();
|
||||||
const { mutate: multipleUpload, isPending: isUploading } = useMultipleUpload()
|
const { mutate: multipleUpload, isPending: isUploading } = useMultipleUpload();
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate();
|
||||||
const categories = categoriesData?.data?.map(category => ({
|
const categories =
|
||||||
|
categoriesData?.data?.map((category) => ({
|
||||||
label: category.title,
|
label: category.title,
|
||||||
value: category.id
|
value: category.id,
|
||||||
})) || []
|
})) || [];
|
||||||
|
|
||||||
const food = foodData?.data
|
const food = foodData?.data;
|
||||||
|
|
||||||
const formik = useFormik<CreateFoodType>({
|
const formik = useFormik<CreateFoodType>({
|
||||||
initialValues: {
|
initialValues: {
|
||||||
title: '',
|
title: "",
|
||||||
desc: '',
|
desc: "",
|
||||||
content: [],
|
content: [],
|
||||||
categoryId: '',
|
categoryId: "",
|
||||||
price: 0,
|
price: 0,
|
||||||
discount: 0,
|
discount: 0,
|
||||||
prepareTime: 0,
|
prepareTime: 0,
|
||||||
@@ -54,72 +54,73 @@ const UpdateFood: FC = () => {
|
|||||||
isSpecialOffer: false,
|
isSpecialOffer: false,
|
||||||
dailyStock: 0,
|
dailyStock: 0,
|
||||||
availableStock: 0,
|
availableStock: 0,
|
||||||
order: 0
|
order: 0,
|
||||||
},
|
},
|
||||||
validationSchema: Yup.object().shape({
|
validationSchema: Yup.object().shape({
|
||||||
title: Yup.string().required('نام غذا الزامی است'),
|
title: Yup.string().required("نام غذا الزامی است"),
|
||||||
categoryId: Yup.string().required('دستهبندی الزامی است'),
|
categoryId: Yup.string().required("دستهبندی الزامی است"),
|
||||||
price: Yup.number().required('قیمت الزامی است').min(0, 'قیمت باید مثبت باشد'),
|
price: Yup.number().required("قیمت الزامی است").min(0, "قیمت باید مثبت باشد"),
|
||||||
prepareTime: Yup.number().required('زمان آمادهسازی الزامی است').min(0, 'زمان آمادهسازی باید مثبت باشد'),
|
prepareTime: Yup.number().required("زمان آمادهسازی الزامی است").min(0, "زمان آمادهسازی باید مثبت باشد"),
|
||||||
discount: Yup.number().min(0, 'تخفیف باید مثبت باشد'),
|
discount: Yup.number().min(0, "تخفیف باید مثبت باشد"),
|
||||||
dailyStock: Yup.number().required('موجودی روزانه الزامی است').min(0, 'موجودی روزانه باید مثبت باشد'),
|
dailyStock: Yup.number().required("موجودی روزانه الزامی است").min(0, "موجودی روزانه باید مثبت باشد"),
|
||||||
availableStock: Yup.number()
|
availableStock: Yup.number().required("موجودی فعلی الزامی است").min(0, "موجودی فعلی باید مثبت باشد"),
|
||||||
.required('موجودی فعلی الزامی است')
|
|
||||||
.min(0, 'موجودی فعلی باید مثبت باشد'),
|
|
||||||
content: Yup.array().of(Yup.string()),
|
content: Yup.array().of(Yup.string()),
|
||||||
weekDays: Yup.array().of(Yup.number()),
|
weekDays: Yup.array().of(Yup.number()),
|
||||||
mealTypes: Yup.array().of(Yup.string())
|
mealTypes: Yup.array().of(Yup.string()),
|
||||||
}),
|
}),
|
||||||
onSubmit: (values) => {
|
onSubmit: (values) => {
|
||||||
if (!id) {
|
if (!id) {
|
||||||
toast.error('شناسه غذا یافت نشد')
|
toast.error("شناسه غذا یافت نشد");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const submitFood = (newImageUrls: string[] = []) => {
|
const submitFood = (newImageUrls: string[] = []) => {
|
||||||
const allImages = [...values.images, ...newImageUrls]
|
const allImages = [...values.images, ...newImageUrls];
|
||||||
const foodData: CreateFoodType = {
|
const foodData: CreateFoodType = {
|
||||||
...values,
|
...values,
|
||||||
isActive,
|
isActive,
|
||||||
isSpecialOffer: isSpecial,
|
isSpecialOffer: isSpecial,
|
||||||
images: allImages,
|
images: allImages,
|
||||||
content: values.content.filter(item => item && item.trim().length > 0)
|
content: values.content.filter((item) => item && item.trim().length > 0),
|
||||||
}
|
};
|
||||||
|
|
||||||
updateFood({ id, params: foodData }, {
|
updateFood(
|
||||||
|
{ id, params: foodData },
|
||||||
|
{
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
toast.success('غذا با موفقیت بهروزرسانی شد')
|
toast.success("غذا با موفقیت بهروزرسانی شد");
|
||||||
navigate(Pages.foods.list)
|
navigate(-1);
|
||||||
},
|
},
|
||||||
onError: (error: ErrorType) => {
|
onError: (error: ErrorType) => {
|
||||||
toast.error(extractErrorMessage(error))
|
toast.error(extractErrorMessage(error));
|
||||||
}
|
},
|
||||||
})
|
},
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
||||||
if (imageFiles.length > 0) {
|
if (imageFiles.length > 0) {
|
||||||
multipleUpload(imageFiles, {
|
multipleUpload(imageFiles, {
|
||||||
onSuccess: (response) => {
|
onSuccess: (response) => {
|
||||||
const imageUrls = response?.data?.map(item => item.url) || []
|
const imageUrls = response?.data?.map((item) => item.url) || [];
|
||||||
submitFood(imageUrls)
|
submitFood(imageUrls);
|
||||||
},
|
},
|
||||||
onError: (error: ErrorType) => {
|
onError: (error: ErrorType) => {
|
||||||
toast.error(error?.response?.data?.error?.message[0] || 'خطا در آپلود تصاویر')
|
toast.error(error?.response?.data?.error?.message[0] || "خطا در آپلود تصاویر");
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
submitFood()
|
submitFood();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (food) {
|
if (food) {
|
||||||
formik.setValues({
|
formik.setValues({
|
||||||
title: food.title || '',
|
title: food.title || "",
|
||||||
desc: food.desc || '',
|
desc: food.desc || "",
|
||||||
content: food.content || [],
|
content: food.content || [],
|
||||||
categoryId: food.category?.id || '',
|
categoryId: food.category?.id || "",
|
||||||
price: food.price || 0,
|
price: food.price || 0,
|
||||||
discount: food.discount || 0,
|
discount: food.discount || 0,
|
||||||
prepareTime: food.prepareTime || 0,
|
prepareTime: food.prepareTime || 0,
|
||||||
@@ -132,59 +133,53 @@ const UpdateFood: FC = () => {
|
|||||||
isSpecialOffer: food.isSpecialOffer || false,
|
isSpecialOffer: food.isSpecialOffer || false,
|
||||||
dailyStock: food.inventory?.totalStock || 0,
|
dailyStock: food.inventory?.totalStock || 0,
|
||||||
availableStock: food.inventory?.availableStock || 0,
|
availableStock: food.inventory?.availableStock || 0,
|
||||||
order: food.order || 0
|
order: food.order || 0,
|
||||||
})
|
});
|
||||||
setIsActive(food.isActive || false)
|
setIsActive(food.isActive || false);
|
||||||
setIsSpecial(food.isSpecialOffer || false)
|
setIsSpecial(food.isSpecialOffer || false);
|
||||||
setExistingImages(food.images || [])
|
setExistingImages(food.images || []);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [food])
|
}, [food]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
formik.setFieldValue('images', existingImages)
|
formik.setFieldValue("images", existingImages);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [existingImages])
|
}, [existingImages]);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<div className='w-full mt-4 flex justify-center items-center'>
|
<div className="w-full mt-4 flex justify-center items-center">
|
||||||
<div>در حال بارگذاری...</div>
|
<div>در حال بارگذاری...</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!food) {
|
if (!food) {
|
||||||
return (
|
return (
|
||||||
<div className='w-full mt-4 flex justify-center items-center'>
|
<div className="w-full mt-4 flex justify-center items-center">
|
||||||
<div>غذا یافت نشد</div>
|
<div>غذا یافت نشد</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full mt-4'>
|
<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="flex flex-col sm:flex-row w-full justify-between items-start sm:items-center gap-4">
|
||||||
<div className='text-lg font-light'>
|
<div className="text-lg font-light">ویرایش غذا</div>
|
||||||
ویرایش غذا
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button className="px-5 w-full sm:w-auto" onClick={() => formik.handleSubmit()} isloading={isPending || isUploading}>
|
||||||
className='px-5 w-full sm:w-auto'
|
<div className="flex gap-2 items-center">
|
||||||
onClick={() => formik.handleSubmit()}
|
<TickCircle className="size-5" color="white" />
|
||||||
isloading={isPending || isUploading}
|
|
||||||
>
|
|
||||||
<div className='flex gap-2 items-center'>
|
|
||||||
<TickCircle className='size-5' color='white' />
|
|
||||||
<div>ذخیره تغییرات</div>
|
<div>ذخیره تغییرات</div>
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='flex flex-col lg:flex-row gap-6 mt-6'>
|
<div className="flex flex-col lg:flex-row gap-6 mt-6">
|
||||||
<div className='flex-1'>
|
<div className="flex-1">
|
||||||
<div className='bg-white py-6 sm:py-8 xl:px-10 px-4 rounded-3xl'>
|
<div className="bg-white py-6 sm:py-8 xl:px-10 px-4 rounded-3xl">
|
||||||
<BasicInfoSection formik={formik} categories={categories} />
|
<BasicInfoSection formik={formik} categories={categories} />
|
||||||
<FoodContentSection formik={formik} />
|
<FoodContentSection formik={formik} />
|
||||||
<MealTimesSection formik={formik} />
|
<MealTimesSection formik={formik} />
|
||||||
@@ -193,7 +188,7 @@ const UpdateFood: FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='w-full lg:w-auto'>
|
<div className="w-full lg:w-auto">
|
||||||
<CreateFoodSidebar
|
<CreateFoodSidebar
|
||||||
isActive={isActive}
|
isActive={isActive}
|
||||||
isSpecial={isSpecial}
|
isSpecial={isSpecial}
|
||||||
@@ -206,7 +201,7 @@ const UpdateFood: FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default UpdateFood
|
export default UpdateFood;
|
||||||
|
|||||||
Reference in New Issue
Block a user