blog category crud
This commit is contained in:
+115
-79
@@ -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<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 (
|
||||
<div className='mt-4'>
|
||||
<div className='flex justify-start items-center'>
|
||||
@@ -19,86 +68,56 @@ const BlogCategory: FC = () => {
|
||||
</div>
|
||||
<div className='flex gap-6 xl:mt-8 mt-4'>
|
||||
<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='relative overflow-x-auto rounded-3xl w-full'>
|
||||
<table className='w-full text-sm '>
|
||||
<thead className='thead'>
|
||||
<tr>
|
||||
<td className='w-[100px]'>
|
||||
|
||||
</td>
|
||||
<Td text={t('blog.number')} />
|
||||
<Td text={''} />
|
||||
<Td text={t('blog.blog_title')} />
|
||||
<Td text={t('blog.blog_Summary')} />
|
||||
<Td text={'توضیحات'} />
|
||||
<Td text={t('blog.category')} />
|
||||
<Td text={t('blog.shareDate')} />
|
||||
<Td text={t('blog.status')} />
|
||||
<Td text={''} />
|
||||
<Td text={t('')} />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<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('')}>
|
||||
<SwitchComponent
|
||||
active={true}
|
||||
onChange={() => { }}
|
||||
/>
|
||||
</Td>
|
||||
<Td text={''}>
|
||||
<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('')}>
|
||||
<SwitchComponent
|
||||
active={true}
|
||||
onChange={() => { }}
|
||||
/>
|
||||
</Td>
|
||||
<Td text={''}>
|
||||
<More size={20} color='black' className='rotate-90' />
|
||||
</Td>
|
||||
</tr>
|
||||
{
|
||||
getBlogCategories.data?.data?.categories?.map((item: BlogCategoryType) => {
|
||||
return (
|
||||
<tr key={item.id} className='tr'>
|
||||
<td>
|
||||
<div className='flex justify-center'>
|
||||
<img src={item.iconUrl} className='w-10' />
|
||||
</div>
|
||||
</td>
|
||||
<Td text={item.title} />
|
||||
<Td text={item.description} />
|
||||
<Td text={t('')}>
|
||||
<SwitchComponent
|
||||
active={true}
|
||||
onChange={() => { }}
|
||||
/>
|
||||
</Td>
|
||||
<Td text={moment(item.createdAt).format('jYYYY/jMM/jDD')} />
|
||||
<Td text={t('')}>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<UpdateCategory id={item.id} />
|
||||
<Trash size={20} color='red' onClick={() => {
|
||||
deleteBlogCategory.mutateAsync(item.id, {
|
||||
onSuccess: () => {
|
||||
toast.success('دسته بندی با موفقیت حذف شد')
|
||||
getBlogCategories.refetch()
|
||||
}
|
||||
})
|
||||
}} />
|
||||
</div>
|
||||
</Td>
|
||||
</tr>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -115,27 +134,44 @@ const BlogCategory: FC = () => {
|
||||
{t('ads.deactive')}
|
||||
</div>
|
||||
<SwitchComponent
|
||||
active={false}
|
||||
onChange={() => { }}
|
||||
active={formik.values.isActive}
|
||||
onChange={(value) => formik.setFieldValue('isActive', value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p className='mt-6 text-sm'>{t('blog.category_title')}</p>
|
||||
|
||||
<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>
|
||||
<p className='mt-6 text-sm'>{t('blog.parent_category')}</p>
|
||||
|
||||
<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>
|
||||
|
||||
<Button
|
||||
className='w-[172px] absolute bottom-4 left-4'
|
||||
onClick={() => formik.handleSubmit()}
|
||||
isLoading={createBlogCategory.isPending || singleUpload.isPending}
|
||||
>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<TickCircle size={20} color='white' />
|
||||
<div>
|
||||
{t('blog.submit')}
|
||||
ذخیره
|
||||
</div>
|
||||
</div>
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user