diff --git a/src/config/func.ts b/src/config/func.ts index f1fa83f..d779275 100644 --- a/src/config/func.ts +++ b/src/config/func.ts @@ -45,3 +45,23 @@ export const NumberFormat = (num?: number): string => { if (!num) return "0"; return num.toLocaleString("fa-IR"); }; + +export interface IGeneralError { + status: number; + success: boolean; + error: { + message: string[]; + }; +} + +export const extractErrorMessage = ( + error: Error | unknown, + fallbackMessage: string = "خطایی رخ داده است", +): string => { + try { + const axiosError = error as { response?: { data: IGeneralError } }; + return axiosError?.response?.data?.error?.message?.[0] || fallbackMessage; + } catch { + return fallbackMessage; + } +}; diff --git a/src/pages/product/category/Create.tsx b/src/pages/product/category/Create.tsx index 5cb8ddf..f773e16 100644 --- a/src/pages/product/category/Create.tsx +++ b/src/pages/product/category/Create.tsx @@ -1,9 +1,124 @@ -import { type FC } from 'react' +import Input from '@/components/Input' +import { useFormik } from 'formik' +import { useState, type FC } from 'react' +import type { CreateCategoryType } from '../types/Types' +import * as Yup from 'yup' +import { useCreateCategory, useGetCategory } from '../hooks/useProductData' +import Select from '@/components/Select' +import Button from '@/components/Button' +import { AddSquare } from 'iconsax-react' +import UploadBox from '@/components/UploadBox' +import SwitchComponent from '@/components/Switch' +import { useSingleUpload } from '@/pages/uploader/hooks/useUploader' +import { toast } from 'react-toastify' +import { extractErrorMessage } from '@/config/func' const ProductCategory: FC = () => { + + const { data } = useGetCategory() + const { mutate, isPending } = useCreateCategory() + const { mutate: upload, isPending: isUploading } = useSingleUpload() + + + const [file, setFile] = useState() + + const handleSave = (values: CreateCategoryType) => { + mutate(values, { + onSuccess: () => { + toast.success('با موفقیت ذخیره شد') + }, + onError: (error) => { + toast.error(extractErrorMessage(error)) + } + }) + } + + const formik = useFormik({ + initialValues: { + title: '', + parentId: undefined, + order: 0, + isActive: true, + avatarUrl: undefined, + }, + validationSchema: Yup.object({ + title: Yup.string().required('این فیلد اجباری است.'), + }), + onSubmit: (values) => { + if (file) { + upload(file, { + onSuccess: (data) => { + values.avatarUrl = data?.data?.url + handleSave(values) + } + }) + } else { + handleSave(values) + } + } + }) + return (
-

دسته بندی محصولات

+
+ +

دسته جدید

+ +
+
+ +
+ setFile(files[0])} + /> +
+ +
+ + + +
+ +
+ formik.setFieldValue('isActive', value)} + /> +
+
) } diff --git a/src/pages/product/category/List.tsx b/src/pages/product/category/List.tsx index 9be6074..e389c56 100644 --- a/src/pages/product/category/List.tsx +++ b/src/pages/product/category/List.tsx @@ -10,6 +10,17 @@ const CategoryList: FC = () => { const { data } = useGetCategory() const column: ColumnType[] = [ + { + title: 'تصویر', + key: 'avatarUrl', + render: (item) => { + if (item.avatarUrl) { + return ( + + ) + } + } + }, { title: 'عنوان', key: 'title', diff --git a/src/pages/product/hooks/useProductData.ts b/src/pages/product/hooks/useProductData.ts index e41fed2..49424d0 100644 --- a/src/pages/product/hooks/useProductData.ts +++ b/src/pages/product/hooks/useProductData.ts @@ -1,4 +1,4 @@ -import { useQuery } from "@tanstack/react-query"; +import { useMutation, useQuery } from "@tanstack/react-query"; import * as api from "../service/ProductService"; export const useGetCategory = () => { @@ -7,3 +7,9 @@ export const useGetCategory = () => { queryFn: api.getCategory, }); }; + +export const useCreateCategory = () => { + return useMutation({ + mutationFn: api.createCategory, + }); +}; diff --git a/src/pages/product/service/ProductService.ts b/src/pages/product/service/ProductService.ts index c15e80c..a7ba062 100644 --- a/src/pages/product/service/ProductService.ts +++ b/src/pages/product/service/ProductService.ts @@ -1,7 +1,12 @@ import axios from "@/config/axios"; -import { type CategoriesResponse } from "../types/Types"; +import { type CategoriesResponse, type CreateCategoryType } from "../types/Types"; export const getCategory = async () => { const { data } = await axios.get("/admin/category"); return data; }; + +export const createCategory = async (params:CreateCategoryType) => { + const { data } = await axios.post("/admin/category", params); + return data; +}; \ No newline at end of file diff --git a/src/pages/product/types/Types.ts b/src/pages/product/types/Types.ts index be9a24a..30ad9c1 100644 --- a/src/pages/product/types/Types.ts +++ b/src/pages/product/types/Types.ts @@ -14,3 +14,11 @@ export interface CategoryType extends RowDataType { } export type CategoriesResponse = BaseResponse; + +export type CreateCategoryType = { + title: string, + parentId?: string, + isActive: boolean, + avatarUrl?: string, + order: number, +} diff --git a/src/pages/uploader/hooks/useUploader.ts b/src/pages/uploader/hooks/useUploader.ts new file mode 100644 index 0000000..a5d2bec --- /dev/null +++ b/src/pages/uploader/hooks/useUploader.ts @@ -0,0 +1,8 @@ +import { useMutation } from "@tanstack/react-query"; +import * as api from "../service/UploaderService"; + +export const useSingleUpload = () => { + return useMutation({ + mutationFn: api.singleUpload, + }); +}; diff --git a/src/pages/uploader/service/UploaderService.ts b/src/pages/uploader/service/UploaderService.ts new file mode 100644 index 0000000..c838788 --- /dev/null +++ b/src/pages/uploader/service/UploaderService.ts @@ -0,0 +1,12 @@ +import axios from "@/config/axios"; +import type { SingleUploadResponseType } from "../types/Types"; + +export const singleUpload = async (file: File) => { + const formData = new FormData(); + formData.append("file", file); + const { data } = await axios.post( + "/admin/single-file", + formData, + ); + return data; +}; diff --git a/src/pages/uploader/types/Types.ts b/src/pages/uploader/types/Types.ts new file mode 100644 index 0000000..11bd096 --- /dev/null +++ b/src/pages/uploader/types/Types.ts @@ -0,0 +1,12 @@ +import type { BaseResponse } from "@/shared/types/Types"; + +export type SingleUploadType = { + url: string; + file: { + url: string; + key: string; + bucket: string; + }; +}; + +export type SingleUploadResponseType = BaseResponse; diff --git a/src/router/MainRouter.tsx b/src/router/MainRouter.tsx index 6342395..2b70829 100644 --- a/src/router/MainRouter.tsx +++ b/src/router/MainRouter.tsx @@ -26,7 +26,8 @@ import LearningList from '@/pages/learning/List' import LearningCreate from '@/pages/learning/Create' import LearningCategory from '@/pages/learning/Category' import CategoryList from '@/pages/product/category/List' -import CreateCategory from '@/pages/learning/components/CreateCategory' +import CreateCategory from '@/pages/product/category/Create' + const MainRouter: FC = () => { return (