change food to product name
This commit is contained in:
+5
-5
@@ -15,11 +15,11 @@ export const Pages = {
|
||||
add: "/payment_methods/create",
|
||||
update: "/payment_methods/update/",
|
||||
},
|
||||
foods: {
|
||||
list: "/foods/list",
|
||||
add: "/foods/add",
|
||||
category: "/foods/category",
|
||||
update: "/foods/update/",
|
||||
products: {
|
||||
list: "/products/list",
|
||||
add: "/products/add",
|
||||
category: "/products/category",
|
||||
update: "/products/update/",
|
||||
},
|
||||
orders: {
|
||||
list: "/orders/list",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export const SideBarItemHasSubMenu = [
|
||||
"foods",
|
||||
"products",
|
||||
"orders",
|
||||
"customers",
|
||||
"discounts",
|
||||
|
||||
@@ -7,8 +7,8 @@ import { useNavigate } from 'react-router-dom'
|
||||
import Button from '@/components/Button'
|
||||
import type { CreateCouponType } from './types/Types'
|
||||
import { useCreateCoupon } from './hooks/useCouponData'
|
||||
import { useGetCategories } from '@/pages/food/hooks/useFoodData'
|
||||
import { useGetFoods } from '@/pages/food/hooks/useFoodData'
|
||||
import { useGetCategories } from '@/pages/product/hooks/useProductData'
|
||||
import { useGetProducts } from '@/pages/product/hooks/useProductData'
|
||||
import { Pages } from '@/config/Pages'
|
||||
import type { ErrorType } from '@/helpers/types'
|
||||
import { extractErrorMessage } from '@/config/func'
|
||||
@@ -21,12 +21,12 @@ const CreateCoupon: FC = () => {
|
||||
const navigate = useNavigate()
|
||||
const { mutate: createCoupon, isPending: isCreating } = useCreateCoupon()
|
||||
const { data: categoriesData } = useGetCategories()
|
||||
const { data: foodsData } = useGetFoods()
|
||||
const { data: productsData } = useGetProducts()
|
||||
|
||||
const [couponType, setCouponType] = useState<'PERCENTAGE' | 'FIXED'>('PERCENTAGE')
|
||||
|
||||
const categories = useMemo(() => categoriesData?.data || [], [categoriesData?.data])
|
||||
const foods = useMemo(() => foodsData?.data || [], [foodsData?.data])
|
||||
const products = useMemo(() => productsData?.data || [], [productsData?.data])
|
||||
|
||||
const formik = useFormik<CreateCouponType>({
|
||||
initialValues: {
|
||||
@@ -119,7 +119,7 @@ const CreateCoupon: FC = () => {
|
||||
<CouponSidebar
|
||||
formik={formik}
|
||||
categories={categories}
|
||||
foods={foods}
|
||||
foods={products}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,8 +7,8 @@ import { toast } from 'react-toastify'
|
||||
import Button from '@/components/Button'
|
||||
import type { CreateCouponType } from './types/Types'
|
||||
import { useGetCouponDetails, useUpdateCoupon } from './hooks/useCouponData'
|
||||
import { useGetCategories } from '@/pages/food/hooks/useFoodData'
|
||||
import { useGetFoods } from '@/pages/food/hooks/useFoodData'
|
||||
import { useGetCategories } from '@/pages/product/hooks/useProductData'
|
||||
import { useGetProducts } from '@/pages/product/hooks/useProductData'
|
||||
import { Pages } from '@/config/Pages'
|
||||
import type { ErrorType } from '@/helpers/types'
|
||||
import { extractErrorMessage } from '@/config/func'
|
||||
@@ -23,12 +23,12 @@ const UpdateCoupon: FC = () => {
|
||||
const { data: couponData, isLoading } = useGetCouponDetails(id || '')
|
||||
const { mutate: updateCoupon, isPending: isUpdating } = useUpdateCoupon()
|
||||
const { data: categoriesData } = useGetCategories()
|
||||
const { data: foodsData } = useGetFoods()
|
||||
const { data: productsData } = useGetProducts()
|
||||
|
||||
const [couponType, setCouponType] = useState<'PERCENTAGE' | 'FIXED'>('PERCENTAGE')
|
||||
|
||||
const categories = useMemo(() => categoriesData?.data || [], [categoriesData?.data])
|
||||
const foods = useMemo(() => foodsData?.data || [], [foodsData?.data])
|
||||
const products = useMemo(() => productsData?.data || [], [productsData?.data])
|
||||
|
||||
const formik = useFormik<CreateCouponType>({
|
||||
initialValues: {
|
||||
@@ -167,7 +167,7 @@ const UpdateCoupon: FC = () => {
|
||||
<CouponSidebar
|
||||
formik={formik}
|
||||
categories={categories}
|
||||
foods={foods}
|
||||
foods={products}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
useCreateCategory,
|
||||
useUpdateCategory,
|
||||
useDeleteCategory
|
||||
} from './hooks/useFoodData'
|
||||
} from './hooks/useProductData'
|
||||
import { useSingleUpload } from '../uploader/hooks/useUploaderData'
|
||||
import { extractErrorMessage } from '@/config/func'
|
||||
|
||||
@@ -24,7 +24,7 @@ type CategoryFormValues = {
|
||||
parentId?: string,
|
||||
}
|
||||
|
||||
const CategoryFood: FC = () => {
|
||||
const CategoryProduct: FC = () => {
|
||||
const [isActive, setIsActive] = useState<boolean>(true)
|
||||
const [iconFiles, setIconFiles] = useState<File[]>([])
|
||||
const [selectedIconUrl, setSelectedIconUrl] = useState<string>('')
|
||||
@@ -226,4 +226,4 @@ const CategoryFood: FC = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export default CategoryFood
|
||||
export default CategoryProduct
|
||||
@@ -8,24 +8,24 @@ import Select from '@/components/Select'
|
||||
import Textarea from '@/components/Textarea'
|
||||
import Button from '@/components/Button'
|
||||
import { Checkbox } from '@/components/ui/checkbox'
|
||||
import CreateFoodSidebar from './components/CreateFoodSidebar'
|
||||
import CreateProductSidebar from './components/CreateProductSidebar'
|
||||
import WeekDaysSection from './components/WeekDaysSection'
|
||||
import MealTimesSection from './components/MealTimesSection'
|
||||
import type { CreateFoodType } from './types/Types'
|
||||
import { useCreateFood, useGetCategories } from './hooks/useFoodData'
|
||||
import type { CreateProductType } from './types/Types'
|
||||
import { useCreateProduct, useGetCategories } from './hooks/useProductData'
|
||||
import { useMultipleUpload } from '../uploader/hooks/useUploaderData'
|
||||
import { Pages } from '@/config/Pages'
|
||||
import type { ErrorType } from '@/helpers/types'
|
||||
|
||||
|
||||
|
||||
const CreateFood: FC = () => {
|
||||
const CreateProduct: FC = () => {
|
||||
|
||||
const { data } = useGetCategories();
|
||||
const [isActive, setIsActive] = useState<boolean>(true)
|
||||
const [isSpecial, setIsSpecial] = useState<boolean>(false)
|
||||
const [imageFiles, setImageFiles] = useState<File[]>([])
|
||||
const { mutate: createFood, isPending } = useCreateFood()
|
||||
const { mutate: createProduct, isPending } = useCreateProduct()
|
||||
const { mutate: multipleUpload, isPending: isUploading } = useMultipleUpload()
|
||||
|
||||
const categories = data?.data?.map(category => ({
|
||||
@@ -33,7 +33,7 @@ const CreateFood: FC = () => {
|
||||
value: category.id
|
||||
})) || []
|
||||
|
||||
const formik = useFormik<CreateFoodType>({
|
||||
const formik = useFormik<CreateProductType>({
|
||||
initialValues: {
|
||||
title: '',
|
||||
desc: '',
|
||||
@@ -64,8 +64,8 @@ const CreateFood: FC = () => {
|
||||
mealTypes: Yup.array().of(Yup.string())
|
||||
}),
|
||||
onSubmit: (values) => {
|
||||
const submitFood = (imageUrls: string[] = []) => {
|
||||
const foodData: CreateFoodType = {
|
||||
const submitProduct = (imageUrls: string[] = []) => {
|
||||
const productData: CreateProductType = {
|
||||
...values,
|
||||
isActive,
|
||||
isSpecialOffer: isSpecial,
|
||||
@@ -73,10 +73,10 @@ const CreateFood: FC = () => {
|
||||
content: values.content.filter(item => item && item.trim().length > 0)
|
||||
}
|
||||
|
||||
createFood(foodData, {
|
||||
createProduct(productData, {
|
||||
onSuccess: () => {
|
||||
toast.success('کالا با موفقیت ایجاد شد')
|
||||
window.location.href = Pages.foods.list
|
||||
window.location.href = Pages.products.list
|
||||
},
|
||||
onError: (error: ErrorType) => {
|
||||
toast.error(error?.response?.data?.error?.message[0] || 'خطا در ایجاد کالا')
|
||||
@@ -88,14 +88,14 @@ const CreateFood: FC = () => {
|
||||
multipleUpload(imageFiles, {
|
||||
onSuccess: (response) => {
|
||||
const imageUrls = response?.data?.map(item => item.url) || []
|
||||
submitFood(imageUrls)
|
||||
submitProduct(imageUrls)
|
||||
},
|
||||
onError: (error: ErrorType) => {
|
||||
toast.error(error?.response?.data?.error?.message[0] || 'خطا در آپلود تصاویر')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
submitFood()
|
||||
submitProduct()
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -279,7 +279,7 @@ const CreateFood: FC = () => {
|
||||
</div>
|
||||
|
||||
<div className='w-full lg:w-auto'>
|
||||
<CreateFoodSidebar
|
||||
<CreateProductSidebar
|
||||
isActive={isActive}
|
||||
isSpecial={isSpecial}
|
||||
onChangeActive={setIsActive}
|
||||
@@ -292,4 +292,4 @@ const CreateFood: FC = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export default CreateFood
|
||||
export default CreateProduct
|
||||
@@ -3,42 +3,42 @@ import Table from '@/components/Table'
|
||||
import Filters from '@/components/Filters'
|
||||
import { Add } from 'iconsax-react'
|
||||
import Button from '@/components/Button'
|
||||
import { useGetFoods, useDeleteFood } from './hooks/useFoodData'
|
||||
import { useFoodFilters } from './hooks/useFoodFilters'
|
||||
import { getFoodTableColumns } from './components/FoodTableColumns'
|
||||
import { useFoodFiltersFields } from './components/FoodFiltersFields'
|
||||
import { useGetProducts, useDeleteProduct } from './hooks/useProductData'
|
||||
import { useProductFilters } from './hooks/useProductFilters'
|
||||
import { getProductTableColumns } from './components/ProductTableColumns'
|
||||
import { useProductFiltersFields } from './components/ProductFiltersFields'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Pages } from '@/config/Pages'
|
||||
|
||||
const FoodsList: FC = () => {
|
||||
const ProductsList: FC = () => {
|
||||
const {
|
||||
filters,
|
||||
currentPage,
|
||||
apiParams,
|
||||
handleFiltersChange,
|
||||
handlePageChange,
|
||||
} = useFoodFilters()
|
||||
} = useProductFilters()
|
||||
|
||||
const { data: foodsData, isLoading } = useGetFoods(apiParams, filters)
|
||||
const { mutate: deleteFood, isPending: isDeleting } = useDeleteFood()
|
||||
const { data: productsData, isLoading } = useGetProducts(apiParams, filters)
|
||||
const { mutate: deleteProduct, isPending: isDeleting } = useDeleteProduct()
|
||||
|
||||
|
||||
|
||||
const foods = foodsData?.data || []
|
||||
const columns = getFoodTableColumns({
|
||||
onDelete: (id: string) => deleteFood(id),
|
||||
const products = productsData?.data || []
|
||||
const columns = getProductTableColumns({
|
||||
onDelete: (id: string) => deleteProduct(id),
|
||||
isDeleting
|
||||
})
|
||||
const filterFields = useFoodFiltersFields()
|
||||
const filterFields = useProductFiltersFields()
|
||||
|
||||
const totalPages = foodsData?.meta?.totalPages || 1
|
||||
const totalPages = productsData?.meta?.totalPages || 1
|
||||
|
||||
return (
|
||||
<div className='mt-5'>
|
||||
<div className='flex justify-between items-center'>
|
||||
<h1 className='text-lg font-light'>لیست کالاها</h1>
|
||||
<Link
|
||||
to={Pages.foods.add}
|
||||
to={Pages.products.add}
|
||||
>
|
||||
<Button className='w-fit px-6'>
|
||||
<div className='flex gap-2 items-center'>
|
||||
@@ -60,7 +60,7 @@ const FoodsList: FC = () => {
|
||||
|
||||
<Table
|
||||
columns={columns}
|
||||
data={foods}
|
||||
data={products}
|
||||
isloading={isLoading}
|
||||
pagination={{
|
||||
currentPage,
|
||||
@@ -72,4 +72,4 @@ const FoodsList: FC = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export default FoodsList
|
||||
export default ProductsList
|
||||
@@ -5,28 +5,28 @@ 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 CreateProductSidebar from './components/CreateProductSidebar'
|
||||
import BasicInfoSection from './components/BasicInfoSection'
|
||||
import FoodContentSection from './components/FoodContentSection'
|
||||
import ProductContentSection from './components/ProductContentSection'
|
||||
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 type { CreateProductType } from './types/Types'
|
||||
import { useUpdateProduct, useGetProductDetails, useGetCategories } from './hooks/useProductData'
|
||||
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 UpdateProduct: FC = () => {
|
||||
const { id } = useParams<{ id: string }>()
|
||||
const { data: foodData, isLoading } = useGetFoodDetails(id || '')
|
||||
const { data: productData, isLoading } = useGetProductDetails(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: updateProduct, isPending } = useUpdateProduct()
|
||||
const { mutate: multipleUpload, isPending: isUploading } = useMultipleUpload()
|
||||
const navigate = useNavigate()
|
||||
const categories = categoriesData?.data?.map(category => ({
|
||||
@@ -34,9 +34,9 @@ const UpdateFood: FC = () => {
|
||||
value: category.id
|
||||
})) || []
|
||||
|
||||
const food = foodData?.data
|
||||
const product = productData?.data
|
||||
|
||||
const formik = useFormik<CreateFoodType>({
|
||||
const formik = useFormik<CreateProductType>({
|
||||
initialValues: {
|
||||
title: '',
|
||||
desc: '',
|
||||
@@ -72,9 +72,9 @@ const UpdateFood: FC = () => {
|
||||
return
|
||||
}
|
||||
|
||||
const submitFood = (newImageUrls: string[] = []) => {
|
||||
const submitProduct = (newImageUrls: string[] = []) => {
|
||||
const allImages = [...values.images, ...newImageUrls]
|
||||
const foodData: CreateFoodType = {
|
||||
const productData: CreateProductType = {
|
||||
...values,
|
||||
isActive,
|
||||
isSpecialOffer: isSpecial,
|
||||
@@ -82,10 +82,10 @@ const UpdateFood: FC = () => {
|
||||
content: values.content.filter(item => item && item.trim().length > 0)
|
||||
}
|
||||
|
||||
updateFood({ id, params: foodData }, {
|
||||
updateProduct({ id, params: productData }, {
|
||||
onSuccess: () => {
|
||||
toast.success('کالا با موفقیت بهروزرسانی شد')
|
||||
navigate(Pages.foods.list)
|
||||
navigate(Pages.products.list)
|
||||
},
|
||||
onError: (error: ErrorType) => {
|
||||
toast.error(extractErrorMessage(error))
|
||||
@@ -97,44 +97,44 @@ const UpdateFood: FC = () => {
|
||||
multipleUpload(imageFiles, {
|
||||
onSuccess: (response) => {
|
||||
const imageUrls = response?.data?.map(item => item.url) || []
|
||||
submitFood(imageUrls)
|
||||
submitProduct(imageUrls)
|
||||
},
|
||||
onError: (error: ErrorType) => {
|
||||
toast.error(error?.response?.data?.error?.message[0] || 'خطا در آپلود تصاویر')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
submitFood()
|
||||
submitProduct()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (food) {
|
||||
if (product) {
|
||||
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,
|
||||
order: food.order || 0
|
||||
title: product.title || '',
|
||||
desc: product.desc || '',
|
||||
content: product.content || [],
|
||||
categoryId: product.category?.id || '',
|
||||
price: product.price || 0,
|
||||
discount: product.discount || 0,
|
||||
prepareTime: product.prepareTime || 0,
|
||||
weekDays: product.weekDays || [],
|
||||
mealTypes: product.mealTypes || [],
|
||||
pickupServe: product.pickupServe || false,
|
||||
inPlaceServe: product.inPlaceServe || false,
|
||||
isActive: product.isActive || false,
|
||||
images: product.images || [],
|
||||
isSpecialOffer: product.isSpecialOffer || false,
|
||||
dailyStock: product.inventory?.totalStock || 0,
|
||||
order: product.order || 0
|
||||
})
|
||||
setIsActive(food.isActive || false)
|
||||
setIsSpecial(food.isSpecialOffer || false)
|
||||
setExistingImages(food.images || [])
|
||||
setIsActive(product.isActive || false)
|
||||
setIsSpecial(product.isSpecialOffer || false)
|
||||
setExistingImages(product.images || [])
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [food])
|
||||
}, [product])
|
||||
|
||||
useEffect(() => {
|
||||
formik.setFieldValue('images', existingImages)
|
||||
@@ -149,7 +149,7 @@ const UpdateFood: FC = () => {
|
||||
)
|
||||
}
|
||||
|
||||
if (!food) {
|
||||
if (!product) {
|
||||
return (
|
||||
<div className='w-full mt-4 flex justify-center items-center'>
|
||||
<div>کالا یافت نشد</div>
|
||||
@@ -181,7 +181,7 @@ const UpdateFood: FC = () => {
|
||||
<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} />
|
||||
<ProductContentSection formik={formik} />
|
||||
<MealTimesSection formik={formik} />
|
||||
<WeekDaysSection formik={formik} />
|
||||
<ServiceOptionsSection formik={formik} />
|
||||
@@ -189,7 +189,7 @@ const UpdateFood: FC = () => {
|
||||
</div>
|
||||
|
||||
<div className='w-full lg:w-auto'>
|
||||
<CreateFoodSidebar
|
||||
<CreateProductSidebar
|
||||
isActive={isActive}
|
||||
isSpecial={isSpecial}
|
||||
onChangeActive={setIsActive}
|
||||
@@ -204,4 +204,4 @@ const UpdateFood: FC = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export default UpdateFood
|
||||
export default UpdateProduct
|
||||
+2
-3
@@ -3,10 +3,10 @@ import type { FormikProps } from 'formik'
|
||||
import Input from '@/components/Input'
|
||||
import Select from '@/components/Select'
|
||||
import Textarea from '@/components/Textarea'
|
||||
import type { CreateFoodType } from '../types/Types'
|
||||
import type { CreateProductType } from '../types/Types'
|
||||
|
||||
type BasicInfoSectionProps = {
|
||||
formik: FormikProps<CreateFoodType>
|
||||
formik: FormikProps<CreateProductType>
|
||||
categories: Array<{ label: string; value: string }>
|
||||
}
|
||||
|
||||
@@ -109,4 +109,3 @@ const BasicInfoSection: FC<BasicInfoSectionProps> = ({ formik, categories }) =>
|
||||
}
|
||||
|
||||
export default BasicInfoSection
|
||||
|
||||
+1
-2
@@ -4,7 +4,7 @@ import Input from '@/components/Input'
|
||||
import SwitchComponent from '@/components/Switch'
|
||||
import Button from '@/components/Button'
|
||||
import type { FormikProps } from 'formik'
|
||||
import { useGetCategories, useGetIcons } from '../hooks/useFoodData'
|
||||
import { useGetCategories, useGetIcons } from '../hooks/useProductData'
|
||||
import IconSelectModal from './IconSelectModal'
|
||||
import Select from '@/components/Select'
|
||||
|
||||
@@ -165,4 +165,3 @@ const CategoryForm: FC<Props> = ({
|
||||
}
|
||||
|
||||
export default CategoryForm
|
||||
|
||||
-1
@@ -78,4 +78,3 @@ const CategoryTableColumns = ({ onStatusChange, onEdit, onDelete, isDeleting = f
|
||||
}
|
||||
|
||||
export default CategoryTableColumns
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@ type Props = {
|
||||
onChangeExistingImages?: (images: string[]) => void
|
||||
}
|
||||
|
||||
const CreateFoodSidebar: FC<Props> = (props: Props) => {
|
||||
const CreateProductSidebar: FC<Props> = (props: Props) => {
|
||||
return (
|
||||
<div className='bg-white w-full lg:w-[300px] text-xs h-fit px-5 py-7 rounded-3xl'>
|
||||
|
||||
@@ -54,4 +54,4 @@ const CreateFoodSidebar: FC<Props> = (props: Props) => {
|
||||
)
|
||||
}
|
||||
|
||||
export default CreateFoodSidebar
|
||||
export default CreateProductSidebar
|
||||
-1
@@ -114,4 +114,3 @@ const IconSelectModal: FC<Props> = ({
|
||||
}
|
||||
|
||||
export default IconSelectModal
|
||||
|
||||
+2
-3
@@ -1,10 +1,10 @@
|
||||
import { type FC } from 'react'
|
||||
import type { FormikProps } from 'formik'
|
||||
import { Checkbox } from '@/components/ui/checkbox'
|
||||
import type { CreateFoodType } from '../types/Types'
|
||||
import type { CreateProductType } from '../types/Types'
|
||||
|
||||
type MealTimesSectionProps = {
|
||||
formik: FormikProps<CreateFoodType>
|
||||
formik: FormikProps<CreateProductType>
|
||||
}
|
||||
|
||||
const MealTimesSection: FC<MealTimesSectionProps> = ({ formik }) => {
|
||||
@@ -51,4 +51,3 @@ const MealTimesSection: FC<MealTimesSectionProps> = ({ formik }) => {
|
||||
}
|
||||
|
||||
export default MealTimesSection
|
||||
|
||||
+5
-5
@@ -2,13 +2,13 @@ import { type FC } from 'react'
|
||||
import type { FormikProps } from 'formik'
|
||||
import Input from '@/components/Input'
|
||||
import Button from '@/components/Button'
|
||||
import type { CreateFoodType } from '../types/Types'
|
||||
import type { CreateProductType } from '../types/Types'
|
||||
|
||||
type FoodContentSectionProps = {
|
||||
formik: FormikProps<CreateFoodType>
|
||||
type ProductContentSectionProps = {
|
||||
formik: FormikProps<CreateProductType>
|
||||
}
|
||||
|
||||
const FoodContentSection: FC<FoodContentSectionProps> = ({ formik }) => {
|
||||
const ProductContentSection: FC<ProductContentSectionProps> = ({ formik }) => {
|
||||
|
||||
return (
|
||||
<div className='mt-5'>
|
||||
@@ -51,4 +51,4 @@ const FoodContentSection: FC<FoodContentSectionProps> = ({ formik }) => {
|
||||
)
|
||||
}
|
||||
|
||||
export default FoodContentSection
|
||||
export default ProductContentSection
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import { useMemo } from 'react'
|
||||
import type { FieldType } from '@/components/Filters'
|
||||
import { useGetCategories } from '../hooks/useFoodData'
|
||||
import { useGetCategories } from '../hooks/useProductData'
|
||||
|
||||
export const useFoodFiltersFields = (): FieldType[] => {
|
||||
export const useProductFiltersFields = (): FieldType[] => {
|
||||
|
||||
const { data } = useGetCategories()
|
||||
|
||||
+11
-12
@@ -1,24 +1,24 @@
|
||||
import { Eye } from 'iconsax-react'
|
||||
import type { ColumnType } from '@/components/types/TableTypes'
|
||||
import type { Food } from '../types/Types'
|
||||
import type { Product } from '../types/Types'
|
||||
import { formatPrice, formatTime } from '../utils/formatters'
|
||||
import Status from '@/components/Status'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Pages } from '@/config/Pages'
|
||||
import TrashWithConfrim from '@/components/TrashWithConfrim'
|
||||
|
||||
interface GetFoodTableColumnsParams {
|
||||
interface GetProductTableColumnsParams {
|
||||
onDelete: (id: string) => void
|
||||
isDeleting: boolean
|
||||
}
|
||||
|
||||
export const getFoodTableColumns = ({ onDelete, isDeleting }: GetFoodTableColumnsParams): ColumnType<Food>[] => {
|
||||
export const getProductTableColumns = ({ onDelete, isDeleting }: GetProductTableColumnsParams): ColumnType<Product>[] => {
|
||||
|
||||
return [
|
||||
{
|
||||
key: 'image',
|
||||
title: 'تصویر',
|
||||
render: (item: Food) => {
|
||||
render: (item: Product) => {
|
||||
const imageUrl = item.images && item.images.length > 0 ? item.images[0] : ''
|
||||
return (
|
||||
<div className='w-10 h-10 rounded-full overflow-hidden bg-gray-200'>
|
||||
@@ -40,7 +40,7 @@ export const getFoodTableColumns = ({ onDelete, isDeleting }: GetFoodTableColumn
|
||||
{
|
||||
key: 'categories',
|
||||
title: 'دسته بندی',
|
||||
render: (item: Food) => {
|
||||
render: (item: Product) => {
|
||||
return item.category?.title
|
||||
? item.category.title
|
||||
: '-'
|
||||
@@ -49,21 +49,21 @@ export const getFoodTableColumns = ({ onDelete, isDeleting }: GetFoodTableColumn
|
||||
{
|
||||
key: 'price',
|
||||
title: 'قیمت',
|
||||
render: (item: Food) => {
|
||||
render: (item: Product) => {
|
||||
return formatPrice(item.price)
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'prepareTime',
|
||||
title: 'زمان آماده سازی',
|
||||
render: (item: Food) => {
|
||||
render: (item: Product) => {
|
||||
return formatTime(item.prepareTime || 0)
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'inventory',
|
||||
title: 'موجودی',
|
||||
render: (item: Food) => {
|
||||
render: (item: Product) => {
|
||||
const availableStock = item.inventory.availableStock
|
||||
const totalStock = item.inventory.totalStock
|
||||
return (
|
||||
@@ -81,7 +81,7 @@ export const getFoodTableColumns = ({ onDelete, isDeleting }: GetFoodTableColumn
|
||||
{
|
||||
key: 'isActive',
|
||||
title: 'وضعیت',
|
||||
render: (item: Food) => {
|
||||
render: (item: Product) => {
|
||||
return (
|
||||
<Status variant={item.isActive ? 'success' : 'error'} label={item.isActive ? 'فعال' : 'غیرفعال'} />
|
||||
)
|
||||
@@ -90,10 +90,10 @@ export const getFoodTableColumns = ({ onDelete, isDeleting }: GetFoodTableColumn
|
||||
{
|
||||
key: 'view',
|
||||
title: '',
|
||||
render: (item: Food) => {
|
||||
render: (item: Product) => {
|
||||
return (
|
||||
<div className='flex gap-2 items-center'>
|
||||
<Link to={Pages.foods.update + item.id} className='flex gap-2 items-center'>
|
||||
<Link to={Pages.products.update + item.id} className='flex gap-2 items-center'>
|
||||
<Eye size={20} color='#8C90A3' />
|
||||
</Link>
|
||||
<TrashWithConfrim
|
||||
@@ -106,4 +106,3 @@ export const getFoodTableColumns = ({ onDelete, isDeleting }: GetFoodTableColumn
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
+2
-3
@@ -1,10 +1,10 @@
|
||||
import { type FC } from 'react'
|
||||
import type { FormikProps } from 'formik'
|
||||
import { Checkbox } from '@/components/ui/checkbox'
|
||||
import type { CreateFoodType } from '../types/Types'
|
||||
import type { CreateProductType } from '../types/Types'
|
||||
|
||||
type ServiceOptionsSectionProps = {
|
||||
formik: FormikProps<CreateFoodType>
|
||||
formik: FormikProps<CreateProductType>
|
||||
}
|
||||
|
||||
const ServiceOptionsSection: FC<ServiceOptionsSectionProps> = ({ formik }) => {
|
||||
@@ -32,4 +32,3 @@ const ServiceOptionsSection: FC<ServiceOptionsSectionProps> = ({ formik }) => {
|
||||
}
|
||||
|
||||
export default ServiceOptionsSection
|
||||
|
||||
+2
-3
@@ -1,10 +1,10 @@
|
||||
import { type FC } from 'react'
|
||||
import type { FormikProps } from 'formik'
|
||||
import { Checkbox } from '@/components/ui/checkbox'
|
||||
import type { CreateFoodType } from '../types/Types'
|
||||
import type { CreateProductType } from '../types/Types'
|
||||
|
||||
type WeekDaysSectionProps = {
|
||||
formik: FormikProps<CreateFoodType>
|
||||
formik: FormikProps<CreateProductType>
|
||||
}
|
||||
|
||||
const WeekDaysSection: FC<WeekDaysSectionProps> = ({ formik }) => {
|
||||
@@ -48,4 +48,3 @@ const WeekDaysSection: FC<WeekDaysSectionProps> = ({ formik }) => {
|
||||
}
|
||||
|
||||
export default WeekDaysSection
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import * as api from "../service/FoodService";
|
||||
import * as api from "../service/ProductService";
|
||||
import type {
|
||||
CreateCategoryType,
|
||||
CreateFoodType,
|
||||
GetFoodsParams,
|
||||
CreateProductType,
|
||||
GetProductsParams,
|
||||
} from "../types/Types";
|
||||
import type { FilterValues } from "@/components/Filters";
|
||||
|
||||
export const useCreateFood = () => {
|
||||
export const useCreateProduct = () => {
|
||||
return useMutation({
|
||||
mutationFn: api.createFood,
|
||||
mutationFn: api.createProduct,
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetFoods = (
|
||||
params?: GetFoodsParams,
|
||||
export const useGetProducts = (
|
||||
params?: GetProductsParams,
|
||||
filters?: FilterValues,
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: ["foods", params, filters],
|
||||
queryFn: () => api.getFoods(params, filters),
|
||||
queryKey: ["products", params, filters],
|
||||
queryFn: () => api.getProducts(params, filters),
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetFoodDetails = (id: string) => {
|
||||
export const useGetProductDetails = (id: string) => {
|
||||
return useQuery({
|
||||
queryKey: ["food", id],
|
||||
queryFn: () => api.getFoodDetails(id),
|
||||
queryKey: ["product", id],
|
||||
queryFn: () => api.getProductDetails(id),
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateFood = () => {
|
||||
export const useUpdateProduct = () => {
|
||||
return useMutation({
|
||||
mutationFn: ({ id, params }: { id: string; params: CreateFoodType }) =>
|
||||
api.updateFood(id, params),
|
||||
mutationFn: ({ id, params }: { id: string; params: CreateProductType }) =>
|
||||
api.updateProduct(id, params),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -44,12 +44,12 @@ export const useGetCategories = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteFood = () => {
|
||||
export const useDeleteProduct = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: api.deleteFood,
|
||||
mutationFn: api.deleteProduct,
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["foods"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["products"] });
|
||||
},
|
||||
});
|
||||
};
|
||||
+4
-4
@@ -1,17 +1,17 @@
|
||||
import { useState, useMemo } from "react";
|
||||
import type { FilterValues } from "@/components/Filters";
|
||||
import type { GetFoodsParams } from "../types/Types";
|
||||
import type { GetProductsParams } from "../types/Types";
|
||||
|
||||
const DEFAULT_PAGE = 1;
|
||||
const DEFAULT_LIMIT = 10;
|
||||
|
||||
export const useFoodFilters = () => {
|
||||
export const useProductFilters = () => {
|
||||
const [filters, setFilters] = useState<FilterValues>({});
|
||||
const [currentPage, setCurrentPage] = useState(DEFAULT_PAGE);
|
||||
const [limit] = useState(DEFAULT_LIMIT);
|
||||
|
||||
const apiParams = useMemo<GetFoodsParams>(() => {
|
||||
const params: GetFoodsParams = {
|
||||
const apiParams = useMemo<GetProductsParams>(() => {
|
||||
const params: GetProductsParams = {
|
||||
page: currentPage,
|
||||
limit: limit,
|
||||
};
|
||||
+14
-14
@@ -1,25 +1,25 @@
|
||||
import axios from "@/config/axios";
|
||||
import type {
|
||||
CreateCategoryType,
|
||||
CreateFoodType,
|
||||
CreateProductType,
|
||||
GetCategoriesResponseType,
|
||||
GetFoodDetailsResponseType,
|
||||
GetFoodsParams,
|
||||
GetFoodsResponseType,
|
||||
GetProductDetailsResponseType,
|
||||
GetProductsParams,
|
||||
GetProductsResponseType,
|
||||
GetIconsResponseType,
|
||||
} from "../types/Types";
|
||||
import type { FilterValues } from "@/components/Filters";
|
||||
|
||||
export const createFood = async (params: CreateFoodType) => {
|
||||
export const createProduct = async (params: CreateProductType) => {
|
||||
const { data } = await axios.post(`/admin/foods`, params);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getFoods = async (
|
||||
params?: GetFoodsParams,
|
||||
export const getProducts = async (
|
||||
params?: GetProductsParams,
|
||||
filters?: FilterValues,
|
||||
): Promise<GetFoodsResponseType> => {
|
||||
const { data } = await axios.get<GetFoodsResponseType>(`/admin/foods`, {
|
||||
): Promise<GetProductsResponseType> => {
|
||||
const { data } = await axios.get<GetProductsResponseType>(`/admin/foods`, {
|
||||
params: {
|
||||
...params,
|
||||
...filters,
|
||||
@@ -28,16 +28,16 @@ export const getFoods = async (
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getFoodDetails = async (
|
||||
export const getProductDetails = async (
|
||||
id: string,
|
||||
): Promise<GetFoodDetailsResponseType> => {
|
||||
const { data } = await axios.get<GetFoodDetailsResponseType>(
|
||||
): Promise<GetProductDetailsResponseType> => {
|
||||
const { data } = await axios.get<GetProductDetailsResponseType>(
|
||||
`/admin/foods/${id}`,
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const updateFood = async (id: string, params: CreateFoodType) => {
|
||||
export const updateProduct = async (id: string, params: CreateProductType) => {
|
||||
const { data } = await axios.patch(`/admin/foods/${id}`, params);
|
||||
return data;
|
||||
};
|
||||
@@ -49,7 +49,7 @@ export const getCategories = async (): Promise<GetCategoriesResponseType> => {
|
||||
return data;
|
||||
};
|
||||
|
||||
export const deleteFood = async (id: string) => {
|
||||
export const deleteProduct = async (id: string) => {
|
||||
const { data } = await axios.delete(`/admin/foods/${id}`);
|
||||
return data;
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { IResponse } from "@/types/response.types";
|
||||
|
||||
export type CreateFoodType = {
|
||||
export type CreateProductType = {
|
||||
categoryId: string;
|
||||
title: string;
|
||||
desc: string;
|
||||
@@ -32,7 +32,7 @@ export type Category = {
|
||||
parent?: Category;
|
||||
};
|
||||
|
||||
export type FoodDetailsCategory = {
|
||||
export type ProductDetailsCategory = {
|
||||
id: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
@@ -48,18 +48,19 @@ export type Inventory = {
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt: string | null;
|
||||
food: string;
|
||||
product?: string;
|
||||
food?: string; // API compatibility
|
||||
totalStock: number;
|
||||
availableStock: number;
|
||||
};
|
||||
|
||||
export type Food = {
|
||||
export type Product = {
|
||||
id: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt: string | null;
|
||||
restaurant: string;
|
||||
category: FoodDetailsCategory;
|
||||
category: ProductDetailsCategory;
|
||||
inventory: Inventory;
|
||||
title: string;
|
||||
desc: string;
|
||||
@@ -78,7 +79,7 @@ export type Food = {
|
||||
isSpecialOffer: boolean;
|
||||
};
|
||||
|
||||
export type GetFoodsParams = {
|
||||
export type GetProductsParams = {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
search?: string;
|
||||
@@ -88,13 +89,13 @@ export type GetFoodsParams = {
|
||||
isActive?: boolean;
|
||||
};
|
||||
|
||||
export type FoodDetails = {
|
||||
export type ProductDetails = {
|
||||
id: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt: string | null;
|
||||
restaurant: string;
|
||||
category: FoodDetailsCategory;
|
||||
category: ProductDetailsCategory;
|
||||
inventory: Inventory;
|
||||
title: string;
|
||||
desc: string;
|
||||
@@ -121,8 +122,8 @@ export type PaginationMeta = {
|
||||
};
|
||||
|
||||
export type GetCategoriesResponseType = IResponse<Category[]>;
|
||||
export type GetFoodsResponseType = IResponse<Food[]> & { meta: PaginationMeta };
|
||||
export type GetFoodDetailsResponseType = IResponse<FoodDetails>;
|
||||
export type GetProductsResponseType = IResponse<Product[]> & { meta: PaginationMeta };
|
||||
export type GetProductDetailsResponseType = IResponse<ProductDetails>;
|
||||
|
||||
export type CreateCategoryType = {
|
||||
title: string;
|
||||
+8
-8
@@ -5,11 +5,11 @@ import { Route, Routes } from 'react-router-dom'
|
||||
import Footer from '../shared/Footer'
|
||||
import { clx } from '../helpers/utils'
|
||||
import { useSharedStore } from '../shared/store/sharedStore'
|
||||
import FoodsList from '@/pages/food/List'
|
||||
import ProductsList from '@/pages/product/List'
|
||||
import { Pages } from '@/config/Pages'
|
||||
import CreateFood from '@/pages/food/Create'
|
||||
import UpdateFood from '@/pages/food/Update'
|
||||
import CategoryFood from '@/pages/food/Category'
|
||||
import CreateProduct from '@/pages/product/Create'
|
||||
import UpdateProduct from '@/pages/product/Update'
|
||||
import CategoryProduct from '@/pages/product/Category'
|
||||
import CustomersList from '@/pages/customers/List'
|
||||
import CustomerDetails from '@/pages/customers/Details'
|
||||
import CreateCustomer from '@/pages/customers/Create'
|
||||
@@ -63,10 +63,10 @@ const MainRouter: FC = () => {
|
||||
<Route path={'/'} element={<Statistics />} />
|
||||
<Route path={Pages.dashboard} element={<Statistics />} />
|
||||
|
||||
<Route path={Pages.foods.list} element={<FoodsList />} />
|
||||
<Route path={Pages.foods.add} element={<CreateFood />} />
|
||||
<Route path={Pages.foods.update + ':id'} element={<UpdateFood />} />
|
||||
<Route path={Pages.foods.category} element={<CategoryFood />} />
|
||||
<Route path={Pages.products.list} element={<ProductsList />} />
|
||||
<Route path={Pages.products.add} element={<CreateProduct />} />
|
||||
<Route path={Pages.products.update + ':id'} element={<UpdateProduct />} />
|
||||
<Route path={Pages.products.category} element={<CategoryProduct />} />
|
||||
<Route path={Pages.customers.list} element={<CustomersList />} />
|
||||
<Route path={Pages.customers.detail + ':id'} element={<CustomerDetails />} />
|
||||
<Route path={Pages.customers.add} element={<CreateCustomer />} />
|
||||
|
||||
@@ -34,7 +34,7 @@ const Footer: FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
<Link to={Pages.foods.list}>
|
||||
<Link to={Pages.products.list}>
|
||||
<div className='text-description w-[70px] flex flex-col items-center gap-1.5'>
|
||||
<div className='bg-white p-1 rounded-full -mt-7'>
|
||||
<div className='bg-black flex justify-center items-center size-10 rounded-full'>
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useLocation } from 'react-router-dom'
|
||||
import { Pages } from '../config/Pages'
|
||||
import { useSharedStore } from './store/sharedStore'
|
||||
import { clx } from '../helpers/utils'
|
||||
import FoodsSubMenu from './components/FoodsSubMenu'
|
||||
import ProductsSubMenu from './components/ProductsSubMenu'
|
||||
import OrdersSubMenu from './components/OrdersSubMenu'
|
||||
import CustomersSubMenu from './components/CustomersSubMenu'
|
||||
import DiscountSubMenu from './components/DiscountSubMenu'
|
||||
@@ -115,11 +115,11 @@ const SideBar: FC = () => {
|
||||
|
||||
{checkPermission(PermissionEnum.MANAGE_FOODS) && (
|
||||
<SideBarItem
|
||||
icon={<Element3 variant={isActive('foods') ? 'Bold' : 'Outline'} color={isActive('foods') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
|
||||
icon={<Element3 variant={isActive('products') ? 'Bold' : 'Outline'} color={isActive('products') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
|
||||
title={t('sidebar.foods')}
|
||||
isActive={isActive('foods')}
|
||||
link={Pages.foods.list}
|
||||
activeName='foods'
|
||||
isActive={isActive('products')}
|
||||
link={Pages.products.list}
|
||||
activeName='products'
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -353,8 +353,8 @@ const SideBar: FC = () => {
|
||||
hasSubMenu && (openSidebar || window.innerWidth > 1139) &&
|
||||
<div className='fixed xl:right-[112px] right-[96px] bg-white z-20 xl:top-4 xl:bottom-4 top-0 bottom-0 rounded-tl-[32px] rounded-bl-[32px] w-[190px] border-r border-border'>
|
||||
{
|
||||
subMenuName === 'foods' ?
|
||||
<FoodsSubMenu />
|
||||
subMenuName === 'products' ?
|
||||
<ProductsSubMenu />
|
||||
: subMenuName === 'orders' ?
|
||||
<OrdersSubMenu />
|
||||
: subMenuName === 'customers' ?
|
||||
|
||||
@@ -5,7 +5,7 @@ import SubMenuItem from './SubMenuItem'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import { Pages } from '../../config/Pages'
|
||||
|
||||
const FoodsSubMenu: FC = () => {
|
||||
const ProductsSubMenu: FC = () => {
|
||||
|
||||
const location = useLocation()
|
||||
const { t } = useTranslation('global')
|
||||
@@ -31,22 +31,21 @@ const FoodsSubMenu: FC = () => {
|
||||
<SubMenuItem
|
||||
title={t('submenu.foods_list')}
|
||||
isActive={isActive('list')}
|
||||
link={Pages.foods.list}
|
||||
link={Pages.products.list}
|
||||
/>
|
||||
<SubMenuItem
|
||||
title={t('submenu.add_food')}
|
||||
isActive={isActive('add')}
|
||||
link={Pages.foods.add}
|
||||
link={Pages.products.add}
|
||||
/>
|
||||
<SubMenuItem
|
||||
title={t('submenu.categories')}
|
||||
isActive={isActive('category')}
|
||||
link={Pages.foods.category}
|
||||
link={Pages.products.category}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default FoodsSubMenu
|
||||
|
||||
export default ProductsSubMenu
|
||||
Reference in New Issue
Block a user