users
This commit is contained in:
+11
-8
@@ -72,14 +72,17 @@ export const Pages = {
|
|||||||
referralCode: {
|
referralCode: {
|
||||||
list: "/referral-code/list",
|
list: "/referral-code/list",
|
||||||
},
|
},
|
||||||
users: {
|
admin: {
|
||||||
list: "/users/list",
|
list: "/admin/list",
|
||||||
create: "/users/create",
|
create: "/admin/create",
|
||||||
detail: "/users/detail/",
|
detail: "/admin/detail/",
|
||||||
roleList: "/users/roles-all",
|
roleList: "/admin/roles-all",
|
||||||
roleCreate: "/users/roles-add",
|
roleCreate: "/admin/roles-add",
|
||||||
groupAdd: "/users/group-add",
|
groupAdd: "/admin/group-add",
|
||||||
groupList: "/users/groups",
|
groupList: "/admin/groups",
|
||||||
|
},
|
||||||
|
buyUsers: {
|
||||||
|
list: "/buy-users/list",
|
||||||
},
|
},
|
||||||
ads: {
|
ads: {
|
||||||
list: "/ads/list",
|
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 CouponList from '@/pages/Coupon/List'
|
||||||
import CreateCoupon from '@/pages/Coupon/Create'
|
import CreateCoupon from '@/pages/Coupon/Create'
|
||||||
import UpdateCoupon from '@/pages/Coupon/Update'
|
import UpdateCoupon from '@/pages/Coupon/Update'
|
||||||
|
import UsersList from '@/pages/user/List'
|
||||||
|
|
||||||
const MainRouter: FC = () => {
|
const MainRouter: FC = () => {
|
||||||
|
|
||||||
@@ -83,6 +84,8 @@ const MainRouter: FC = () => {
|
|||||||
<Route path={Pages.coupon.list} element={<CouponList />} />
|
<Route path={Pages.coupon.list} element={<CouponList />} />
|
||||||
<Route path={Pages.coupon.create} element={<CreateCoupon />} />
|
<Route path={Pages.coupon.create} element={<CreateCoupon />} />
|
||||||
<Route path={`${Pages.coupon.detail}:id`} element={<UpdateCoupon />} />
|
<Route path={`${Pages.coupon.detail}:id`} element={<UpdateCoupon />} />
|
||||||
|
|
||||||
|
<Route path={Pages.buyUsers.list} element={<UsersList />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+18
-18
@@ -46,7 +46,7 @@ const SideBar: FC = () => {
|
|||||||
|
|
||||||
if (split[1] === 'dashboard' || split[1] === 'products' || split[1] === 'orders' ||
|
if (split[1] === 'dashboard' || split[1] === 'products' || split[1] === 'orders' ||
|
||||||
split[1] === 'blog' || split[1] === 'shipment' || split[1] === 'financial' ||
|
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] === 'tickets' || split[1] === 'reports' || split[1] === 'chat' ||
|
||||||
split[1] === 'contact' || split[1] === 'settings' || split[1] === 'pages' ||
|
split[1] === 'contact' || split[1] === 'settings' || split[1] === 'pages' ||
|
||||||
split[1] === 'jobs' || split[1] === 'category') {
|
split[1] === 'jobs' || split[1] === 'category') {
|
||||||
@@ -164,20 +164,20 @@ const SideBar: FC = () => {
|
|||||||
|
|
||||||
{/* خریداران */}
|
{/* خریداران */}
|
||||||
<SideBarItem
|
<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="خریداران"
|
title="خریداران"
|
||||||
isActive={isActive('buyers')}
|
isActive={isActive('buy-users')}
|
||||||
link="/buyers"
|
link={Pages.buyUsers.list}
|
||||||
activeName='buyers'
|
activeName='buy-users'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* کاربران */}
|
{/* کاربران */}
|
||||||
<SideBarItem
|
<SideBarItem
|
||||||
icon={<Profile variant={isActive('users') ? 'Bold' : 'Outline'} color={isActive('users') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
|
icon={<Profile variant={isActive('admin') ? 'Bold' : 'Outline'} color={isActive('admin') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
|
||||||
title="کاربران"
|
title="ادمین ها"
|
||||||
isActive={isActive('users')}
|
isActive={isActive('admin')}
|
||||||
link="/users"
|
link="/admin"
|
||||||
activeName='users'
|
activeName='admin'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* تیکت ها */}
|
{/* تیکت ها */}
|
||||||
@@ -271,8 +271,8 @@ const SideBar: FC = () => {
|
|||||||
: subMenuName === 'shipment' ? <ShippingSubMenu />
|
: subMenuName === 'shipment' ? <ShippingSubMenu />
|
||||||
: subMenuName === 'financial' ? <FinancialSubMenu />
|
: subMenuName === 'financial' ? <FinancialSubMenu />
|
||||||
: subMenuName === 'sellers' ? <SellersSubMenu />
|
: subMenuName === 'sellers' ? <SellersSubMenu />
|
||||||
: subMenuName === 'buyers' ? <BuyersSubMenu />
|
: subMenuName === 'buy-users' ? <BuyersSubMenu />
|
||||||
: subMenuName === 'users' ? <UsersSubMenu />
|
: subMenuName === 'admin' ? <UsersSubMenu />
|
||||||
: subMenuName === 'tickets' ? <TicketsSubMenu />
|
: subMenuName === 'tickets' ? <TicketsSubMenu />
|
||||||
: subMenuName === 'reports' ? <ReportsSubMenu />
|
: subMenuName === 'reports' ? <ReportsSubMenu />
|
||||||
: subMenuName === 'chat' ? <ChatSubMenu />
|
: subMenuName === 'chat' ? <ChatSubMenu />
|
||||||
@@ -563,7 +563,7 @@ const BuyersSubMenu: FC = () => {
|
|||||||
<SubMenuItem
|
<SubMenuItem
|
||||||
title={'لیست خریداران'}
|
title={'لیست خریداران'}
|
||||||
isActive={isActive('list')}
|
isActive={isActive('list')}
|
||||||
link="/buyers/list"
|
link={Pages.buyUsers.list}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -584,25 +584,25 @@ const UsersSubMenu: FC = () => {
|
|||||||
variant='Bold'
|
variant='Bold'
|
||||||
/>
|
/>
|
||||||
<div className='text-xs'>
|
<div className='text-xs'>
|
||||||
کاربران
|
ادمین ها
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='flex flex-col mt-10 gap-4'>
|
<div className='flex flex-col mt-10 gap-4'>
|
||||||
<SubMenuItem
|
<SubMenuItem
|
||||||
title={'لیست کاربران'}
|
title={'لیست ادمین ها'}
|
||||||
isActive={isActive('list')}
|
isActive={isActive('list')}
|
||||||
link="/users/list"
|
link={Pages.admin.list}
|
||||||
/>
|
/>
|
||||||
<SubMenuItem
|
<SubMenuItem
|
||||||
title={'تعریف نقش'}
|
title={'تعریف نقش'}
|
||||||
isActive={isActive('roles')}
|
isActive={isActive('roles')}
|
||||||
link="/users/roles"
|
link={Pages.admin.roleList}
|
||||||
/>
|
/>
|
||||||
<SubMenuItem
|
<SubMenuItem
|
||||||
title={'تعریف گروه کاربری'}
|
title={'تعریف گروه کاربری'}
|
||||||
isActive={isActive('groups')}
|
isActive={isActive('groups')}
|
||||||
link="/users/groups"
|
link={Pages.admin.groupList}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</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