From d3031e5557a8ee72b1c01c0f23259f302ea97e9a Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Tue, 15 Apr 2025 14:58:17 +0330 Subject: [PATCH] blog category crud --- .env | 4 +- src/components/Textarea.tsx | 6 +- src/config/SideBarSubMenu.ts | 1 + src/pages/blog/BlogCategory.tsx | 194 +++++++++++-------- src/pages/blog/BlogList.tsx | 2 +- src/pages/blog/components/UpdateCategory.tsx | 113 +++++++++++ src/pages/blog/hooks/useBlogData.ts | 32 ++- src/pages/blog/service/BlogService.ts | 25 ++- src/pages/blog/types/BlogTypes.ts | 9 + src/shared/SideBar.tsx | 6 +- src/shared/components/BlogSubMenu.tsx | 45 +++++ 11 files changed, 350 insertions(+), 87 deletions(-) create mode 100644 src/pages/blog/components/UpdateCategory.tsx create mode 100644 src/shared/components/BlogSubMenu.tsx diff --git a/.env b/.env index 6056929..343e676 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ VITE_TOKEN_NAME = 'admin_token' VITE_REFRESH_TOKEN_NAME = 'admin_refresh_token' -# VITE_BASE_URL = 'https://api.danakcorp.com' -VITE_BASE_URL = 'http://192.168.1.108:4000' \ No newline at end of file +VITE_BASE_URL = 'https://api.danakcorp.com' +# VITE_BASE_URL = 'http://192.168.1.108:4000' \ No newline at end of file diff --git a/src/components/Textarea.tsx b/src/components/Textarea.tsx index 60999e8..2872f79 100644 --- a/src/components/Textarea.tsx +++ b/src/components/Textarea.tsx @@ -1,5 +1,6 @@ import { FC, InputHTMLAttributes } from 'react' import Error from './Error' +import { clx } from '../helpers/utils' type Props = { label?: string, @@ -17,8 +18,11 @@ const Textarea: FC = (props: Props) => { } diff --git a/src/config/SideBarSubMenu.ts b/src/config/SideBarSubMenu.ts index ba3c2aa..73ef588 100644 --- a/src/config/SideBarSubMenu.ts +++ b/src/config/SideBarSubMenu.ts @@ -5,4 +5,5 @@ export const SideBarItemHasSubMenu = [ "users", "tickets", "learning", + "blog", ]; diff --git a/src/pages/blog/BlogCategory.tsx b/src/pages/blog/BlogCategory.tsx index 5229686..189e26f 100644 --- a/src/pages/blog/BlogCategory.tsx +++ b/src/pages/blog/BlogCategory.tsx @@ -1,15 +1,64 @@ -import { FC } from 'react' +import { FC, useState } from 'react' import { useTranslation } from 'react-i18next' -import Select from '../../components/Select' import Input from '../../components/Input' import Td from '../../components/Td' import SwitchComponent from '../../components/Switch' -import { TickSquare, More, TickCircle } from 'iconsax-react' +import { TickCircle, Trash } from 'iconsax-react' import "quill/dist/quill.snow.css"; import Button from '../../components/Button' +import { useCreateBlogCategory, useDeleteBlogCategory, useGetBlogCategories } from './hooks/useBlogData' +import { BlogCategoryType, CreateBlogCategoryType } from './types/BlogTypes' +import moment from 'moment-jalaali' +import { useFormik } from 'formik' +import * as Yup from 'yup' +import Textarea from '../../components/Textarea' +import UploadBoxDraggble from '../../components/UploadBoxDraggble' +import { useSingleUpload } from '../service/hooks/useServiceData' +import { toast } from 'react-toastify' +import UpdateCategory from './components/UpdateCategory' const BlogCategory: FC = () => { + const { t } = useTranslation('global') + const getBlogCategories = useGetBlogCategories() + const [file, setFile] = useState() + const singleUpload = useSingleUpload() + const createBlogCategory = useCreateBlogCategory() + const deleteBlogCategory = useDeleteBlogCategory() + const formik = useFormik({ + initialValues: { + title: '', + description: '', + iconUrl: '', + isActive: true + }, + validationSchema: Yup.object({ + title: Yup.string().required(t('errors.required')), + description: Yup.string().required(t('errors.required')), + }), + onSubmit: async (values) => { + if (!file) { + toast.error('فایل را انتخاب کنید') + return + } + const formData = new FormData() + formData.append('file', file) + await singleUpload.mutateAsync(formData, { + onSuccess: (data) => { + values.iconUrl = data.data.url + } + }) + + createBlogCategory.mutateAsync(values, { + onSuccess: () => { + toast.success('دسته بندی با موفقیت ثبت شد') + setFile(undefined) + formik.resetForm() + getBlogCategories.refetch() + } + }) + } + }) return (
@@ -19,86 +68,56 @@ const BlogCategory: FC = () => {
-
-
- -
-
- - - - - - - - - - - - + { + getBlogCategories.data?.data?.categories?.map((item: BlogCategoryType) => { + return ( + + + + + + ) + }) + } +
- - + - + - - +
-
- -
-
- - - - - - { }} - /> - - -
-
- -
-
- - - - - - { }} - /> - - -
+
+ +
+
+ + + { }} + /> + + +
+ + { + deleteBlogCategory.mutateAsync(item.id, { + onSuccess: () => { + toast.success('دسته بندی با موفقیت حذف شد') + getBlogCategories.refetch() + } + }) + }} /> +
+
@@ -115,27 +134,44 @@ const BlogCategory: FC = () => { {t('ads.deactive')}
{ }} + active={formik.values.isActive} + onChange={(value) => formik.setFieldValue('isActive', value)} />
-

{t('blog.category_title')}

+
- +
-

{t('blog.parent_category')}

+
- +