Fixed infinite loop on the dashboards
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
import Modal from "@/components/Modal";
|
||||
import useFilterRecordsByUser from "@/hooks/useFilterRecordsByUser";
|
||||
import useUsers from "@/hooks/useUsers";
|
||||
import {CorporateUser, Group, MasterCorporateUser, Stat, User} from "@/interfaces/user";
|
||||
import useUsers, { userHashStudent, userHashTeacher, userHashCorporate} from "@/hooks/useUsers";
|
||||
import {CorporateUser, Group, MasterCorporateUser, Stat, User } from "@/interfaces/user";
|
||||
import UserList from "@/pages/(admin)/Lists/UserList";
|
||||
import {dateSorter} from "@/utils";
|
||||
import moment from "moment";
|
||||
@@ -156,6 +156,7 @@ const StudentPerformanceList = ({items, stats, users}: {items: StudentPerformanc
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default function CorporateDashboard({user, linkedCorporate}: Props) {
|
||||
const [selectedUser, setSelectedUser] = useState<User>();
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
@@ -165,8 +166,8 @@ export default function CorporateDashboard({user, linkedCorporate}: Props) {
|
||||
const {assignments, isLoading: isAssignmentsLoading, reload: reloadAssignments} = useAssignments({corporate: user.id});
|
||||
const {balance} = useUserBalance();
|
||||
|
||||
const {users: students, reload: reloadStudents, isLoading: isStudentsLoading} = useUsers({type: "student"});
|
||||
const {users: teachers, reload: reloadTeachers, isLoading: isTeachersLoading} = useUsers({type: "teacher"});
|
||||
const {users: students, reload: reloadStudents, isLoading: isStudentsLoading} = useUsers(userHashStudent);
|
||||
const {users: teachers, reload: reloadTeachers, isLoading: isTeachersLoading} = useUsers(userHashTeacher);
|
||||
|
||||
const appendUserFilters = useFilterStore((state) => state.appendUserFilter);
|
||||
const router = useRouter();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, {useMemo} from "react";
|
||||
import useUsers from "@/hooks/useUsers";
|
||||
import useUsers, { userHashStudent, userHashTeacher, userHashCorporate } from "@/hooks/useUsers";
|
||||
import useGroups from "@/hooks/useGroups";
|
||||
import {User} from "@/interfaces/user";
|
||||
import Select from "@/components/Low/Select";
|
||||
@@ -63,8 +63,8 @@ const Card = ({user}: {user: User}) => {
|
||||
const CorporateStudentsLevels = () => {
|
||||
const [corporateId, setCorporateId] = React.useState<string>("");
|
||||
|
||||
const {users: students} = useUsers({type: "student"});
|
||||
const {users: corporates} = useUsers({type: "corporate"});
|
||||
const {users: students} = useUsers(userHashStudent);
|
||||
const {users: corporates} = useUsers(userHashCorporate);
|
||||
|
||||
const corporate = useMemo(() => corporates.find((u) => u.id === corporateId) || corporates[0], [corporates, corporateId]);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
import Modal from "@/components/Modal";
|
||||
import useFilterRecordsByUser from "@/hooks/useFilterRecordsByUser";
|
||||
import useUsers from "@/hooks/useUsers";
|
||||
import useUsers, { userHashStudent, userHashTeacher, userHashCorporate } from "@/hooks/useUsers";
|
||||
import {CorporateUser, Group, MasterCorporateUser, Stat, User} from "@/interfaces/user";
|
||||
import UserList from "@/pages/(admin)/Lists/UserList";
|
||||
import {dateSorter} from "@/utils";
|
||||
@@ -302,9 +302,9 @@ export default function MasterCorporateDashboard({user}: Props) {
|
||||
|
||||
const {data: stats} = useFilterRecordsByUser<Stat[]>();
|
||||
|
||||
const {users: students, reload: reloadStudents, isLoading: isStudentsLoading} = useUsers({type: "student"});
|
||||
const {users: teachers, reload: reloadTeachers, isLoading: isTeachersLoading} = useUsers({type: "teacher"});
|
||||
const {users: corporates, reload: reloadCorporates, isLoading: isCorporatesLoading} = useUsers({type: "corporate"});
|
||||
const {users: students, reload: reloadStudents, isLoading: isStudentsLoading} = useUsers(userHashStudent);
|
||||
const {users: teachers, reload: reloadTeachers, isLoading: isTeachersLoading} = useUsers(userHashTeacher);
|
||||
const {users: corporates, reload: reloadCorporates, isLoading: isCorporatesLoading} = useUsers(userHashCorporate);
|
||||
|
||||
const {groups} = useGroups({admin: user.id, userType: user.type});
|
||||
const {balance} = useUserBalance();
|
||||
|
||||
@@ -6,7 +6,7 @@ import useAssignments from "@/hooks/useAssignments";
|
||||
import useGradingSystem from "@/hooks/useGrading";
|
||||
import useInvites from "@/hooks/useInvites";
|
||||
import useFilterRecordsByUser from "@/hooks/useFilterRecordsByUser";
|
||||
import useUsers from "@/hooks/useUsers";
|
||||
import useUsers, { userHashStudent, userHashTeacher, userHashCorporate} from "@/hooks/useUsers";
|
||||
import {Invite} from "@/interfaces/invite";
|
||||
import {Assignment} from "@/interfaces/results";
|
||||
import {CorporateUser, MasterCorporateUser, Stat, User} from "@/interfaces/user";
|
||||
@@ -43,8 +43,8 @@ export default function StudentDashboard({user, linkedCorporate}: Props) {
|
||||
const {assignments, isLoading: isAssignmentsLoading, reload: reloadAssignments} = useAssignments({assignees: user?.id});
|
||||
const {invites, isLoading: isInvitesLoading, reload: reloadInvites} = useInvites({to: user.id});
|
||||
|
||||
const {users: teachers} = useUsers({type: "teacher"});
|
||||
const {users: corporates} = useUsers({type: "corporate"});
|
||||
const {users: teachers} = useUsers(userHashTeacher);
|
||||
const {users: corporates} = useUsers(userHashCorporate);
|
||||
|
||||
const users = useMemo(() => [...teachers, ...corporates], [teachers, corporates]);
|
||||
const router = useRouter();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
import Modal from "@/components/Modal";
|
||||
import useFilterRecordsByUser from "@/hooks/useFilterRecordsByUser";
|
||||
import useUsers from "@/hooks/useUsers";
|
||||
import useUsers, { userHashStudent, userHashTeacher, userHashCorporate } from "@/hooks/useUsers";
|
||||
import {CorporateUser, Group, MasterCorporateUser, Stat, User} from "@/interfaces/user";
|
||||
import UserList from "@/pages/(admin)/Lists/UserList";
|
||||
import {dateSorter} from "@/utils";
|
||||
@@ -67,7 +67,7 @@ export default function TeacherDashboard({user, linkedCorporate}: Props) {
|
||||
const {permissions} = usePermissions(user.id);
|
||||
const {assignments, isLoading: isAssignmentsLoading, reload: reloadAssignments} = useAssignments({assigner: user.id});
|
||||
|
||||
const {users: students, reload: reloadStudents, isLoading: isStudentsLoading} = useUsers({type: "student"});
|
||||
const {users: students, reload: reloadStudents, isLoading: isStudentsLoading} = useUsers(userHashStudent);
|
||||
|
||||
const appendUserFilters = useFilterStore((state) => state.appendUserFilter);
|
||||
const router = useRouter();
|
||||
|
||||
@@ -2,10 +2,13 @@ import {Type, User} from "@/interfaces/user";
|
||||
import Axios from "axios";
|
||||
import {useEffect, useState} from "react";
|
||||
import {setupCache} from "axios-cache-interceptor";
|
||||
|
||||
const instance = Axios.create();
|
||||
const axios = setupCache(instance);
|
||||
|
||||
export const userHashStudent = { type: "student" } as { type: Type };
|
||||
export const userHashTeacher = { type: "teacher" } as { type: Type };
|
||||
export const userHashCorporate = { type: "corporate" } as { type: Type };
|
||||
|
||||
export default function useUsers(props?: {type?: Type; page?: number; size?: number}) {
|
||||
const [users, setUsers] = useState<User[]>([]);
|
||||
const [total, setTotal] = useState(0);
|
||||
|
||||
@@ -164,4 +164,4 @@ export interface Code {
|
||||
}
|
||||
|
||||
export type Type = "student" | "teacher" | "corporate" | "admin" | "developer" | "agent" | "mastercorporate";
|
||||
export const userTypes: Type[] = ["student", "teacher", "corporate", "admin", "developer", "agent", "mastercorporate"];
|
||||
export const userTypes: Type[] = ["student", "teacher", "corporate", "admin", "developer", "agent", "mastercorporate"];
|
||||
@@ -9,7 +9,7 @@ import axios from "axios";
|
||||
import clsx from "clsx";
|
||||
import {capitalize, reverse} from "lodash";
|
||||
import moment from "moment";
|
||||
import {Fragment, useEffect, useState} from "react";
|
||||
import {Fragment, useEffect, useState, useMemo} from "react";
|
||||
import {BsArrowDown, BsArrowDownUp, BsArrowUp, BsCheck, BsCheckCircle, BsEye, BsFillExclamationOctagonFill, BsPerson, BsTrash} from "react-icons/bs";
|
||||
import {toast} from "react-toastify";
|
||||
import {countries, TCountries} from "countries-list";
|
||||
@@ -59,7 +59,12 @@ export default function UserList({
|
||||
const [displayUsers, setDisplayUsers] = useState<User[]>([]);
|
||||
const [selectedUser, setSelectedUser] = useState<User>();
|
||||
|
||||
const {users, page, total, reload, next, previous} = useUsers({type, size: 25});
|
||||
const userHash = useMemo(() => ({
|
||||
type,
|
||||
size: 25,
|
||||
}), [type])
|
||||
|
||||
const {users, page, total, reload, next, previous} = useUsers(userHash);
|
||||
const {permissions} = usePermissions(user?.id || "");
|
||||
const {balance} = useUserBalance();
|
||||
const {groups} = useGroups({
|
||||
|
||||
@@ -1,37 +1,48 @@
|
||||
import {CorporateUser, Group, User, Type} from "@/interfaces/user";
|
||||
import { CorporateUser, Group, User, Type } from "@/interfaces/user";
|
||||
import axios from "axios";
|
||||
|
||||
export const isUserFromCorporate = async (userID: string) => {
|
||||
const groups = (await axios.get<Group[]>(`/api/groups?participant=${userID}`)).data;
|
||||
const users = (await axios.get<User[]>("/api/users/list")).data;
|
||||
const groups = (await axios.get<Group[]>(`/api/groups?participant=${userID}`))
|
||||
.data;
|
||||
const usersData = (await axios.get<{users: User[], total: number}>("/api/users/list")).data;
|
||||
|
||||
const adminTypes = groups.map((g) => users.find((u) => u.id === g.admin)?.type);
|
||||
return adminTypes.includes("corporate");
|
||||
const adminTypes = groups.reduce((accm: Type[], g) => {
|
||||
const user = usersData.users.find((u) => u.id === g.admin);
|
||||
if (user) {
|
||||
return [...accm, user.type];
|
||||
}
|
||||
|
||||
return accm;
|
||||
}, []);
|
||||
return adminTypes.includes("corporate");
|
||||
};
|
||||
|
||||
const getAdminForGroup = async (userID: string, role: Type) => {
|
||||
const groups = (await axios.get<Group[]>(`/api/groups?participant=${userID}`)).data;
|
||||
const groups = (await axios.get<Group[]>(`/api/groups?participant=${userID}`))
|
||||
.data;
|
||||
|
||||
const adminRequests = await Promise.all(
|
||||
groups.map(async (g) => {
|
||||
const userRequest = await axios.get<User>(`/api/users/${g.admin}`);
|
||||
if (userRequest.status === 200) return userRequest.data;
|
||||
return undefined;
|
||||
}),
|
||||
);
|
||||
const adminRequests = await Promise.all(
|
||||
groups.map(async (g) => {
|
||||
const userRequest = await axios.get<User>(`/api/users/${g.admin}`);
|
||||
if (userRequest.status === 200) return userRequest.data;
|
||||
return undefined;
|
||||
})
|
||||
);
|
||||
|
||||
const admins = adminRequests.filter((x) => x?.type === role);
|
||||
return admins.length > 0 ? (admins[0] as CorporateUser) : undefined;
|
||||
const admins = adminRequests.filter((x) => x?.type === role);
|
||||
return admins.length > 0 ? (admins[0] as CorporateUser) : undefined;
|
||||
};
|
||||
|
||||
export const getUserCorporate = async (userID: string): Promise<CorporateUser | undefined> => {
|
||||
const userRequest = await axios.get<User>(`/api/users/${userID}`);
|
||||
if (userRequest.status === 200) {
|
||||
const user = userRequest.data;
|
||||
if (user.type === "corporate") {
|
||||
return getAdminForGroup(userID, "mastercorporate");
|
||||
}
|
||||
}
|
||||
export const getUserCorporate = async (
|
||||
userID: string
|
||||
): Promise<CorporateUser | undefined> => {
|
||||
const userRequest = await axios.get<User>(`/api/users/${userID}`);
|
||||
if (userRequest.status === 200) {
|
||||
const user = userRequest.data;
|
||||
if (user.type === "corporate") {
|
||||
return getAdminForGroup(userID, "mastercorporate");
|
||||
}
|
||||
}
|
||||
|
||||
return getAdminForGroup(userID, "corporate");
|
||||
return getAdminForGroup(userID, "corporate");
|
||||
};
|
||||
|
||||
@@ -86,6 +86,9 @@ export async function getLinkedUsers(userID?: string, userType?: Type, type?: Ty
|
||||
...(userType === "teacher" ? belongingGroups.flatMap((x) => x.participants) : []),
|
||||
]);
|
||||
|
||||
// ⨯ [FirebaseError: Invalid Query. A non-empty array is required for 'in' filters.] {
|
||||
if(participants.length === 0) return {users: [], total: 0};
|
||||
|
||||
const snapshot = await getDocs(query(collection(db, "users"), ...[where(documentId(), "in", participants), ...q]));
|
||||
const users = snapshot.docs.map((doc) => ({
|
||||
id: doc.id,
|
||||
|
||||
Reference in New Issue
Block a user