blog category crud

This commit is contained in:
hamid zarghami
2025-04-15 14:58:17 +03:30
parent 63aecce426
commit d3031e5557
11 changed files with 350 additions and 87 deletions
+115 -79
View File
@@ -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>