review admin

This commit is contained in:
hamid zarghami
2025-03-02 12:09:18 +03:30
parent 0cf7dede8b
commit cac446007f
9 changed files with 175 additions and 2 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
VITE_TOKEN_NAME = 'admin_token'
VITE_REFRESH_TOKEN_NAME = 'admin_refresh_token'
VITE_BASE_URL = 'https://api.danakcorp.com'
# VITE_BASE_URL = 'http://192.168.0.245:4000'
# VITE_BASE_URL = 'http://192.168.1.124:4000'
+1
View File
@@ -13,6 +13,7 @@ export const Pages = {
list: "/services/list",
category: "/services/category",
plan: "/services/plan/",
review: "/services/reviews",
},
transactions: "/transactions",
receipts: {
+14 -1
View File
@@ -83,7 +83,20 @@
"user_list": "لیست کاربران",
"add_user": "افزودن کاربر",
"role_list": "لیست نقش ها",
"role_create": "افزودن نقش"
"role_create": "افزودن نقش",
"reviews": "نظرات"
},
"review": {
"title": "عنوان",
"comment": "نظر",
"user": "کاربر",
"service": "سرویس",
"date": "تاریخ",
"status": "وضعیت",
"approved": "تایید شده",
"rejected": "رد شده",
"approve": "تایید",
"reject": "رد"
},
"header": {
"search": "جستجو"
+104
View File
@@ -0,0 +1,104 @@
import { FC, useState } from 'react'
import { useChangeStatusReview, useGetReviews } from './hooks/useServiceData'
import { useTranslation } from 'react-i18next'
import Td from '../../components/Td'
import { ReviewItemType } from './types/ServiceTypes'
import moment from 'moment-jalaali'
import Button from '../../components/Button'
import { CloseCircle, TickCircle } from 'iconsax-react'
enum ReviewStatusEnum {
PENDING = 'PENDING',
APPROVED = 'APPROVED',
REJECTED = 'REJECTED'
}
const Reviews: FC = () => {
const { t } = useTranslation('global')
const [loadingType, setLoadingType] = useState<ReviewStatusEnum>(ReviewStatusEnum.PENDING)
const [loadingId, setLoadingId] = useState<string>('')
const getReviews = useGetReviews()
const changeStatusReview = useChangeStatusReview()
const handleChange = (status: ReviewStatusEnum, id: string) => {
setLoadingType(status)
setLoadingId(id)
changeStatusReview.mutate({ status, id }, {
onSuccess: () => {
getReviews.refetch()
}
})
}
return (
<div className='mt-4'>
<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('review.title')} />
<Td text={t('review.comment')} />
<Td text={t('review.user')} />
<Td text={t('review.service')} />
<Td text={t('review.date')} />
<Td text={t('review.status')} />
</tr>
</thead>
<tbody>
{
getReviews.data?.data?.reviews?.map((item: ReviewItemType) => (
<tr className='tr'>
<Td text={item.title} />
<Td text={item.comment} />
<Td text={item.user?.firstName + ' ' + item.user.lastName} />
<Td text={item.service?.name} />
<Td text={''}>
<div className='dltr text-right'>
{moment(item.createdAt).format('jYYYY-jMM-jDD HH:mm')}
</div>
</Td>
<Td text={''}>
{
item.status === 'PENDING' ?
<div className='flex gap-2'>
<Button
className='bg-green-500 text-xs h-7 w-fit px-3 text-white'
onClick={() => handleChange(ReviewStatusEnum.APPROVED, item.id)}
isLoading={changeStatusReview.isPending && loadingType === ReviewStatusEnum.APPROVED && item.id === loadingId}
>
<div className='flex gap-1.5 items-center'>
<TickCircle size={16} color='white' />
<div>
{t('review.approve')}
</div>
</div>
</Button>
<Button
className='bg-red-500 text-xs h-7 w-fit px-3 text-white'
onClick={() => handleChange(ReviewStatusEnum.REJECTED, item.id)}
isLoading={changeStatusReview.isPending && loadingType === ReviewStatusEnum.REJECTED && item.id === loadingId}
>
<div className='flex gap-1.5 items-center'>
<CloseCircle size={16} color='white' />
<div>
{t('review.reject')}
</div>
</div>
</Button>
</div>
:
t('review.' + item.status.toLowerCase())
}
</Td>
</tr>
))
}
</tbody>
</table>
</div>
</div>
)
}
export default Reviews
+14
View File
@@ -132,3 +132,17 @@ export const useUpdatePlan = (id: string) => {
mutationFn: (variables: UpdatePlanType) => api.updatePlan(id, variables),
});
};
export const useGetReviews = (page: number = 1) => {
return useQuery({
queryKey: ["reviews", page],
queryFn: () => api.getReviews(page),
});
};
export const useChangeStatusReview = () => {
return useMutation({
mutationFn: (variables: { status: string; id: string }) =>
api.changeStatusReview(variables),
});
};
@@ -115,3 +115,18 @@ export const updatePlan = async (id: string, params: UpdatePlanType) => {
const { data } = await axios.patch(`/subscriptions/${id}`, params);
return data;
};
export const getReviews = async (page: number) => {
const { data } = await axios.get(`/danak-services/reviews?page=${page}`);
return data;
};
export const changeStatusReview = async (params: {
status: string;
id: string;
}) => {
const { data } = await axios.patch(
`/danak-services/reviews/${params.id}/${params.status}`
);
return data;
};
+19
View File
@@ -82,3 +82,22 @@ export type UpdatePlanType = {
isActive?: boolean;
serviceId?: string;
};
export type ReviewItemType = {
id: string;
comment: string;
createdAt: string;
rating: number;
service: {
id: string;
name: string;
};
status: "APPROVED" | "PENDING" | "REJECTED";
title: string;
user: {
id: string;
firstName: string;
lastName: string;
profilePic: string;
};
};
+2
View File
@@ -54,6 +54,7 @@ import CreateLearning from '../pages/learning/Create'
import Plans from '../pages/service/Plans'
import GroupCreate from '../pages/users/GroupCreate'
import GroupList from '../pages/users/GroupList'
import Reviews from '../pages/service/Reviews'
const MainRouter: FC = () => {
@@ -80,6 +81,7 @@ const MainRouter: FC = () => {
<Route path={Pages.services.list} element={<ListService />} />
<Route path={Pages.services.category} element={<Category />} />
<Route path={Pages.services.plan + ':id'} element={<Plans />} />
<Route path={Pages.services.review} element={<Reviews />} />
<Route path={Pages.ticket.list} element={<TicketList />} />
<Route path={Pages.ticket.create} element={<CreateTicket />} />
<Route path={Pages.ticket.category} element={<TicketCategory />} />
@@ -44,6 +44,11 @@ const ServicesSubMenu: FC = () => {
isActive={isActive('category')}
link={Pages.services.category}
/>
<SubMenuItem
title={t('submenu.reviews')}
isActive={isActive('reviews')}
link={Pages.services.review}
/>
</div>
</div>
)