change food to product name

This commit is contained in:
hamid zarghami
2026-02-09 14:04:21 +03:30
parent eae2ba0e7a
commit 687fc1e6c2
28 changed files with 186 additions and 194 deletions
+5 -5
View File
@@ -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 -1
View File
@@ -1,5 +1,5 @@
export const SideBarItemHasSubMenu = [
"foods",
"products",
"orders",
"customers",
"discounts",
+5 -5
View File
@@ -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>
+5 -5
View File
@@ -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
@@ -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
@@ -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
@@ -78,4 +78,3 @@ const CategoryTableColumns = ({ onStatusChange, onEdit, onDelete, isDeleting = f
}
export default CategoryTableColumns
@@ -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
@@ -114,4 +114,3 @@ const IconSelectModal: FC<Props> = ({
}
export default IconSelectModal
@@ -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
@@ -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
@@ -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()
@@ -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
},
]
}
@@ -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
@@ -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"] });
},
});
};
@@ -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,
};
@@ -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
View File
@@ -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 />} />
+1 -1
View File
@@ -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'>
+7 -7
View File
@@ -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