Crud group
This commit is contained in:
@@ -33,6 +33,9 @@ export const Pages = {
|
||||
add: "/customers/add",
|
||||
detail: "/customers/detail/",
|
||||
update: "/customers/update/",
|
||||
groups: "/customers/groups",
|
||||
groupsAdd: "/customers/groups/add",
|
||||
groupsUpdate: "/customers/groups/update/",
|
||||
},
|
||||
discount: {
|
||||
list: "/discounts/list",
|
||||
|
||||
+2
-1
@@ -104,7 +104,8 @@
|
||||
"discount_list": "لیست تخفیف",
|
||||
"add_discount": "افزودن تخفیف",
|
||||
"customers_list": "لیست مشتریان",
|
||||
"add_customer": "افزودن مشتری"
|
||||
"add_customer": "افزودن مشتری",
|
||||
"groups": "گروه مشتری"
|
||||
},
|
||||
"guide": {
|
||||
"list_guide": "لیست راهنمای سرویس",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from "./groups/List";
|
||||
@@ -0,0 +1,60 @@
|
||||
import Button from "@/components/Button";
|
||||
import Input from "@/components/Input";
|
||||
import { extractErrorMessage } from "@/config/func";
|
||||
import { Pages } from "@/config/Pages";
|
||||
import type { ErrorType } from "@/helpers/types";
|
||||
import { useFormik } from "formik";
|
||||
import { TickCircle } from "iconsax-react";
|
||||
import { type FC } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import * as Yup from "yup";
|
||||
import { useCreateUserGroup } from "./hooks/useUserGroupData";
|
||||
import type { CreateUserGroupType } from "./types/Types";
|
||||
|
||||
const CreateUserGroup: FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const { mutate: createUserGroup, isPending } = useCreateUserGroup();
|
||||
|
||||
const formik = useFormik<CreateUserGroupType>({
|
||||
initialValues: {
|
||||
name: "",
|
||||
},
|
||||
validationSchema: Yup.object().shape({
|
||||
name: Yup.string().required("نام گروه الزامی است"),
|
||||
}),
|
||||
onSubmit: (values) => {
|
||||
createUserGroup(values, {
|
||||
onSuccess: () => {
|
||||
toast.success("گروه با موفقیت ایجاد شد");
|
||||
navigate(Pages.customers.groups);
|
||||
},
|
||||
onError: (error: ErrorType) => {
|
||||
toast.error(extractErrorMessage(error));
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="mt-5">
|
||||
<div className="flex w-full justify-between items-center">
|
||||
<div className="text-lg font-light">افزودن گروه مشتری</div>
|
||||
<Button className="px-5 w-fit" onClick={() => formik.handleSubmit()} isloading={isPending}>
|
||||
<div className="flex gap-2 items-center">
|
||||
<TickCircle className="size-5" color="white" />
|
||||
<div>ثبت گروه</div>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="mt-6">
|
||||
<div className="bg-white rounded-3xl p-6">
|
||||
<Input label="نام گروه" name="name" value={formik.values.name} onChange={formik.handleChange} error_text={formik.touched.name && formik.errors.name ? formik.errors.name : ""} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreateUserGroup;
|
||||
@@ -0,0 +1,75 @@
|
||||
import { type FC } from "react";
|
||||
import Table from "@/components/Table";
|
||||
import Filters from "@/components/Filters";
|
||||
import { Add } from "iconsax-react";
|
||||
import Button from "@/components/Button";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Pages } from "@/config/Pages";
|
||||
import {
|
||||
useDeleteUserGroup,
|
||||
useGetUserGroups,
|
||||
} from "./hooks/useUserGroupData";
|
||||
import { useUserGroupFilters } from "./hooks/useUserGroupFilters";
|
||||
import { getUserGroupTableColumns } from "./components/UserGroupTableColumns";
|
||||
import { useUserGroupFiltersFields } from "./components/UserGroupFiltersFields";
|
||||
|
||||
const UserGroupsList: FC = () => {
|
||||
const {
|
||||
filters,
|
||||
currentPage,
|
||||
apiParams,
|
||||
handleFiltersChange,
|
||||
handlePageChange,
|
||||
limit,
|
||||
} = useUserGroupFilters();
|
||||
|
||||
const { data: groupsData, isLoading } = useGetUserGroups(apiParams);
|
||||
const { mutate: deleteUserGroup, isPending: isDeleting } =
|
||||
useDeleteUserGroup();
|
||||
|
||||
const groups = groupsData?.data || [];
|
||||
const columns = getUserGroupTableColumns({
|
||||
onDelete: (id: string) => deleteUserGroup(id),
|
||||
isDeleting,
|
||||
});
|
||||
const filterFields = useUserGroupFiltersFields();
|
||||
const totalPages = Math.ceil(groups.length / limit) || 1;
|
||||
|
||||
return (
|
||||
<div className="mt-5">
|
||||
<div className="flex justify-between items-center">
|
||||
<h1 className="text-lg font-light">گروههای مشتری</h1>
|
||||
<Link to={Pages.customers.groupsAdd}>
|
||||
<Button className="w-fit px-6">
|
||||
<div className="flex gap-2 items-center">
|
||||
<Add color="#fff" size={20} />
|
||||
<span>افزودن گروه</span>
|
||||
</div>
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="mt-8">
|
||||
<Filters
|
||||
fields={filterFields}
|
||||
onChange={handleFiltersChange}
|
||||
initialValues={filters}
|
||||
searchField="search"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Table
|
||||
columns={columns}
|
||||
data={groups}
|
||||
isloading={isLoading}
|
||||
pagination={{
|
||||
currentPage,
|
||||
totalPages,
|
||||
onPageChange: handlePageChange,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserGroupsList;
|
||||
@@ -0,0 +1,91 @@
|
||||
import Button from "@/components/Button";
|
||||
import Input from "@/components/Input";
|
||||
import PageLoading from "@/components/PageLoading";
|
||||
import { extractErrorMessage } from "@/config/func";
|
||||
import { Pages } from "@/config/Pages";
|
||||
import type { ErrorType } from "@/helpers/types";
|
||||
import { useFormik } from "formik";
|
||||
import { TickCircle } from "iconsax-react";
|
||||
import { type FC, useEffect } from "react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import * as Yup from "yup";
|
||||
import { useGetUserGroup, useUpdateUserGroup } from "./hooks/useUserGroupData";
|
||||
import type { CreateUserGroupType } from "./types/Types";
|
||||
|
||||
const UpdateUserGroup: FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const { data: groupData, isLoading } = useGetUserGroup(id || "");
|
||||
const { mutate: updateUserGroup, isPending } = useUpdateUserGroup();
|
||||
|
||||
const group = groupData?.data;
|
||||
|
||||
const formik = useFormik<CreateUserGroupType>({
|
||||
initialValues: {
|
||||
name: "",
|
||||
},
|
||||
validationSchema: Yup.object().shape({
|
||||
name: Yup.string().required("نام گروه الزامی است"),
|
||||
}),
|
||||
onSubmit: (values) => {
|
||||
if (!id) return;
|
||||
|
||||
updateUserGroup(
|
||||
{ id, params: values },
|
||||
{
|
||||
onSuccess: () => {
|
||||
toast.success("گروه با موفقیت ویرایش شد");
|
||||
navigate(Pages.customers.groups);
|
||||
},
|
||||
onError: (error: ErrorType) => {
|
||||
toast.error(extractErrorMessage(error));
|
||||
},
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (group) {
|
||||
formik.setValues({
|
||||
name: group.name || "",
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [group]);
|
||||
|
||||
if (isLoading) {
|
||||
return <PageLoading />;
|
||||
}
|
||||
|
||||
if (!group) {
|
||||
return (
|
||||
<div className="w-full mt-4 flex justify-center items-center">
|
||||
<div>گروه یافت نشد</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mt-5">
|
||||
<div className="flex w-full justify-between items-center">
|
||||
<div className="text-lg font-light">ویرایش گروه مشتری</div>
|
||||
<Button className="px-5 w-fit" onClick={() => formik.handleSubmit()} isloading={isPending}>
|
||||
<div className="flex gap-2 items-center">
|
||||
<TickCircle className="size-5" color="white" />
|
||||
<div>ثبت تغییرات</div>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="mt-6">
|
||||
<div className="bg-white rounded-3xl p-6">
|
||||
<Input label="نام گروه" name="name" value={formik.values.name} onChange={formik.handleChange} error_text={formik.touched.name && formik.errors.name ? formik.errors.name : ""} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateUserGroup;
|
||||
@@ -0,0 +1,15 @@
|
||||
import { useMemo } from "react";
|
||||
import type { FieldType } from "@/components/Filters";
|
||||
|
||||
export const useUserGroupFiltersFields = (): FieldType[] => {
|
||||
return useMemo(
|
||||
() => [
|
||||
{
|
||||
type: "input",
|
||||
name: "search",
|
||||
placeholder: "جستجو",
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
import type { ColumnType } from "@/components/types/TableTypes";
|
||||
import type { UserGroup } from "../types/Types";
|
||||
import TrashWithConfrim from "@/components/TrashWithConfrim";
|
||||
import { Eye } from "iconsax-react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Pages } from "@/config/Pages";
|
||||
import { formatOptionalDate } from "@/helpers/func";
|
||||
|
||||
interface GetUserGroupTableColumnsParams {
|
||||
onDelete?: (id: string) => void;
|
||||
isDeleting?: boolean;
|
||||
}
|
||||
|
||||
export const getUserGroupTableColumns = ({
|
||||
onDelete,
|
||||
isDeleting,
|
||||
}: GetUserGroupTableColumnsParams = {}): ColumnType<UserGroup>[] => {
|
||||
return [
|
||||
{
|
||||
key: "name",
|
||||
title: "نام گروه",
|
||||
render: (item: UserGroup) => item.name || "-",
|
||||
},
|
||||
{
|
||||
key: "createdAt",
|
||||
title: "تاریخ ایجاد",
|
||||
render: (item: UserGroup) => formatOptionalDate(item.createdAt),
|
||||
},
|
||||
{
|
||||
key: "actions",
|
||||
title: "",
|
||||
render: (item: UserGroup) => (
|
||||
<div className="flex gap-2 items-center">
|
||||
<Link to={Pages.customers.groupsUpdate + item.id}>
|
||||
<Eye size={20} color="#8C90A3" className="cursor-pointer" />
|
||||
</Link>
|
||||
{onDelete && (
|
||||
<TrashWithConfrim
|
||||
onDelete={() => onDelete(item.id)}
|
||||
isloading={isDeleting}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import * as api from "../service/UserGroupService";
|
||||
import type { CreateUserGroupType, GetUserGroupsParams } from "../types/Types";
|
||||
|
||||
export const useGetUserGroups = (params?: GetUserGroupsParams) => {
|
||||
return useQuery({
|
||||
queryKey: ["user-groups", params],
|
||||
queryFn: () => api.getUserGroups(params),
|
||||
});
|
||||
};
|
||||
|
||||
export const useCreateUserGroup = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: api.createUserGroup,
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["user-groups"] });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteUserGroup = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: api.deleteUserGroup,
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["user-groups"] });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetUserGroup = (id: string) => {
|
||||
return useQuery({
|
||||
queryKey: ["user-group", id],
|
||||
queryFn: () => api.getUserGroup(id),
|
||||
enabled: !!id,
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateUserGroup = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: ({ id, params }: { id: string; params: CreateUserGroupType }) =>
|
||||
api.updateUserGroup(id, params),
|
||||
onSuccess: (_, { id }) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["user-groups"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["user-group", id] });
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
import { useMemo, useState } from "react";
|
||||
import type { FilterValues } from "@/components/Filters";
|
||||
|
||||
const DEFAULT_PAGE = 1;
|
||||
const DEFAULT_LIMIT = 10;
|
||||
|
||||
export const useUserGroupFilters = () => {
|
||||
const [filters, setFilters] = useState<FilterValues>({});
|
||||
const [currentPage, setCurrentPage] = useState(DEFAULT_PAGE);
|
||||
const [limit] = useState(DEFAULT_LIMIT);
|
||||
|
||||
const apiParams = useMemo(() => {
|
||||
const params: Record<string, unknown> = {
|
||||
page: currentPage,
|
||||
limit,
|
||||
};
|
||||
|
||||
if (filters.search) {
|
||||
params.search = filters.search;
|
||||
}
|
||||
|
||||
return params;
|
||||
}, [filters, currentPage, limit]);
|
||||
|
||||
const handleFiltersChange = (newFilters: FilterValues) => {
|
||||
setFilters(newFilters);
|
||||
setCurrentPage(DEFAULT_PAGE);
|
||||
};
|
||||
|
||||
const handlePageChange = (page: number) => {
|
||||
setCurrentPage(page);
|
||||
};
|
||||
|
||||
return {
|
||||
filters,
|
||||
currentPage,
|
||||
apiParams,
|
||||
handleFiltersChange,
|
||||
handlePageChange,
|
||||
limit,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
import axios from "@/config/axios";
|
||||
import type {
|
||||
CreateUserGroupType,
|
||||
GetUserGroupsParams,
|
||||
UserGroupResponse,
|
||||
UserGroupsResponse,
|
||||
} from "../types/Types";
|
||||
|
||||
export const getUserGroups = async (
|
||||
params?: GetUserGroupsParams
|
||||
): Promise<UserGroupsResponse> => {
|
||||
const { data } = await axios.get<UserGroupsResponse>("/admin/user-groups", {
|
||||
params,
|
||||
});
|
||||
return data;
|
||||
};
|
||||
|
||||
export const createUserGroup = async (params: CreateUserGroupType) => {
|
||||
const { data } = await axios.post("/admin/user-groups", params);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const deleteUserGroup = async (id: string) => {
|
||||
const { data } = await axios.delete(`/admin/user-groups/${id}`);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getUserGroup = async (id: string): Promise<UserGroupResponse> => {
|
||||
const { data } = await axios.get<UserGroupResponse>(
|
||||
`/admin/user-groups/${id}`
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const updateUserGroup = async (
|
||||
id: string,
|
||||
params: CreateUserGroupType
|
||||
) => {
|
||||
const { data } = await axios.patch(`/admin/user-groups/${id}`, params);
|
||||
return data;
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
import type { IResponse } from "@/types/response.types";
|
||||
|
||||
export type UserGroup = {
|
||||
id: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt: string | null;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type UserGroupsResponse = IResponse<UserGroup[]>;
|
||||
export type UserGroupResponse = IResponse<UserGroup>;
|
||||
|
||||
export type CreateUserGroupType = {
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type GetUserGroupsParams = {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
search?: string;
|
||||
};
|
||||
@@ -50,6 +50,9 @@ import Statistics from '@/pages/statistics/Statistics'
|
||||
import SlidersList from '@/pages/sliders/List'
|
||||
import CreateSlider from '@/pages/sliders/Create'
|
||||
import UpdateSlider from '@/pages/sliders/Update'
|
||||
import UserGroupsList from '@/pages/customers/groups/List'
|
||||
import CreateUserGroup from '@/pages/customers/groups/Create'
|
||||
import UpdateUserGroup from '@/pages/customers/groups/Update'
|
||||
const MainRouter: FC = () => {
|
||||
|
||||
const { hasSubMenu } = useSharedStore()
|
||||
@@ -78,6 +81,9 @@ const MainRouter: FC = () => {
|
||||
<Route path={Pages.customers.detail + ':id'} element={<CustomerDetails />} />
|
||||
<Route path={Pages.customers.add} element={<CreateCustomer />} />
|
||||
<Route path={Pages.customers.update + ':id'} element={<UpdateCustomer />} />
|
||||
<Route path={Pages.customers.groups} element={<UserGroupsList />} />
|
||||
<Route path={Pages.customers.groupsAdd} element={<CreateUserGroup />} />
|
||||
<Route path={Pages.customers.groupsUpdate + ':id'} element={<UpdateUserGroup />} />
|
||||
<Route path={Pages.orders.list} element={<OrdersList />} />
|
||||
<Route path={Pages.orders.add} element={<CreateOrder />} />
|
||||
<Route path={Pages.orders.foodReport} element={<FoodOrderReport />} />
|
||||
|
||||
@@ -1,45 +1,29 @@
|
||||
import { People } from 'iconsax-react'
|
||||
import { type FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import SubMenuItem from './SubMenuItem'
|
||||
import { Pages } from '../../config/Pages'
|
||||
import { People } from "iconsax-react";
|
||||
import { type FC } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Pages } from "../../config/Pages";
|
||||
import SubMenuItem from "./SubMenuItem";
|
||||
|
||||
const CustomerSubMenu: FC = () => {
|
||||
const { t } = useTranslation("global");
|
||||
|
||||
const { t } = useTranslation('global')
|
||||
const isActive = (name: string) => {
|
||||
return location.pathname.includes(name);
|
||||
};
|
||||
|
||||
const isActive = (name: string) => {
|
||||
return location.pathname.includes(name)
|
||||
}
|
||||
return (
|
||||
<div className="py-12">
|
||||
<div className="flex gap-3 items-center border-b border-border pb-10 px-6">
|
||||
<People size={24} color="#000" variant="Bold" />
|
||||
<div className="text-xs">{t("sidebar.customers")}</div>
|
||||
</div>
|
||||
|
||||
return (
|
||||
<div className='py-12'>
|
||||
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
|
||||
<People
|
||||
size={24}
|
||||
color='#000'
|
||||
variant='Bold'
|
||||
/>
|
||||
<div className='text-xs'>
|
||||
{t('sidebar.customers')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col mt-10 gap-4">
|
||||
<SubMenuItem title={t("submenu.customer_list")} isActive={isActive("list")} link={Pages.orders.list} />
|
||||
<SubMenuItem title={t("submenu.create_customer")} isActive={isActive("create")} link={Pages.orders.add} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
<div className='flex flex-col mt-10 gap-4'>
|
||||
<SubMenuItem
|
||||
title={t('submenu.customer_list')}
|
||||
isActive={isActive('list')}
|
||||
link={Pages.orders.list}
|
||||
/>
|
||||
<SubMenuItem
|
||||
title={t('submenu.create_customer')}
|
||||
isActive={isActive('create')}
|
||||
link={Pages.orders.add}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CustomerSubMenu
|
||||
export default CustomerSubMenu;
|
||||
|
||||
@@ -1,47 +1,33 @@
|
||||
import { People } from 'iconsax-react'
|
||||
import { type FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import SubMenuItem from './SubMenuItem'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import { Pages } from '../../config/Pages'
|
||||
import { People } from "iconsax-react";
|
||||
import { type FC } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { Pages } from "../../config/Pages";
|
||||
import SubMenuItem from "./SubMenuItem";
|
||||
|
||||
const CustomersSubMenu: FC = () => {
|
||||
const location = useLocation();
|
||||
const { t } = useTranslation("global");
|
||||
|
||||
const location = useLocation()
|
||||
const { t } = useTranslation('global')
|
||||
const isActive = (name: string) => {
|
||||
return location.pathname.includes(name);
|
||||
};
|
||||
|
||||
const isActive = (name: string) => {
|
||||
return location.pathname.includes(name)
|
||||
}
|
||||
return (
|
||||
<div className="py-12">
|
||||
<div className="flex gap-3 items-center border-b border-border pb-10 px-6">
|
||||
<People size={24} color="#000" variant="Bold" />
|
||||
<div className="text-xs">{t("sidebar.customers")}</div>
|
||||
</div>
|
||||
|
||||
return (
|
||||
<div className='py-12'>
|
||||
<div className='flex gap-3 items-center border-b border-border pb-10 px-6'>
|
||||
<People
|
||||
size={24}
|
||||
color='#000'
|
||||
variant='Bold'
|
||||
/>
|
||||
<div className='text-xs'>
|
||||
{t('sidebar.customers')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col mt-10 gap-4">
|
||||
<SubMenuItem title={t("submenu.customers_list")} isActive={isActive("list")} link={Pages.customers.list} />
|
||||
<SubMenuItem title={t("submenu.add_customer")} isActive={isActive("add")} link={Pages.customers.add} />
|
||||
|
||||
<div className='flex flex-col mt-10 gap-4'>
|
||||
<SubMenuItem
|
||||
title={t('submenu.customers_list')}
|
||||
isActive={isActive('list')}
|
||||
link={Pages.customers.list}
|
||||
/>
|
||||
<SubMenuItem
|
||||
title={t('submenu.add_customer')}
|
||||
isActive={isActive('add')}
|
||||
link={Pages.customers.add}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CustomersSubMenu
|
||||
<SubMenuItem title={t("submenu.groups")} isActive={isActive("groups")} link={Pages.customers.groups} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomersSubMenu;
|
||||
|
||||
Reference in New Issue
Block a user