Pagination on UserList

This commit is contained in:
Carlos Mesquita
2024-09-09 01:22:13 +01:00
parent 02564c8426
commit 9177a6b2ac
4 changed files with 111 additions and 108 deletions

View File

@@ -9,7 +9,7 @@ export const userHashStudent = {type: "student"} as {type: Type};
export const userHashTeacher = {type: "teacher"} as {type: Type}; export const userHashTeacher = {type: "teacher"} as {type: Type};
export const userHashCorporate = {type: "corporate"} as {type: Type}; export const userHashCorporate = {type: "corporate"} as {type: Type};
export default function useUsers(props?: {type?: string; page?: number; size?: number; orderBy?: string; direction?: "asc" | "desc"}) { export default function useUsers(props?: {type?: string; page?: number; size?: number; orderBy?: string; direction?: "asc" | "desc", searchTerm?: string | undefined}) {
const [users, setUsers] = useState<User[]>([]); const [users, setUsers] = useState<User[]>([]);
const [total, setTotal] = useState(0); const [total, setTotal] = useState(0);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
@@ -35,7 +35,7 @@ export default function useUsers(props?: {type?: string; page?: number; size?: n
.finally(() => setIsLoading(false)); .finally(() => setIsLoading(false));
}; };
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(getData, [props?.page, props?.size, props?.type, props?.orderBy, props?.direction]); useEffect(getData, [props?.page, props?.size, props?.type, props?.orderBy, props?.direction, props?.searchTerm]);
return {users, total, isLoading, isError, reload: getData}; return {users, total, isLoading, isError, reload: getData};
} }

View File

