create category themee

This commit is contained in:
hamid zarghami
2025-11-29 09:28:10 +03:30
parent 15c6d29bb1
commit 259fc8af97
9 changed files with 177 additions and 0 deletions
+5
View File
@@ -154,6 +154,11 @@ export const Pages = {
attributes: "/products/category/attributes/",
},
products: {
theme: {
list: "/products/theme",
create: "/products/theme/create",
update: "/products/theme/update/",
},
create: "/products/create",
list: "/products/list",
variants: "/products/variants/",
+90
View File
@@ -0,0 +1,90 @@
import PageTitle from '@/components/PageTitle'
import { useFormik } from 'formik'
import { type FC } from 'react'
import type { CreateThemeType } from './type/Types'
import { ThemeInputType } from './enum/Enum'
import * as Yup from 'yup'
import Input from '@/components/Input'
import Select from '@/components/Select'
import { useCreateTheme } from './hooks/useThemeData'
import { useNavigate } from 'react-router-dom'
import { Pages } from '@/config/Pages'
import { extractErrorMessage } from '@/helpers/utils'
import { toast } from 'react-toastify'
import Button from '@/components/Button'
import { TickCircle } from 'iconsax-react'
const CreateTheme: FC = () => {
const navigate = useNavigate()
const { mutate: createTheme, isPending } = useCreateTheme();
const formik = useFormik<CreateThemeType>({
initialValues: {
title: '',
inputType: ThemeInputType.Color,
},
validationSchema: Yup.object({
title: Yup.string().required('عنوان تم الزامی است'),
inputType: Yup.string().required('نوع ورودی تم الزامی است'),
}),
onSubmit: (values) => {
createTheme(values, {
onSuccess: () => {
navigate(Pages.products.theme.list)
},
onError: (error) => {
toast.error(extractErrorMessage(error))
}
})
},
})
return (
<div>
<PageTitle title1='افزودن تم' />
<div className='bg-white p-8 rounded-4xl'>
<div>
<Input
label='عنوان تم'
placeholder='عنوان تم را وارد کنید'
{...formik.getFieldProps('title')}
error_text={formik.touched.title && formik.errors.title ? formik.errors.title : ''}
/>
</div>
<div className='mt-5'>
<Select
label='نوع ورودی تم'
placeholder='انتخاب نوع ورودی تم'
value={formik.values.inputType}
onChange={(e) => formik.setFieldValue('inputType', e.target.value)}
items={[
{ value: ThemeInputType.Color, label: 'رنگ' },
{ value: ThemeInputType.Text, label: 'متن' },
]}
error_text={formik.touched.inputType && formik.errors.inputType ? formik.errors.inputType : ''}
/>
</div>
<div className='mt-5 flex justify-end'>
<Button
onClick={() => formik.handleSubmit()}
isLoading={isPending}
disabled={!formik.isValid || isPending}
className='w-fit'
>
<div className='flex gap-2 items-center'>
<TickCircle size={16} color='#fff' />
<div>ذخیره</div>
</div>
</Button>
</div>
</div>
</div>
)
}
export default CreateTheme
+31
View File
@@ -0,0 +1,31 @@
import { type FC } from 'react'
import PageTitle from '@/components/PageTitle'
import { useGetThemes } from './hooks/useThemeData'
import Button from '@/components/Button';
import { Link } from 'react-router-dom';
import { Pages } from '@/config/Pages';
import { Plus } from 'lucide-react';
const ThemeList: FC = () => {
const { data, isLoading } = useGetThemes();
return (
<div>
<PageTitle title1='تم ها' />
<div className='mt-5 flex justify-end'>
<Link to={Pages.products.theme.create}>
<Button
className='w-fit px-4 flex gap-2'
>
<Plus color='#fff' size={16} />
<span>افزودن تم</span>
</Button>
</Link>
</div>
</div>
)
}
export default ThemeList
+4
View File
@@ -0,0 +1,4 @@
export enum ThemeInputType {
Color = "color",
Text = "text",
}
+19
View File
@@ -0,0 +1,19 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import * as api from "../service/ThemeService";
export const useGetThemes = () => {
return useQuery({
queryKey: ["themes"],
queryFn: api.getThemes,
});
};
export const useCreateTheme = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: api.createTheme,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["themes"] });
},
});
};
+12
View File
@@ -0,0 +1,12 @@
import axios from "@/config/axios";
import type { CreateThemeType } from "../type/Types";
export const getThemes = async () => {
const { data } = await axios.get("/admin/category/theme");
return data;
};
export const createTheme = async (params: CreateThemeType) => {
const { data } = await axios.post("/admin/category/theme", params);
return data;
};
+6
View File
@@ -0,0 +1,6 @@
import type { ThemeInputType } from "../enum/Enum";
export type CreateThemeType = {
title: string;
inputType: ThemeInputType;
};
+5
View File
@@ -83,6 +83,8 @@ import Questions from '@/pages/products/Questions'
import Returns from '@/pages/orders/Returns'
import ReturnDetails from '@/pages/orders/ReturnDetails'
import Cancels from '@/pages/orders/Cancels'
import ThemeList from '@/pages/theme/List'
import CreateTheme from '@/pages/theme/Create'
const MainRouter: FC = () => {
const { hasSubMenu } = useSharedStore()
@@ -203,6 +205,9 @@ const MainRouter: FC = () => {
<Route path={Pages.orders.return} element={<Returns />} />
<Route path={`${Pages.orders.returnDetails}:id`} element={<ReturnDetails />} />
<Route path={Pages.orders.cancels} element={<Cancels />} />
<Route path={Pages.products.theme.list} element={<ThemeList />} />
<Route path={Pages.products.theme.create} element={<CreateTheme />} />
</Routes>
</div>
</div>
@@ -29,6 +29,11 @@ const ProductsSubMenu: FC = () => {
isActive={isActive('category')}
link={Pages.category.list}
/>
<SubMenuItem
title={'تم'}
isActive={isActive('theme')}
link={Pages.products.theme.list}
/>
<SubMenuItem
title={'برند ها'}
isActive={isActive('brands')}