users
This commit is contained in:
+11
-8
@@ -72,14 +72,17 @@ export const Pages = {
|
||||
referralCode: {
|
||||
list: "/referral-code/list",
|
||||
},
|
||||
users: {
|
||||
list: "/users/list",
|
||||
create: "/users/create",
|
||||
detail: "/users/detail/",
|
||||
roleList: "/users/roles-all",
|
||||
roleCreate: "/users/roles-add",
|
||||
groupAdd: "/users/group-add",
|
||||
groupList: "/users/groups",
|
||||
admin: {
|
||||
list: "/admin/list",
|
||||
create: "/admin/create",
|
||||
detail: "/admin/detail/",
|
||||
roleList: "/admin/roles-all",
|
||||
roleCreate: "/admin/roles-add",
|
||||
groupAdd: "/admin/group-add",
|
||||
groupList: "/admin/groups",
|
||||
},
|
||||
buyUsers: {
|
||||
list: "/buy-users/list",
|
||||
},
|
||||
ads: {
|
||||
list: "/ads/list",
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
import { type FC, useState } from 'react'
|
||||
import { useGetUsers } from './hooks/useUserData'
|
||||
import { type User } from './types/Types'
|
||||
import PageLoading from '../../components/PageLoading'
|
||||
import Error from '../../components/Error'
|
||||
import PaginationUi from '../../components/PaginationUi'
|
||||
import Td from '../../components/Td'
|
||||
import { Calendar, Call, Card, User as UserIcon } from 'iconsax-react'
|
||||
|
||||
const UsersList: FC = () => {
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const { data: usersData, isLoading, error } = useGetUsers(currentPage);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex justify-center items-center min-h-[400px]">
|
||||
<PageLoading />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="flex justify-center items-center min-h-[400px]">
|
||||
<Error errorText="خطا در بارگذاری کاربران" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const users = usersData?.results?.users || [];
|
||||
const pager = usersData?.results?.pager;
|
||||
|
||||
const formatDate = (dateString: string) => {
|
||||
if (!dateString) return '-';
|
||||
return new Date(dateString).toLocaleDateString('fa-IR');
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='relative overflow-x-auto rounded-3xl mt-5 w-full'>
|
||||
<table className='w-full text-sm'>
|
||||
<thead className='thead'>
|
||||
<tr>
|
||||
<Td text={'نام و نام خانوادگی'} />
|
||||
<Td text={'شماره تلفن'} />
|
||||
<Td text={'کد ملی'} />
|
||||
<Td text={'تاریخ تولد'} />
|
||||
<Td text={'تاریخ ثبتنام'} />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{users.length === 0 ? (
|
||||
<tr className='tr'>
|
||||
<td colSpan={6} className="text-center py-8 text-gray-500">
|
||||
هیچ کاربری یافت نشد
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
users.map((user: User) => (
|
||||
<tr key={user._id} className='tr'>
|
||||
<Td text="">
|
||||
<div className="flex items-center gap-2">
|
||||
<UserIcon size={16} color="#8C90A3" />
|
||||
<span>{user.fullName || '-'}</span>
|
||||
</div>
|
||||
</Td>
|
||||
<Td text="">
|
||||
<div className="flex items-center gap-2">
|
||||
<Call size={16} color="#8C90A3" />
|
||||
<span>{user.phoneNumber}</span>
|
||||
</div>
|
||||
</Td>
|
||||
<Td text="">
|
||||
<div className="flex items-center gap-2">
|
||||
<Card size={16} color="#8C90A3" />
|
||||
<span>{user.nationalCode || '-'}</span>
|
||||
</div>
|
||||
</Td>
|
||||
<Td text="">
|
||||
<div className="flex items-center gap-2">
|
||||
<Calendar size={16} color="#8C90A3" />
|
||||
<span>{user.dateOfBirth}</span>
|
||||
</div>
|
||||
</Td>
|
||||
<Td text={formatDate(user.createdAt)} />
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<PaginationUi
|
||||
pager={pager}
|
||||
onPageChange={(page) => {
|
||||
setCurrentPage(page);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default UsersList
|
||||
@@ -0,0 +1,9 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import * as api from "../service/UserService";
|
||||
|
||||
export const useGetUsers = (page: number = 1, limit: number = 10) => {
|
||||
return useQuery({
|
||||
queryKey: ["users", page, limit],
|
||||
queryFn: () => api.getUsers(page, limit),
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
import axios from "../../../config/axios";
|
||||
|
||||
import type { UserResponse } from "../types/Types";
|
||||
|
||||
export const getUsers = async (
|
||||
page: number = 1,
|
||||
limit: number = 10
|
||||
): Promise<UserResponse> => {
|
||||
const { data } = await axios.get("/admin/users", {
|
||||
params: { page, limit },
|
||||
});
|
||||
return data;
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
export interface User {
|
||||
_id: string;
|
||||
fullName: string;
|
||||
phoneNumber: string;
|
||||
dateOfBirth: string | null;
|
||||
address: string | null;
|
||||
nationalCode: string | null;
|
||||
homeNumber: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
__v: number;
|
||||
}
|
||||
|
||||
export interface Pager {
|
||||
page: number;
|
||||
limit: number;
|
||||
totalItems: number;
|
||||
totalPages: number;
|
||||
prevPage: boolean;
|
||||
nextPage: string | null;
|
||||
}
|
||||
|
||||
export interface UserResults {
|
||||
users: User[];
|
||||
pager: Pager;
|
||||
}
|
||||
|
||||
export interface UserResponse {
|
||||
status: number;
|
||||
success: boolean;
|
||||
results: UserResults;
|
||||
}
|
||||
@@ -32,6 +32,7 @@ import CreateShipment from '@/pages/shipment/Create'
|
||||
import CouponList from '@/pages/Coupon/List'
|
||||
import CreateCoupon from '@/pages/Coupon/Create'
|
||||
import UpdateCoupon from '@/pages/Coupon/Update'
|
||||
import UsersList from '@/pages/user/List'
|
||||
|
||||
const MainRouter: FC = () => {
|
||||
|
||||
@@ -83,6 +84,8 @@ const MainRouter: FC = () => {
|
||||
<Route path={Pages.coupon.list} element={<CouponList />} />
|
||||
<Route path={Pages.coupon.create} element={<CreateCoupon />} />
|
||||
<Route path={`${Pages.coupon.detail}:id`} element={<UpdateCoupon />} />
|
||||
|
||||
<Route path={Pages.buyUsers.list} element={<UsersList />} />
|
||||
</Routes>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+18
-18
@@ -46,7 +46,7 @@ const SideBar: FC = () => {
|
||||
|
||||
if (split[1] === 'dashboard' || split[1] === 'products' || split[1] === 'orders' ||
|
||||
split[1] === 'blog' || split[1] === 'shipment' || split[1] === 'financial' ||
|
||||
split[1] === 'sellers' || split[1] === 'buyers' || split[1] === 'users' ||
|
||||
split[1] === 'sellers' || split[1] === 'buyers' || split[1] === 'admin' ||
|
||||
split[1] === 'tickets' || split[1] === 'reports' || split[1] === 'chat' ||
|
||||
split[1] === 'contact' || split[1] === 'settings' || split[1] === 'pages' ||
|
||||
split[1] === 'jobs' || split[1] === 'category') {
|
||||
@@ -164,20 +164,20 @@ const SideBar: FC = () => {
|
||||
|
||||
{/* خریداران */}
|
||||
<SideBarItem
|
||||
icon={<UserSquare variant={isActive('buyers') ? 'Bold' : 'Outline'} color={isActive('buyers') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
|
||||
icon={<UserSquare variant={isActive('buy-users') ? 'Bold' : 'Outline'} color={isActive('buy-users') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
|
||||
title="خریداران"
|
||||
isActive={isActive('buyers')}
|
||||
link="/buyers"
|
||||
activeName='buyers'
|
||||
isActive={isActive('buy-users')}
|
||||
link={Pages.buyUsers.list}
|
||||
activeName='buy-users'
|
||||
/>
|
||||
|
||||
{/* کاربران */}
|
||||
<SideBarItem
|
||||
icon={<Profile variant={isActive('users') ? 'Bold' : 'Outline'} color={isActive('users') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
|
||||
title="کاربران"
|
||||
isActive={isActive('users')}
|
||||
link="/users"
|
||||
activeName='users'
|
||||
icon={<Profile variant={isActive('admin') ? 'Bold' : 'Outline'} color={isActive('admin') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
|
||||
title="ادمین ها"
|
||||
isActive={isActive('admin')}
|
||||
link="/admin"
|
||||
activeName='admin'
|
||||
/>
|
||||
|
||||
{/* تیکت ها */}
|
||||
@@ -271,8 +271,8 @@ const SideBar: FC = () => {
|
||||
: subMenuName === 'shipment' ? <ShippingSubMenu />
|
||||
: subMenuName === 'financial' ? <FinancialSubMenu />
|
||||
: subMenuName === 'sellers' ? <SellersSubMenu />
|
||||
: subMenuName === 'buyers' ? <BuyersSubMenu />
|
||||
: subMenuName === 'users' ? <UsersSubMenu />
|
||||
: subMenuName === 'buy-users' ? <BuyersSubMenu />
|
||||
: subMenuName === 'admin' ? <UsersSubMenu />
|
||||
: subMenuName === 'tickets' ? <TicketsSubMenu />
|
||||
: subMenuName === 'reports' ? <ReportsSubMenu />
|
||||
: subMenuName === 'chat' ? <ChatSubMenu />
|
||||
@@ -563,7 +563,7 @@ const BuyersSubMenu: FC = () => {
|
||||
<SubMenuItem
|
||||
title={'لیست خریداران'}
|
||||
isActive={isActive('list')}
|
||||
link="/buyers/list"
|
||||
link={Pages.buyUsers.list}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -584,25 +584,25 @@ const UsersSubMenu: FC = () => {
|
||||
variant='Bold'
|
||||
/>
|
||||
<div className='text-xs'>
|
||||
کاربران
|
||||
ادمین ها
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col mt-10 gap-4'>
|
||||
<SubMenuItem
|
||||
title={'لیست کاربران'}
|
||||
title={'لیست ادمین ها'}
|
||||
isActive={isActive('list')}
|
||||
link="/users/list"
|
||||
link={Pages.admin.list}
|
||||
/>
|
||||
<SubMenuItem
|
||||
title={'تعریف نقش'}
|
||||
isActive={isActive('roles')}
|
||||
link="/users/roles"
|
||||
link={Pages.admin.roleList}
|
||||
/>
|
||||
<SubMenuItem
|
||||
title={'تعریف گروه کاربری'}
|
||||
isActive={isActive('groups')}
|
||||
link="/users/groups"
|
||||
link={Pages.admin.groupList}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
import { Profile } from 'iconsax-react'
|
||||
import { type FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import SubMenuItem from './SubMenuItem'
|
||||
import { Pages } from '../../config/Pages'
|
||||
|
||||
const UsersSubMenu: FC = () => {
|
||||
|
||||
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'>
|
||||
<Profile
|
||||
size={24}
|
||||
color='#000'
|
||||
variant='Bold'
|
||||
/>
|
||||
<div className='text-xs'>
|
||||
{t('sidebar.users')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col mt-10 gap-4'>
|
||||
<SubMenuItem
|
||||
title={t('submenu.user_list')}
|
||||
isActive={isActive('list')}
|
||||
link={Pages.users.list}
|
||||
/>
|
||||
<SubMenuItem
|
||||
title={t('submenu.add_user')}
|
||||
isActive={isActive('create')}
|
||||
link={Pages.users.create}
|
||||
/>
|
||||
<SubMenuItem
|
||||
title={t('submenu.role_list')}
|
||||
isActive={isActive('all')}
|
||||
link={Pages.users.roleList}
|
||||
/>
|
||||
<SubMenuItem
|
||||
title={t('submenu.role_create')}
|
||||
isActive={isActive('roles-add')}
|
||||
link={Pages.users.roleCreate}
|
||||
/>
|
||||
<SubMenuItem
|
||||
title={t('user.add_user_group')}
|
||||
isActive={isActive('group-add')}
|
||||
link={Pages.users.groupAdd}
|
||||
/>
|
||||
<SubMenuItem
|
||||
title={t('user.list_user_group')}
|
||||
isActive={isActive('groups')}
|
||||
link={Pages.users.groupList}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default UsersSubMenu
|
||||
Reference in New Issue
Block a user