@@ -28,6 +28,7 @@ import {checkAccess} from "@/utils/permissions";
import { PermissionType } from "@/interfaces/permissions"; import { PermissionType } from "@/interfaces/permissions";
import usePermissions from "@/hooks/usePermissions"; import usePermissions from "@/hooks/usePermissions";
import useUserBalance from "@/hooks/useUserBalance"; import useUserBalance from "@/hooks/useUserBalance";
import Input from "@/components/Low/Input";
const columnHelper = createColumnHelper<User>(); const columnHelper = createColumnHelper<User>();
const searchFields = [["name"], ["email"], ["corporateInformation", "companyInformation", "name"]]; const searchFields = [["name"], ["email"], ["corporateInformation", "companyInformation", "name"]];
@@ -59,17 +60,10 @@ export default function UserList({
const [displayUsers, setDisplayUsers] = useState<User[]>([]); const [displayUsers, setDisplayUsers] = useState<User[]>([]);
const [selectedUser, setSelectedUser] = useState<User>(); const [selectedUser, setSelectedUser] = useState<User>();
const [page, setPage] = useState(0); const [page, setPage] = useState(0);
const [searchTerm, setSearchTerm] = useState<string | undefined>(undefined);
const userHash = useMemo( const { users, total, isLoading, reload } = useUsers({type: type, size: 16, page: page, searchTerm: searchTerm});
() => ({
type,
size: 16,
page,
}),
[type, page],
);
const {users, total, isLoading, reload} = useUsers(userHash);
const { permissions } = usePermissions(user?.id || ""); const { permissions } = usePermissions(user?.id || "");
const { balance } = useUserBalance(); const { balance } = useUserBalance();
const { groups } = useGroups({ const { groups } = useGroups({
@@ -135,8 +129,7 @@ export default function UserList({
const toggleDisableAccount = (user: User) => { const toggleDisableAccount = (user: User) => {
if ( if (
!confirm( !confirm(
`Are you sure you want to ${user.status === "disabled" ? "enable" : "disable"} ${ `Are you sure you want to ${user.status === "disabled" ? "enable" : "disable"} ${user.name
user.name
}'s account? This change is usually related to their payment state.`, }'s account? This change is usually related to their payment state.`,
) )
) )
@@ -230,8 +223,7 @@ export default function UserList({
) as any, ) as any,
cell: (info) => cell: (info) =>
info.getValue() info.getValue()
? `${countryCodes.findOne("countryCode" as any, info.getValue())?.flag} ${ ? `${countryCodes.findOne("countryCode" as any, info.getValue())?.flag} ${countries[info.getValue() as unknown as keyof TCountries]?.name
countries[info.getValue() as unknown as keyof TCountries]?.name
} (+${countryCodes.findOne("countryCode" as any, info.getValue())?.countryCallingCode})` } (+${countryCodes.findOne("countryCode" as any, info.getValue())?.countryCallingCode})`
: "N/A", : "N/A",
}), }),
@@ -505,16 +497,14 @@ export default function UserList({
return a.id.localeCompare(b.id); return a.id.localeCompare(b.id);
}; };
const {rows: filteredRows, renderSearch} = useListSearch<User>(searchFields, displayUsers);
const table = useReactTable({ const table = useReactTable({
data: filteredRows, data: displayUsers,
columns: (!showDemographicInformation ? defaultColumns : demographicColumns) as any, columns: (!showDemographicInformation ? defaultColumns : demographicColumns) as any,
getCoreRowModel: getCoreRowModel(), getCoreRowModel: getCoreRowModel(),
}); });
const downloadExcel = () => { const downloadExcel = () => {
const csv = exportListToExcel(filteredRows, users, groups); const csv = exportListToExcel(displayUsers, users, groups);
const element = document.createElement("a"); const element = document.createElement("a");
const file = new Blob([csv], { type: "text/csv" }); const file = new Blob([csv], { type: "text/csv" });
@@ -619,7 +609,7 @@ export default function UserList({
</Modal> </Modal>
<div className="w-full flex flex-col gap-2"> <div className="w-full flex flex-col gap-2">
<div className="w-full flex gap-2 items-end"> <div className="w-full flex gap-2 items-end">
{renderSearch()} <Input label="Search" type="text" name="search" onChange={setSearchTerm} placeholder="Enter search text" value={searchTerm} />
<Button className="w-full max-w-[200px] mb-1" variant="outline" onClick={downloadExcel}> <Button className="w-full max-w-[200px] mb-1" variant="outline" onClick={downloadExcel}>
Download List Download List
</Button> </Button>

View File

@@ -19,7 +19,8 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
page, page,
orderBy, orderBy,
direction = "desc", direction = "desc",
} = req.query as {size?: string; type?: Type; page?: string; orderBy?: string; direction?: "asc" | "desc"}; searchTerm
} = req.query as {size?: string; type?: Type; page?: string; orderBy?: string; direction?: "asc" | "desc"; searchTerm?: string | undefined};
const {users, total} = await getLinkedUsers( const {users, total} = await getLinkedUsers(
req.session.user?.id, req.session.user?.id,
@@ -29,6 +30,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
size !== undefined ? parseInt(size) : undefined, size !== undefined ? parseInt(size) : undefined,
orderBy, orderBy,
direction, direction,
searchTerm
); );
res.status(200).json({users, total}); res.status(200).json({users, total});

View File

@@ -33,10 +33,21 @@ export async function getLinkedUsers(
size?: number, size?: number,
sort?: string, sort?: string,
direction?: "asc" | "desc", direction?: "asc" | "desc",
searchTerm?: string | undefined,
) { ) {
const filters = { const filters: any = {};
...(!!type ? {type} : {}),
}; if (type) {
filters.type = type;
}
if (searchTerm) {
filters.$or = [
{ name: { $regex: searchTerm, $options: 'i' } },
{ email: { $regex: searchTerm, $options: 'i' } },
{ company: { $regex: searchTerm, $options: 'i' } },
];
}
if (!userID || userType === "admin" || userType === "developer") { if (!userID || userType === "admin" || userType === "developer") {
const users = await db const users = await db