From 13ec627b310f31eb6a90db93db85cf69d514daae Mon Sep 17 00:00:00 2001 From: IlyaDoronin Date: Thu, 7 Mar 2024 15:44:44 +0300 Subject: [PATCH] feat: users pagination --- src/api/user.ts | 70 ------------ src/api/user/requests.ts | 89 +++++++++++++++ src/api/user/swr.ts | 104 ++++++++++++++++++ .../dashboard/Content/ServiceUsersDG.tsx | 17 +++ src/pages/dashboard/Content/Users.tsx | 98 +++++++++++++---- src/pages/dashboard/ModalUser/UserTab.tsx | 4 +- 6 files changed, 287 insertions(+), 95 deletions(-) delete mode 100644 src/api/user.ts create mode 100644 src/api/user/requests.ts create mode 100644 src/api/user/swr.ts diff --git a/src/api/user.ts b/src/api/user.ts deleted file mode 100644 index aa6be3b..0000000 --- a/src/api/user.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { makeRequest } from "@frontend/kitui"; - -import { parseAxiosError } from "@root/utils/parse-error"; - -import type { UserType } from "@root/api/roles"; - -type RegisteredUsersResponse = { - tatalPages: number; - users: UserType[]; -}; - -const baseUrl = process.env.REACT_APP_DOMAIN + "/user"; - -export const getUserInfo = async ( - id: string -): Promise<[UserType | null, string?]> => { - try { - const userInfoResponse = await makeRequest({ - url: `${baseUrl}/${id}`, - method: "GET", - useToken: true, - }); - - return [userInfoResponse]; - } catch (nativeError) { - const [error] = parseAxiosError(nativeError); - - return [null, `Ошибка получения информации о пользователе. ${error}`]; - } -}; - -export const getRegisteredUsers = async (): Promise< - [RegisteredUsersResponse | null, string?] -> => { - try { - const registeredUsersResponse = await makeRequest< - never, - RegisteredUsersResponse - >({ - method: "get", - url: baseUrl + "/", - }); - - return [registeredUsersResponse]; - } catch (nativeError) { - const [error] = parseAxiosError(nativeError); - - return [null, `Ошибка при получении пользователей. ${error}`]; - } -}; - -export const getManagersList = async (): Promise< - [RegisteredUsersResponse | null, string?] -> => { - try { - const managersListResponse = await makeRequest< - never, - RegisteredUsersResponse - >({ - method: "get", - url: baseUrl + "/", - }); - - return [managersListResponse]; - } catch (nativeError) { - const [error] = parseAxiosError(nativeError); - - return [null, `Ошибка при получении менеджеров. ${error}`]; - } -}; diff --git a/src/api/user/requests.ts b/src/api/user/requests.ts new file mode 100644 index 0000000..859165f --- /dev/null +++ b/src/api/user/requests.ts @@ -0,0 +1,89 @@ +import { makeRequest } from "@frontend/kitui"; + +import { parseAxiosError } from "@root/utils/parse-error"; + +import type { UserType } from "@root/api/roles"; + +export type RegisteredUsersResponse = { + totalPages: number; + users: UserType[]; +}; + +const baseUrl = process.env.REACT_APP_DOMAIN + "/user"; + +const getUserInfo = async (id: string): Promise<[UserType | null, string?]> => { + try { + const userInfoResponse = await makeRequest({ + url: `${baseUrl}/${id}`, + method: "GET", + useToken: true, + }); + + return [userInfoResponse]; + } catch (nativeError) { + const [error] = parseAxiosError(nativeError); + + return [null, `Ошибка получения информации о пользователе. ${error}`]; + } +}; + +const getUserList = async ( + page = 1, + limit = 10 +): Promise<[RegisteredUsersResponse | null, string?]> => { + try { + const userResponse = await makeRequest({ + method: "get", + url: baseUrl + `/?page=${page}&limit=${limit}`, + }); + + return [userResponse]; + } catch (nativeError) { + const [error] = parseAxiosError(nativeError); + + return [null, `Ошибка при получении пользователей. ${error}`]; + } +}; + +const getManagerList = async ( + page = 1, + limit = 10 +): Promise<[RegisteredUsersResponse | null, string?]> => { + try { + const managerResponse = await makeRequest({ + method: "get", + url: baseUrl + `/?page=${page}&limit=${limit}`, + }); + + return [managerResponse]; + } catch (nativeError) { + const [error] = parseAxiosError(nativeError); + + return [null, `Ошибка при получении менеджеров. ${error}`]; + } +}; + +const getAdminList = async ( + page = 1, + limit = 10 +): Promise<[RegisteredUsersResponse | null, string?]> => { + try { + const adminResponse = await makeRequest({ + method: "get", + url: baseUrl + `/?page=${page}&limit=${limit}`, + }); + + return [adminResponse]; + } catch (nativeError) { + const [error] = parseAxiosError(nativeError); + + return [null, `Ошибка при получении админов. ${error}`]; + } +}; + +export const userApi = { + getUserInfo, + getUserList, + getManagerList, + getAdminList, +}; diff --git a/src/api/user/swr.ts b/src/api/user/swr.ts new file mode 100644 index 0000000..23dc84d --- /dev/null +++ b/src/api/user/swr.ts @@ -0,0 +1,104 @@ +import { useRef } from "react"; +import useSwr from "swr"; +import { enqueueSnackbar } from "notistack"; + +import { userApi } from "./requests"; + +export function useAdmins(page: number, pageSize: number) { + const adminPagesRef = useRef(0); + + const swrResponse = useSwr( + ["admin", page, pageSize], + async ([_, page, pageSize]) => { + const [adminResponse, error] = await userApi.getManagerList( + page, + pageSize + ); + + if (error) { + throw new Error(error); + } + + adminPagesRef.current = adminResponse?.totalPages || 1; + return adminResponse; + }, + { + onError(err) { + console.log("Error fetching users", err); + enqueueSnackbar(err.message, { variant: "error" }); + }, + focusThrottleInterval: 60e3, + keepPreviousData: true, + } + ); + + return { + ...swrResponse, + adminPages: adminPagesRef.current, + }; +} + +export function useManagers(page: number, pageSize: number) { + const managerPagesRef = useRef(0); + + const swrResponse = useSwr( + ["manager", page, pageSize], + async ([_, page, pageSize]) => { + const [managerResponse, error] = await userApi.getManagerList( + page, + pageSize + ); + + if (error) { + throw new Error(error); + } + + managerPagesRef.current = managerResponse?.totalPages || 1; + return managerResponse; + }, + { + onError(err) { + console.log("Error fetching users", err); + enqueueSnackbar(err.message, { variant: "error" }); + }, + focusThrottleInterval: 60e3, + keepPreviousData: true, + } + ); + + return { + ...swrResponse, + managerPages: managerPagesRef.current, + }; +} + +export function useUsers(page: number, pageSize: number) { + const userPagesRef = useRef(0); + + const swrResponse = useSwr( + ["users", page, pageSize], + async ([_, page, pageSize]) => { + const [userResponse, error] = await userApi.getUserList(page, pageSize); + + if (error) { + throw new Error(error); + } + + userPagesRef.current = userResponse?.totalPages || 1; + return userResponse; + }, + { + onError(err) { + console.log("Error fetching users", err); + enqueueSnackbar(err.message, { variant: "error" }); + }, + focusThrottleInterval: 60e3, + keepPreviousData: true, + } + ); + + return { + ...swrResponse, + userPagesCount: userPagesRef.current, + }; +} diff --git a/src/pages/dashboard/Content/ServiceUsersDG.tsx b/src/pages/dashboard/Content/ServiceUsersDG.tsx index 9f0c9cd..2aca18d 100644 --- a/src/pages/dashboard/Content/ServiceUsersDG.tsx +++ b/src/pages/dashboard/Content/ServiceUsersDG.tsx @@ -42,11 +42,21 @@ const columns: GridColDef[] = [ interface Props { handleSelectionChange: (selectionModel: GridSelectionModel) => void; users: UserType[]; + page: number; + setPage: (page: number) => void; + pageSize: number; + pagesCount: number; + onPageSizeChange?: (count: number) => void; } export default function ServiceUsersDG({ handleSelectionChange, users = [], + page, + setPage, + pageSize = 10, + pagesCount = 1, + onPageSizeChange, }: Props) { const navigate = useNavigate(); @@ -60,6 +70,13 @@ export default function ServiceUsersDG({ rows={users} columns={columns} components={{ Toolbar: GridToolbar }} + rowCount={pageSize * pagesCount} + rowsPerPageOptions={[10, 25, 50, 100]} + paginationMode="server" + page={page} + pageSize={pageSize} + onPageChange={setPage} + onPageSizeChange={onPageSizeChange} onSelectionModelChange={handleSelectionChange} onCellClick={({ row }, event) => { event.stopPropagation(); diff --git a/src/pages/dashboard/Content/Users.tsx b/src/pages/dashboard/Content/Users.tsx index 4eece62..7c9f20c 100644 --- a/src/pages/dashboard/Content/Users.tsx +++ b/src/pages/dashboard/Content/Users.tsx @@ -23,14 +23,24 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import ConditionalRender from "@root/pages/Setting/ConditionalRender"; import ModalUser from "@root/pages/dashboard/ModalUser"; import ServiceUsersDG from "./ServiceUsersDG"; -import { getRegisteredUsers, getManagersList } from "@root/api/user"; +import { useUsers, useManagers, useAdmins } from "@root/api/user/swr"; import { getRoles } from "@root/api/privilegies"; import { getRoles_mock, TMockData } from "../../../api/roles"; import theme from "../../../theme"; -import type { UserType } from "../../../api/roles"; +type Pages = { + adminPage: number; + managerPage: number; + userPage: number; +}; + +type PagesSize = { + adminPageSize: number; + managerPageSize: number; + userPageSize: number; +}; const Users: React.FC = () => { const radioboxes = ["admin", "manager", "user"]; @@ -39,11 +49,11 @@ const Users: React.FC = () => { const navigate = useNavigate(); - const [data, setData] = React.useState([]); + const [mockData, setMockData] = React.useState([]); const handleChangeData = () => { getRoles_mock().then((mockdata) => { - setData(mockdata); + setMockData(mockdata); setAccordionText(mockdata[0].desc || ""); }); }; @@ -53,7 +63,7 @@ const Users: React.FC = () => { const handleChange = (value: string) => { setSelectedValue(value); - setAccordionText(data.find(({ name }) => name === value)?.desc || ""); + setAccordionText(mockData.find(({ name }) => name === value)?.desc || ""); if (selectedValue === "manager") { } @@ -64,12 +74,33 @@ const Users: React.FC = () => { }; const [roles, setRoles] = React.useState([]); - const [users, setUsers] = React.useState([]); - const [manager, setManager] = React.useState([]); + + const [page, setPage] = useState({ + adminPage: 0, + managerPage: 0, + userPage: 0, + }); + const [pageSize, setPageSize] = useState({ + adminPageSize: 10, + managerPageSize: 10, + userPageSize: 10, + }); const [openUserModal, setOpenUserModal] = useState(false); const [activeUserId, setActiveUserId] = useState(""); const { userId } = useParams(); + const { data: adminData, adminPages } = useAdmins( + page.adminPage + 1, + pageSize.adminPageSize + ); + const { data: managerData, managerPages } = useManagers( + page.managerPage + 1, + pageSize.managerPageSize + ); + const { data: userData, userPagesCount } = useUsers( + page.userPage + 1, + pageSize.userPageSize + ); useEffect(() => { handleChangeData(); @@ -88,18 +119,6 @@ const Users: React.FC = () => { }, [userId]); useEffect(() => { - getManagersList().then(([managersListResponse]) => { - if (managersListResponse) { - setManager(managersListResponse.users); - } - }); - - getRegisteredUsers().then(([registeredUsersResponse]) => { - if (registeredUsersResponse) { - setUsers(registeredUsersResponse.users); - } - }); - getRoles().then(([rolesResponse]) => { if (rolesResponse) { setRoles(rolesResponse); @@ -210,8 +229,8 @@ const Users: React.FC = () => { - {data.length ? ( - data.map(function (item, index) { + {mockData.length ? ( + mockData.map(function (item, index) { return ( { + setPage((pages) => ({ ...pages, adminPage })) + } + pagesCount={adminPages} + pageSize={pageSize.adminPageSize} + handleSelectionChange={setSelectedTariffs} + onPageSizeChange={(adminPageSize) => + setPageSize((pageSize) => ({ ...pageSize, adminPageSize })) + } + /> + } childrenManager={ + setPage((pages) => ({ ...pages, managerPage })) + } + pagesCount={managerPages} + pageSize={pageSize.managerPageSize} handleSelectionChange={setSelectedTariffs} + onPageSizeChange={(managerPageSize) => + setPageSize((pageSize) => ({ ...pageSize, managerPageSize })) + } /> } childrenUser={ + setPage((pages) => ({ ...pages, userPage })) + } + pagesCount={userPagesCount} + pageSize={pageSize.userPageSize} handleSelectionChange={setSelectedTariffs} + onPageSizeChange={(userPageSize) => + setPageSize((pageSize) => ({ ...pageSize, userPageSize })) + } /> } /> diff --git a/src/pages/dashboard/ModalUser/UserTab.tsx b/src/pages/dashboard/ModalUser/UserTab.tsx index ad03896..4fc1b22 100644 --- a/src/pages/dashboard/ModalUser/UserTab.tsx +++ b/src/pages/dashboard/ModalUser/UserTab.tsx @@ -1,7 +1,7 @@ import { useState, useEffect } from "react"; import { Box, Typography, useTheme, useMediaQuery } from "@mui/material"; -import { getUserInfo } from "@root/api/user"; +import { userApi } from "@root/api/user/requests"; import { getAccountInfo } from "@root/api/account"; import type { UserType } from "@root/api/roles"; @@ -19,7 +19,7 @@ export const UserTab = ({ userId }: UserTabProps) => { useEffect(() => { if (userId) { - getUserInfo(userId).then(([userInfo]) => setUser(userInfo)); + userApi.getUserInfo(userId).then(([userInfo]) => setUser(userInfo)); getAccountInfo(userId).then(([accountsInfo]) => setAccount(accountsInfo)); } }, []);