plan users
This commit is contained in:
@@ -110,5 +110,6 @@ export const Pages = {
|
|||||||
create: "/support/create",
|
create: "/support/create",
|
||||||
list: "/support/list",
|
list: "/support/list",
|
||||||
detail: "/support/detail/",
|
detail: "/support/detail/",
|
||||||
|
planUsers: "/support/plan-users/",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,4 +6,5 @@ export const SideBarItemHasSubMenu = [
|
|||||||
"tickets",
|
"tickets",
|
||||||
"learning",
|
"learning",
|
||||||
"blog",
|
"blog",
|
||||||
|
"support",
|
||||||
];
|
];
|
||||||
|
|||||||
+16
-2
@@ -102,7 +102,10 @@
|
|||||||
"add_user": "افزودن کاربر",
|
"add_user": "افزودن کاربر",
|
||||||
"role_list": "لیست نقش ها",
|
"role_list": "لیست نقش ها",
|
||||||
"role_create": "افزودن نقش",
|
"role_create": "افزودن نقش",
|
||||||
"reviews": "نظرات"
|
"reviews": "نظرات",
|
||||||
|
"create_plan": "ایجاد پلن",
|
||||||
|
"plan_users": "کاربران پلن",
|
||||||
|
"plan_list": "لیست پلن ها"
|
||||||
},
|
},
|
||||||
"review": {
|
"review": {
|
||||||
"title": "عنوان",
|
"title": "عنوان",
|
||||||
@@ -779,12 +782,23 @@
|
|||||||
"on_site_support": "پشتیبانی در محل",
|
"on_site_support": "پشتیبانی در محل",
|
||||||
"on_site_training": "آموزش در محل",
|
"on_site_training": "آموزش در محل",
|
||||||
"ticket_limit": "ظرفیت ارسال تیکت",
|
"ticket_limit": "ظرفیت ارسال تیکت",
|
||||||
|
"technical_issue_resolution": "رفع ایراد فنی",
|
||||||
|
"service_functionality_test": "تست عملکرد سرویس",
|
||||||
"plans": "پلن ها",
|
"plans": "پلن ها",
|
||||||
"plan_name": "نام پلن",
|
"plan_name": "نام پلن",
|
||||||
"price": "قیمت",
|
"price": "قیمت",
|
||||||
"duration": "مدت",
|
"duration": "مدت",
|
||||||
"features": "ویژگی ها",
|
"features": "ویژگی ها",
|
||||||
"actions": "عملیات",
|
"actions": "عملیات",
|
||||||
"new_plan": "پلن جدید"
|
"new_plan": "پلن جدید",
|
||||||
|
"plan_users": "کاربران ",
|
||||||
|
"ACTIVE": "فعال",
|
||||||
|
"INACTIVE": "غیرفعال",
|
||||||
|
"EXPIRED": "منقضی شده",
|
||||||
|
"start_date": "تاریخ شروع",
|
||||||
|
"end_date": "تاریخ پایان",
|
||||||
|
"status": "وضعیت",
|
||||||
|
"full_name": "نام و نام خانوادگی",
|
||||||
|
"users": "کاربران"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,17 +41,28 @@ const SupportList: FC = () => {
|
|||||||
<Td text={t('support.plan_name')} />
|
<Td text={t('support.plan_name')} />
|
||||||
<Td text={t('support.price')} />
|
<Td text={t('support.price')} />
|
||||||
<Td text={t('support.duration')} />
|
<Td text={t('support.duration')} />
|
||||||
|
<Td text={t('support.users')} />
|
||||||
<Td text={''} />
|
<Td text={''} />
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{
|
{
|
||||||
data?.data?.supportPlans?.map((item: { id: string, name: string, price: number, duration: string }) => {
|
data?.data?.supportPlans?.map((item: { id: string, name: string, price: number, duration: string, userCount: number }) => {
|
||||||
return (
|
return (
|
||||||
<tr className='tr' key={item.id}>
|
<tr className='tr' key={item.id}>
|
||||||
<Td text={item.name} />
|
<Td text={item.name} />
|
||||||
<Td text={NumberFormat(item.price)} />
|
<Td text={NumberFormat(item.price)} />
|
||||||
<Td text={item.duration} />
|
<Td text={item.duration} />
|
||||||
|
<Td text={''}>
|
||||||
|
<Link to={Pages.support.planUsers + item.id}>
|
||||||
|
<div className='flex items-center gap-2 text-blue-500'>
|
||||||
|
<div>
|
||||||
|
{item.userCount}
|
||||||
|
</div>
|
||||||
|
کاربر
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
</Td>
|
||||||
<Td text={''}>
|
<Td text={''}>
|
||||||
<div className='flex items-center gap-2'>
|
<div className='flex items-center gap-2'>
|
||||||
<Link to={Pages.support.detail + item.id}>
|
<Link to={Pages.support.detail + item.id}>
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { FC } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { useGetPlanUsers } from './hooks/useSupportData'
|
||||||
|
import { useParams } from 'react-router-dom'
|
||||||
|
import Td from '../../components/Td'
|
||||||
|
import moment from 'moment-jalaali'
|
||||||
|
import { PlanItemUserType } from './types/SupportTypes'
|
||||||
|
const PlanUsers: FC = () => {
|
||||||
|
|
||||||
|
const { t } = useTranslation('global')
|
||||||
|
const { id } = useParams()
|
||||||
|
const { data } = useGetPlanUsers(id)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='mt-4'>
|
||||||
|
<div>
|
||||||
|
{t('support.plan_users')} {data?.data?.users?.[0]?.supportPlan?.name}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='relative overflow-x-auto rounded-3xl mt-9 w-full'>
|
||||||
|
<table className='w-full text-sm '>
|
||||||
|
<thead className='thead'>
|
||||||
|
<tr>
|
||||||
|
<Td text={t('support.full_name')} />
|
||||||
|
<Td text={t('support.start_date')} />
|
||||||
|
<Td text={t('support.end_date')} />
|
||||||
|
<Td text={t('support.status')} />
|
||||||
|
<Td text={''} />
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{data?.data?.users?.map((item: PlanItemUserType) => (
|
||||||
|
<tr className='tr' key={item.id}>
|
||||||
|
<Td text={item.user.firstName + ' ' + item.user.lastName} />
|
||||||
|
<Td text={''}>
|
||||||
|
<div className='dltr text-right'>
|
||||||
|
{moment(item.startDate).format('jYYYY/jMM/jDD HH:mm')}
|
||||||
|
</div>
|
||||||
|
</Td>
|
||||||
|
<Td text={''}>
|
||||||
|
<div className='dltr text-right'>
|
||||||
|
{moment(item.endDate).format('jYYYY/jMM/jDD HH:mm')}
|
||||||
|
</div>
|
||||||
|
</Td>
|
||||||
|
<Td text={t(`support.${item.status}`)} />
|
||||||
|
<Td text={''} />
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PlanUsers
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
export enum SupportPlanFeatureKey {
|
export enum SupportPlanFeatureKey {
|
||||||
LEARNING_DOCS = "learning_docs", // راهنما و مستندات آموزشی
|
LEARNING_DOCS = "learning_docs", // راهنما و مستندات آموزشی
|
||||||
TICKET_SUPPORT = "ticket_support", // ارسال تیکت
|
TICKET_SUPPORT = "ticket_support", // ارسال تیکت
|
||||||
|
TICKET_LIMIT = "ticket_limit", // ظرفیت ارسال تیکت
|
||||||
RESPONSE_TIME = "response_time", // زمان پاسخگویی به تیکت
|
RESPONSE_TIME = "response_time", // زمان پاسخگویی به تیکت
|
||||||
PHONE_SUPPORT = "phone_support", // پاسخگویی تلفنی
|
PHONE_SUPPORT = "phone_support", // پاسخگویی تلفنی
|
||||||
BACKUP_VERSION = "backup_version", // نسخه بکاپ
|
TECHNICAL_ISSUE_RESOLUTION = "technical_issue_resolution", // رفع ایراد فنی
|
||||||
TECHNICAL_EXPERT_ACCESS = "technical_expert_access", // دسترسی به متخصصین فنی
|
TECHNICAL_EXPERT_ACCESS = "technical_expert_access", // دسترسی به متخصصین فنی
|
||||||
|
BACKUP_VERSION = "backup_version", // نسخه بکاپ
|
||||||
|
SERVICE_FUNCTIONALITY_TEST = "service_functionality_test", // تست عملکرد سرویس
|
||||||
ON_SITE_SUPPORT = "on_site_support", // پشتیبانی در محل
|
ON_SITE_SUPPORT = "on_site_support", // پشتیبانی در محل
|
||||||
ON_SITE_TRAINING = "on_site_training", // آموزش در محل
|
ON_SITE_TRAINING = "on_site_training", // آموزش در محل
|
||||||
TICKET_LIMIT = "ticket_limit", // ظرفیت ارسال تیکت
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,3 +34,11 @@ export const useDeletePlan = () => {
|
|||||||
mutationFn: (id: string) => api.deletePlan(id),
|
mutationFn: (id: string) => api.deletePlan(id),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useGetPlanUsers = (id?: string) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["plan-users", id],
|
||||||
|
queryFn: () => api.getPlanUsers(id),
|
||||||
|
enabled: !!id,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -25,3 +25,8 @@ export const deletePlan = async (id: string) => {
|
|||||||
const { data } = await axios.delete(`/support-plans/${id}`);
|
const { data } = await axios.delete(`/support-plans/${id}`);
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getPlanUsers = async (id?: string) => {
|
||||||
|
const { data } = await axios.get(`/support-plans/${id}/users`);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|||||||
@@ -10,3 +10,40 @@ export type CreatePlanType = {
|
|||||||
featureType: "boolean" | "text";
|
featureType: "boolean" | "text";
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type PlanItemUserType = {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
user: {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
email: string;
|
||||||
|
phone: string;
|
||||||
|
userName: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
birthDate: string;
|
||||||
|
nationalCode: string;
|
||||||
|
profilePic: string | null;
|
||||||
|
emailVerified: boolean;
|
||||||
|
financialType: string;
|
||||||
|
deletedAt: string | null;
|
||||||
|
};
|
||||||
|
supportPlan: {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
price: number;
|
||||||
|
isFree: boolean;
|
||||||
|
duration: number;
|
||||||
|
isActive: boolean;
|
||||||
|
deletedAt: string | null;
|
||||||
|
};
|
||||||
|
startDate: string;
|
||||||
|
endDate: string;
|
||||||
|
status: string;
|
||||||
|
};
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ import Comments from '../pages/blog/Comments'
|
|||||||
import CreatePlan from '../pages/support/Create'
|
import CreatePlan from '../pages/support/Create'
|
||||||
import SupportList from '../pages/support/List'
|
import SupportList from '../pages/support/List'
|
||||||
import UpdateSupport from '../pages/support/Update'
|
import UpdateSupport from '../pages/support/Update'
|
||||||
|
import PlanUsers from '../pages/support/PlanUsers'
|
||||||
const MainRouter: FC = () => {
|
const MainRouter: FC = () => {
|
||||||
|
|
||||||
const { hasSubMenu } = useSharedStore()
|
const { hasSubMenu } = useSharedStore()
|
||||||
@@ -147,6 +148,7 @@ const MainRouter: FC = () => {
|
|||||||
<Route path={Pages.support.create} element={<CreatePlan />} />
|
<Route path={Pages.support.create} element={<CreatePlan />} />
|
||||||
<Route path={Pages.support.list} element={<SupportList />} />
|
<Route path={Pages.support.list} element={<SupportList />} />
|
||||||
<Route path={Pages.support.detail + ':id'} element={<UpdateSupport />} />
|
<Route path={Pages.support.detail + ':id'} element={<UpdateSupport />} />
|
||||||
|
<Route path={Pages.support.planUsers + ':id'} element={<PlanUsers />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import UsersSubMenu from './components/UsersSubMenu'
|
|||||||
import LearningSubMenu from './components/LearningSubMenu'
|
import LearningSubMenu from './components/LearningSubMenu'
|
||||||
import BlogSubMenu from './components/BlogSubMenu'
|
import BlogSubMenu from './components/BlogSubMenu'
|
||||||
import { useGetProfile } from '../pages/profile/hooks/useProfileData'
|
import { useGetProfile } from '../pages/profile/hooks/useProfileData'
|
||||||
|
import SupportSubMenu from './components/SupportSubMenu'
|
||||||
const SideBar: FC = () => {
|
const SideBar: FC = () => {
|
||||||
|
|
||||||
const { t } = useTranslation('global')
|
const { t } = useTranslation('global')
|
||||||
@@ -324,7 +325,9 @@ const SideBar: FC = () => {
|
|||||||
<LearningSubMenu />
|
<LearningSubMenu />
|
||||||
: subMenuName === 'blog' ?
|
: subMenuName === 'blog' ?
|
||||||
<BlogSubMenu />
|
<BlogSubMenu />
|
||||||
: null
|
: subMenuName === 'support' ?
|
||||||
|
<SupportSubMenu />
|
||||||
|
: null
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { Headphone } from 'iconsax-react'
|
||||||
|
import { FC } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { useLocation } from 'react-router-dom'
|
||||||
|
import { Pages } from '../../config/Pages'
|
||||||
|
import SubMenuItem from './SubMenuItem'
|
||||||
|
|
||||||
|
const SupportSubMenu: FC = () => {
|
||||||
|
|
||||||
|
const location = useLocation()
|
||||||
|
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'>
|
||||||
|
<Headphone
|
||||||
|
size={24}
|
||||||
|
color='#000'
|
||||||
|
variant='Bold'
|
||||||
|
/>
|
||||||
|
<div className='text-xs'>
|
||||||
|
{t('sidebar.support')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='flex flex-col mt-10 gap-4'>
|
||||||
|
<SubMenuItem
|
||||||
|
title={t('submenu.plan_list')}
|
||||||
|
isActive={isActive('list')}
|
||||||
|
link={Pages.support.list}
|
||||||
|
/>
|
||||||
|
<SubMenuItem
|
||||||
|
title={t('submenu.create_plan')}
|
||||||
|
isActive={isActive('create')}
|
||||||
|
link={Pages.support.create}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SupportSubMenu
|
||||||
Reference in New Issue
Block a user