blog category crud
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
VITE_TOKEN_NAME = 'admin_token'
|
VITE_TOKEN_NAME = 'admin_token'
|
||||||
VITE_REFRESH_TOKEN_NAME = 'admin_refresh_token'
|
VITE_REFRESH_TOKEN_NAME = 'admin_refresh_token'
|
||||||
# VITE_BASE_URL = 'https://api.danakcorp.com'
|
VITE_BASE_URL = 'https://api.danakcorp.com'
|
||||||
VITE_BASE_URL = 'http://192.168.1.108:4000'
|
# VITE_BASE_URL = 'http://192.168.1.108:4000'
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { FC, InputHTMLAttributes } from 'react'
|
import { FC, InputHTMLAttributes } from 'react'
|
||||||
import Error from './Error'
|
import Error from './Error'
|
||||||
|
import { clx } from '../helpers/utils'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
label?: string,
|
label?: string,
|
||||||
@@ -17,8 +18,11 @@ const Textarea: FC<Props> = (props: Props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
<textarea
|
<textarea
|
||||||
className='border border-border leading-7 w-full rounded-xl px-4 py-3 min-h-[100px] mt-1 text-xs'
|
|
||||||
{...props}
|
{...props}
|
||||||
|
className={clx(
|
||||||
|
'border border-border leading-7 w-full rounded-xl px-4 py-3 min-h-[100px] mt-1 text-xs',
|
||||||
|
props.className
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
|
|
||||||
</textarea>
|
</textarea>
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ export const SideBarItemHasSubMenu = [
|
|||||||
"users",
|
"users",
|
||||||
"tickets",
|
"tickets",
|
||||||
"learning",
|
"learning",
|
||||||
|
"blog",
|
||||||
];
|
];
|
||||||
|
|||||||
+102
-66
@@ -1,15 +1,64 @@
|
|||||||
|
|
||||||
import { FC } from 'react'
|
import { FC, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import Select from '../../components/Select'
|
|
||||||
import Input from '../../components/Input'
|
import Input from '../../components/Input'
|
||||||
import Td from '../../components/Td'
|
import Td from '../../components/Td'
|
||||||
import SwitchComponent from '../../components/Switch'
|
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 "quill/dist/quill.snow.css";
|
||||||
import Button from '../../components/Button'
|
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 BlogCategory: FC = () => {
|
||||||
|
|
||||||
const { t } = useTranslation('global')
|
const { t } = useTranslation('global')
|
||||||
|
const getBlogCategories = useGetBlogCategories()
|
||||||
|
const [file, setFile] = useState<File>()
|
||||||
|
const singleUpload = useSingleUpload()
|
||||||
|
const createBlogCategory = useCreateBlogCategory()
|
||||||
|
const deleteBlogCategory = useDeleteBlogCategory()
|
||||||
|
const formik = useFormik<CreateBlogCategoryType>({
|
||||||
|
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 (
|
return (
|
||||||
<div className='mt-4'>
|
<div className='mt-4'>
|
||||||
<div className='flex justify-start items-center'>
|
<div className='flex justify-start items-center'>
|
||||||
@@ -19,86 +68,56 @@ const BlogCategory: FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className='flex gap-6 xl:mt-8 mt-4'>
|
<div className='flex gap-6 xl:mt-8 mt-4'>
|
||||||
<div className='flex-1'>
|
<div className='flex-1'>
|
||||||
<div className='flex items-end w-full justify-between'>
|
|
||||||
<div className='w-[200px]'>
|
|
||||||
<Select
|
|
||||||
items={[
|
|
||||||
{
|
|
||||||
label: 'تست',
|
|
||||||
value: 'active'
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
className='bg-white border'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='xl:w-[300px] w-full'>
|
|
||||||
<Input
|
|
||||||
variant='search'
|
|
||||||
placeholder={t('ads.search')}
|
|
||||||
className='bg-white w-full'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='bg-white min-h-[calc(100vh-245px)] mt-4 rounded-3xl'>
|
<div className='bg-white min-h-[calc(100vh-245px)] mt-4 rounded-3xl'>
|
||||||
<div className='relative overflow-x-auto rounded-3xl w-full'>
|
<div className='relative overflow-x-auto rounded-3xl w-full'>
|
||||||
<table className='w-full text-sm '>
|
<table className='w-full text-sm '>
|
||||||
<thead className='thead'>
|
<thead className='thead'>
|
||||||
<tr>
|
<tr>
|
||||||
<td className='w-[100px]'>
|
<Td text={''} />
|
||||||
|
|
||||||
</td>
|
|
||||||
<Td text={t('blog.number')} />
|
|
||||||
<Td text={t('blog.blog_title')} />
|
<Td text={t('blog.blog_title')} />
|
||||||
<Td text={t('blog.blog_Summary')} />
|
<Td text={'توضیحات'} />
|
||||||
<Td text={t('blog.category')} />
|
<Td text={t('blog.category')} />
|
||||||
<Td text={t('blog.shareDate')} />
|
<Td text={t('blog.shareDate')} />
|
||||||
<Td text={t('blog.status')} />
|
<Td text={t('')} />
|
||||||
<Td text={''} />
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr className='tr'>
|
{
|
||||||
|
getBlogCategories.data?.data?.categories?.map((item: BlogCategoryType) => {
|
||||||
|
return (
|
||||||
|
<tr key={item.id} className='tr'>
|
||||||
<td>
|
<td>
|
||||||
<div className='flex justify-center'>
|
<div className='flex justify-center'>
|
||||||
<TickSquare size={20} color='black' variant='Bold' />
|
<img src={item.iconUrl} className='w-10' />
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<Td text={t('blog.number')} />
|
<Td text={item.title} />
|
||||||
<Td text={t('blog.blog_title')} />
|
<Td text={item.description} />
|
||||||
<Td text={t('blog.blog_Summary')} />
|
|
||||||
<Td text={t('blog.category')} />
|
|
||||||
<Td text={t('blog.shareDate')} />
|
|
||||||
<Td text={t('')}>
|
<Td text={t('')}>
|
||||||
<SwitchComponent
|
<SwitchComponent
|
||||||
active={true}
|
active={true}
|
||||||
onChange={() => { }}
|
onChange={() => { }}
|
||||||
/>
|
/>
|
||||||
</Td>
|
</Td>
|
||||||
<Td text={''}>
|
<Td text={moment(item.createdAt).format('jYYYY/jMM/jDD')} />
|
||||||
<More size={20} color='black' className='rotate-90' />
|
|
||||||
</Td>
|
|
||||||
</tr>
|
|
||||||
<tr className='tr'>
|
|
||||||
<td>
|
|
||||||
<div className='flex justify-center'>
|
|
||||||
<TickSquare size={20} color='black' variant='Bold' />
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<Td text={t('blog.number')} />
|
|
||||||
<Td text={t('blog.blog_title')} />
|
|
||||||
<Td text={t('blog.blog_Summary')} />
|
|
||||||
<Td text={t('blog.category')} />
|
|
||||||
<Td text={t('blog.shareDate')} />
|
|
||||||
<Td text={t('')}>
|
<Td text={t('')}>
|
||||||
<SwitchComponent
|
<div className='flex gap-2 items-center'>
|
||||||
active={true}
|
<UpdateCategory id={item.id} />
|
||||||
onChange={() => { }}
|
<Trash size={20} color='red' onClick={() => {
|
||||||
/>
|
deleteBlogCategory.mutateAsync(item.id, {
|
||||||
</Td>
|
onSuccess: () => {
|
||||||
<Td text={''}>
|
toast.success('دسته بندی با موفقیت حذف شد')
|
||||||
<More size={20} color='black' className='rotate-90' />
|
getBlogCategories.refetch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}} />
|
||||||
|
</div>
|
||||||
</Td>
|
</Td>
|
||||||
</tr>
|
</tr>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@@ -115,27 +134,44 @@ const BlogCategory: FC = () => {
|
|||||||
{t('ads.deactive')}
|
{t('ads.deactive')}
|
||||||
</div>
|
</div>
|
||||||
<SwitchComponent
|
<SwitchComponent
|
||||||
active={false}
|
active={formik.values.isActive}
|
||||||
onChange={() => { }}
|
onChange={(value) => formik.setFieldValue('isActive', value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p className='mt-6 text-sm'>{t('blog.category_title')}</p>
|
|
||||||
<div className='mt-6'>
|
<div className='mt-6'>
|
||||||
<Input className='-mt-4' />
|
<Input
|
||||||
|
label='عنوان'
|
||||||
|
{...formik.getFieldProps('title')}
|
||||||
|
error_text={formik.touched.title && formik.errors.title ? formik.errors.title : undefined}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p className='mt-6 text-sm'>{t('blog.parent_category')}</p>
|
|
||||||
<div className='mt-6'>
|
<div className='mt-6'>
|
||||||
<Input className='-mt-4' />
|
<Textarea
|
||||||
|
label='توضیحات'
|
||||||
|
{...formik.getFieldProps('description')}
|
||||||
|
error_text={formik.touched.description && formik.errors.description ? formik.errors.description : undefined}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='mt-6'>
|
||||||
|
<UploadBoxDraggble
|
||||||
|
label='آپلود آیکون'
|
||||||
|
onChange={(file) => setFile(file[0])}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
className='w-[172px] absolute bottom-4 left-4'
|
className='w-[172px] absolute bottom-4 left-4'
|
||||||
|
onClick={() => formik.handleSubmit()}
|
||||||
|
isLoading={createBlogCategory.isPending || singleUpload.isPending}
|
||||||
>
|
>
|
||||||
<div className='flex gap-2 items-center'>
|
<div className='flex gap-2 items-center'>
|
||||||
<TickCircle size={20} color='white' />
|
<TickCircle size={20} color='white' />
|
||||||
<div>
|
<div>
|
||||||
{t('blog.submit')}
|
ذخیره
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ const BlogList: FC = () => {
|
|||||||
<Td text={''}>
|
<Td text={''}>
|
||||||
<p dangerouslySetInnerHTML={{ __html: item.previewContent }}></p>
|
<p dangerouslySetInnerHTML={{ __html: item.previewContent }}></p>
|
||||||
</Td>
|
</Td>
|
||||||
<Td text={item.category.title} />
|
<Td text={item.category?.title} />
|
||||||
<Td text={moment(item.createdAt).format('jYYYY/jMM/jDD')} />
|
<Td text={moment(item.createdAt).format('jYYYY/jMM/jDD')} />
|
||||||
{/* <Td text={t('')}>
|
{/* <Td text={t('')}>
|
||||||
<SwitchComponent
|
<SwitchComponent
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
import { Edit } from 'iconsax-react'
|
||||||
|
import { FC, useEffect, useState } from 'react'
|
||||||
|
import { useGetBlogCategoryDetail, useUpdateBlogCategory } from '../hooks/useBlogData'
|
||||||
|
import DefaulModal from '../../../components/DefaulModal'
|
||||||
|
import { useFormik } from 'formik'
|
||||||
|
import { CreateBlogCategoryType } from '../types/BlogTypes'
|
||||||
|
import Input from '../../../components/Input'
|
||||||
|
import Textarea from '../../../components/Textarea'
|
||||||
|
import UploadBox from '../../../components/UploadBox'
|
||||||
|
import { useSingleUpload } from '../../service/hooks/useServiceData'
|
||||||
|
import SwitchComponent from '../../../components/Switch'
|
||||||
|
import Button from '../../../components/Button'
|
||||||
|
import { toast } from 'react-toastify'
|
||||||
|
import { ErrorType } from '../../../helpers/types'
|
||||||
|
interface Props {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const UpdateCategory: FC<Props> = ({ id }) => {
|
||||||
|
const [isOpen, setIsOpen] = useState(false)
|
||||||
|
const [file, setFile] = useState<File>()
|
||||||
|
const { data } = useGetBlogCategoryDetail(id, isOpen)
|
||||||
|
const singleUpload = useSingleUpload()
|
||||||
|
const updateBlogCategory = useUpdateBlogCategory()
|
||||||
|
|
||||||
|
const formik = useFormik<CreateBlogCategoryType>({
|
||||||
|
initialValues: {
|
||||||
|
title: '',
|
||||||
|
description: '',
|
||||||
|
iconUrl: '',
|
||||||
|
isActive: true
|
||||||
|
},
|
||||||
|
onSubmit: async (values) => {
|
||||||
|
if (file) {
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('file', file)
|
||||||
|
await singleUpload.mutateAsync(formData, {
|
||||||
|
onSuccess: (data) => {
|
||||||
|
values.iconUrl = data.data.url
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
updateBlogCategory.mutateAsync({ id: id, params: values }, {
|
||||||
|
onSuccess: () => {
|
||||||
|
toast.success('دسته بندی با موفقیت ویرایش شد')
|
||||||
|
setIsOpen(false)
|
||||||
|
window.location.reload()
|
||||||
|
},
|
||||||
|
onError: (error: ErrorType) => {
|
||||||
|
toast.error(error.response?.data?.error.message[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (data?.data?.category) {
|
||||||
|
formik.setValues(data?.data?.category)
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [data])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Edit onClick={() => setIsOpen(true)} size={20} color='#888' />
|
||||||
|
|
||||||
|
<DefaulModal
|
||||||
|
open={isOpen}
|
||||||
|
close={() => setIsOpen(false)}
|
||||||
|
isHeader
|
||||||
|
title_header='ویرایش دسته بندی'
|
||||||
|
>
|
||||||
|
<div className='mt-8'>
|
||||||
|
<UploadBox
|
||||||
|
label='آپلود آیکون'
|
||||||
|
onChange={(file) => setFile(file[0])}
|
||||||
|
/>
|
||||||
|
<div className='mt-6'>
|
||||||
|
<Input
|
||||||
|
label='عنوان'
|
||||||
|
{...formik.getFieldProps('title')}
|
||||||
|
className='bg-white bg-opacity-25 w-full'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='mt-6'>
|
||||||
|
<Textarea
|
||||||
|
label='توضیحات'
|
||||||
|
{...formik.getFieldProps('description')}
|
||||||
|
className='bg-white bg-opacity-25 w-full'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='mt-6'>
|
||||||
|
<SwitchComponent
|
||||||
|
active={formik.values.isActive}
|
||||||
|
onChange={(value) => formik.setFieldValue('isActive', value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='mt-10 flex justify-end'>
|
||||||
|
<Button
|
||||||
|
onClick={() => formik.handleSubmit()}
|
||||||
|
className='w-fit px-7'
|
||||||
|
label='ذخیره'
|
||||||
|
isLoading={updateBlogCategory.isPending}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DefaulModal>
|
||||||
|
</div >
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UpdateCategory
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as api from "../service/BlogService";
|
import * as api from "../service/BlogService";
|
||||||
import { useQuery, useMutation } from "@tanstack/react-query";
|
import { useQuery, useMutation } from "@tanstack/react-query";
|
||||||
import { CreateBlogType } from "../types/BlogTypes";
|
import { CreateBlogCategoryType, CreateBlogType } from "../types/BlogTypes";
|
||||||
|
|
||||||
export const useGetBlogCategories = () => {
|
export const useGetBlogCategories = () => {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
@@ -9,6 +9,36 @@ export const useGetBlogCategories = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useCreateBlogCategory = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: api.createBlogCategory,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUpdateBlogCategory = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (data: { id: string; params: CreateBlogCategoryType }) =>
|
||||||
|
api.updateBlogCategory(data.id, data.params),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDeleteBlogCategory = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: api.deleteBlogCategory,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGetBlogCategoryDetail = (
|
||||||
|
id: string,
|
||||||
|
enabled: boolean = true
|
||||||
|
) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["blog-category-detail", id],
|
||||||
|
queryFn: () => api.getBlogCategoryDetail(id),
|
||||||
|
enabled,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const useGetBlogs = (search: string) => {
|
export const useGetBlogs = (search: string) => {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ["blogs", search],
|
queryKey: ["blogs", search],
|
||||||
|
|||||||
@@ -1,11 +1,34 @@
|
|||||||
import axios from "../../../config/axios";
|
import axios from "../../../config/axios";
|
||||||
import { CreateBlogType } from "../types/BlogTypes";
|
import { CreateBlogCategoryType, CreateBlogType } from "../types/BlogTypes";
|
||||||
|
|
||||||
export const getBlogCategories = async () => {
|
export const getBlogCategories = async () => {
|
||||||
const { data } = await axios.get("/blogs/categories/list");
|
const { data } = await axios.get("/blogs/categories/list");
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const createBlogCategory = async (params: CreateBlogCategoryType) => {
|
||||||
|
const { data } = await axios.post("/blogs/categories", params);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateBlogCategory = async (
|
||||||
|
id: string,
|
||||||
|
params: CreateBlogCategoryType
|
||||||
|
) => {
|
||||||
|
const { data } = await axios.patch(`/blogs/categories/${id}`, params);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteBlogCategory = async (id: string) => {
|
||||||
|
const { data } = await axios.delete(`/blogs/categories/${id}`);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getBlogCategoryDetail = async (id: string) => {
|
||||||
|
const { data } = await axios.get(`/blogs/categories/${id}`);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
export const getBlogs = async (search: string) => {
|
export const getBlogs = async (search: string) => {
|
||||||
const { data } = await axios.get(`/blogs/list?q=${search}`);
|
const { data } = await axios.get(`/blogs/list?q=${search}`);
|
||||||
return data;
|
return data;
|
||||||
|
|||||||
@@ -39,4 +39,13 @@ export type BlogCategoryType = {
|
|||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
iconUrl: string;
|
iconUrl: string;
|
||||||
|
createdAt: string;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CreateBlogCategoryType = {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
iconUrl: string;
|
||||||
|
isActive: boolean;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import CustomerSubMenu from './components/CustomerSubMenu'
|
|||||||
import TicketSubMenu from './components/TicketSubMenu'
|
import TicketSubMenu from './components/TicketSubMenu'
|
||||||
import UsersSubMenu from './components/UsersSubMenu'
|
import UsersSubMenu from './components/UsersSubMenu'
|
||||||
import LearningSubMenu from './components/LearningSubMenu'
|
import LearningSubMenu from './components/LearningSubMenu'
|
||||||
|
import BlogSubMenu from './components/BlogSubMenu'
|
||||||
const SideBar: FC = () => {
|
const SideBar: FC = () => {
|
||||||
|
|
||||||
const { t } = useTranslation('global')
|
const { t } = useTranslation('global')
|
||||||
@@ -275,6 +275,8 @@ const SideBar: FC = () => {
|
|||||||
<UsersSubMenu />
|
<UsersSubMenu />
|
||||||
: subMenuName === 'learning' ?
|
: subMenuName === 'learning' ?
|
||||||
<LearningSubMenu />
|
<LearningSubMenu />
|
||||||
|
: subMenuName === 'blog' ?
|
||||||
|
<BlogSubMenu />
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { DocumentText } from 'iconsax-react'
|
||||||
|
import { FC } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import SubMenuItem from './SubMenuItem'
|
||||||
|
import { Pages } from '../../config/Pages'
|
||||||
|
|
||||||
|
const BlogSubMenu: FC = () => {
|
||||||
|
|
||||||
|
const { t } = useTranslation('global')
|
||||||
|
|
||||||
|
const isActive = (name: string) => {
|
||||||
|
return location.pathname.includes(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='py-12'>
|
||||||
|
<div className='flex gap-3 items-center border-b pb-10 px-6'>
|
||||||
|
<DocumentText
|
||||||
|
size={24}
|
||||||
|
color='#000'
|
||||||
|
variant='Bold'
|
||||||
|
/>
|
||||||
|
<div className='text-xs'>
|
||||||
|
{t('sidebar.blog')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='flex flex-col mt-10 gap-4'>
|
||||||
|
<SubMenuItem
|
||||||
|
title={'لیست'}
|
||||||
|
isActive={isActive('list')}
|
||||||
|
link={Pages.blog.list}
|
||||||
|
/>
|
||||||
|
<SubMenuItem
|
||||||
|
title={'دسته بندی'}
|
||||||
|
isActive={isActive('create')}
|
||||||
|
link={Pages.blog.category}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BlogSubMenu
|
||||||
Reference in New Issue
Block a user