Did the same to all of the dashboards

This commit is contained in:
Tiago Ribeiro
2024-09-06 15:35:26 +01:00
parent de35e1a8b7
commit 4530e4079f
12 changed files with 237 additions and 241 deletions

View File

@@ -51,8 +51,7 @@ export default function AdminDashboard({user}: Props) {
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(reload, [page]);
const inactiveCountryManagerFilter = (x: User) =>
x.type === "agent" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate));
const inactiveCountryManagerFilter = (x: User) => x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate);
const UserDisplay = (displayUser: User) => (
<div
@@ -72,17 +71,17 @@ export default function AdminDashboard({user}: Props) {
const StudentsList = () => {
const filter = (x: User) =>
x.type === "student" &&
(!!selectedUser
!!selectedUser
? groups
.filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id))
.flatMap((g) => g.participants)
.includes(x.id)
: true);
: true;
return (
<UserList
user={user}
type="student"
filters={[filter]}
renderHeader={(total) => (
<div className="flex flex-col gap-4">
@@ -101,17 +100,17 @@ export default function AdminDashboard({user}: Props) {
const TeachersList = () => {
const filter = (x: User) =>
x.type === "teacher" &&
(!!selectedUser
!!selectedUser
? groups
.filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id))
.flatMap((g) => g.participants)
.includes(x.id) || false
: true);
: true;
return (
<UserList
user={user}
type="teacher"
filters={[filter]}
renderHeader={(total) => (
<div className="flex flex-col gap-4">
@@ -129,12 +128,10 @@ export default function AdminDashboard({user}: Props) {
};
const AgentsList = () => {
const filter = (x: User) => x.type === "agent";
return (
<UserList
user={user}
filters={[filter]}
type="agent"
renderHeader={(total) => (
<div className="flex flex-col gap-4">
<div
@@ -153,7 +150,7 @@ export default function AdminDashboard({user}: Props) {
const CorporateList = () => (
<UserList
user={user}
filters={[(x) => x.type === "corporate"]}
type="corporate"
renderHeader={(total) => (
<div className="flex flex-col gap-4">
<div
@@ -170,11 +167,12 @@ export default function AdminDashboard({user}: Props) {
const CorporatePaidStatusList = ({paid}: {paid: Boolean}) => {
const list = paid ? done : pending;
const filter = (x: User) => x.type === "corporate" && list.includes(x.id);
const filter = (x: User) => list.includes(x.id);
return (
<UserList
user={user}
type="corporate"
filters={[filter]}
renderHeader={(total) => (
<div className="flex flex-col gap-4">
@@ -197,6 +195,7 @@ export default function AdminDashboard({user}: Props) {
return (
<UserList
user={user}
type="agent"
filters={[inactiveCountryManagerFilter]}
renderHeader={(total) => (
<div className="flex flex-col gap-4">
@@ -214,11 +213,12 @@ export default function AdminDashboard({user}: Props) {
};
const InactiveStudentsList = () => {
const filter = (x: User) => x.type === "student" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate));
const filter = (x: User) => x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate);
return (
<UserList
user={user}
type="student"
filters={[filter]}
renderHeader={(total) => (
<div className="flex flex-col gap-4">
@@ -236,12 +236,13 @@ export default function AdminDashboard({user}: Props) {
};
const InactiveCorporateList = () => {
const filter = (x: User) => x.type === "corporate" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate));
const filter = (x: User) => x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate);
return (
<UserList
user={user}
filters={[filter]}
type="corporate"
renderHeader={(total) => (
<div className="flex flex-col gap-4">
<div

View File

@@ -161,11 +161,13 @@ export default function CorporateDashboard({user, linkedCorporate}: Props) {
const [showModal, setShowModal] = useState(false);
const {data: stats} = useFilterRecordsByUser<Stat[]>();
const {users, reload, isLoading} = useUsers();
const {groups} = useGroups({admin: user.id});
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 appendUserFilters = useFilterStore((state) => state.appendUserFilter);
const router = useRouter();
@@ -173,26 +175,21 @@ export default function CorporateDashboard({user, linkedCorporate}: Props) {
const assignmentsUsers = useMemo(
() =>
users.filter(
(x) =>
(x.type === "student" || x.type === "teacher") &&
(!!selectedUser
[...teachers, ...students].filter((x) =>
!!selectedUser
? groups
.filter((g) => g.admin === selectedUser.id)
.flatMap((g) => g.participants)
.includes(x.id) || false
: groups.flatMap((g) => g.participants).includes(x.id)),
: groups.flatMap((g) => g.participants).includes(x.id),
),
[groups, users, selectedUser],
[groups, teachers, students, selectedUser],
);
useEffect(() => {
setShowModal(!!selectedUser && router.asPath === "/#");
}, [selectedUser, router.asPath]);
const studentFilter = (user: User) => user.type === "student" && groups.flatMap((g) => g.participants).includes(user.id);
const teacherFilter = (user: User) => user.type === "teacher" && groups.flatMap((g) => g.participants).includes(user.id);
const getStatsByStudent = (user: User) => stats.filter((s) => s.user === user.id);
const UserDisplay = (displayUser: User) => (
@@ -228,12 +225,10 @@ export default function CorporateDashboard({user, linkedCorporate}: Props) {
};
const StudentPerformancePage = () => {
const students = users
.filter((x) => x.type === "student" && groups.flatMap((g) => g.participants).includes(x.id))
.map((u) => ({
const performanceStudents = students.map((u) => ({
...u,
group: groups.find((x) => x.participants.includes(u.id))?.name || "N/A",
corporateName: getUserCompanyName(u, users, groups),
corporateName: getUserCompanyName(user, [], groups),
}));
return (
@@ -246,13 +241,13 @@ export default function CorporateDashboard({user, linkedCorporate}: Props) {
<span>Back</span>
</div>
<div
onClick={reload}
onClick={reloadStudents}
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300">
<span>Reload</span>
<BsArrowRepeat className={clsx("text-xl", isLoading && "animate-spin")} />
<BsArrowRepeat className={clsx("text-xl", isStudentsLoading && "animate-spin")} />
</div>
</div>
<StudentPerformanceList items={students} stats={stats} users={users} />
<StudentPerformanceList items={performanceStudents} stats={stats} users={students} />
</>
);
};
@@ -260,7 +255,7 @@ export default function CorporateDashboard({user, linkedCorporate}: Props) {
const averageLevelCalculator = (studentStats: Stat[]) => {
const formattedStats = studentStats
.map((s) => ({
focus: users.find((u) => u.id === s.user)?.focus,
focus: students.find((u) => u.id === s.user)?.focus,
score: s.score,
module: s.module,
}))
@@ -292,16 +287,18 @@ export default function CorporateDashboard({user, linkedCorporate}: Props) {
<section className="grid grid-cols-5 -md:grid-cols-2 gap-4 text-center">
<IconCard
onClick={() => router.push("/#students")}
isLoading={isStudentsLoading}
Icon={BsPersonFill}
label="Students"
value={users.filter(studentFilter).length}
value={students.length}
color="purple"
/>
<IconCard
onClick={() => router.push("/#teachers")}
isLoading={isTeachersLoading}
Icon={BsPencilSquare}
label="Teachers"
value={users.filter(teacherFilter).length}
value={teachers.length}
color="purple"
/>
<IconCard
@@ -312,6 +309,7 @@ export default function CorporateDashboard({user, linkedCorporate}: Props) {
/>
<IconCard
Icon={BsPaperclip}
isLoading={isStudentsLoading}
label="Average Level"
value={averageLevelCalculator(stats.filter((s) => groups.flatMap((g) => g.participants).includes(s.user))).toFixed(1)}
color="purple"
@@ -331,8 +329,9 @@ export default function CorporateDashboard({user, linkedCorporate}: Props) {
/>
<IconCard
Icon={BsPersonFillGear}
isLoading={isStudentsLoading}
label="Student Performance"
value={users.filter(studentFilter).length}
value={students.length}
color="purple"
onClick={() => router.push("/#studentsPerformance")}
/>
@@ -354,8 +353,7 @@ export default function CorporateDashboard({user, linkedCorporate}: Props) {
<div className="bg-white shadow flex flex-col rounded-xl w-full">
<span className="p-4">Latest students</span>
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
{users
.filter(studentFilter)
{students
.sort((a, b) => dateSorter(a, b, "desc", "registrationDate"))
.map((x) => (
<UserDisplay key={x.id} {...x} />
@@ -365,8 +363,7 @@ export default function CorporateDashboard({user, linkedCorporate}: Props) {
<div className="bg-white shadow flex flex-col rounded-xl w-full">
<span className="p-4">Latest teachers</span>
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
{users
.filter(teacherFilter)
{teachers
.sort((a, b) => dateSorter(a, b, "desc", "registrationDate"))
.map((x) => (
<UserDisplay key={x.id} {...x} />
@@ -376,8 +373,7 @@ export default function CorporateDashboard({user, linkedCorporate}: Props) {
<div className="bg-white shadow flex flex-col rounded-xl w-full">
<span className="p-4">Highest level students</span>
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
{users
.filter(studentFilter)
{students
.sort((a, b) => calculateAverageLevel(b.levels) - calculateAverageLevel(a.levels))
.map((x) => (
<UserDisplay key={x.id} {...x} />
@@ -387,8 +383,7 @@ export default function CorporateDashboard({user, linkedCorporate}: Props) {
<div className="bg-white shadow flex flex-col rounded-xl w-full">
<span className="p-4">Highest exam count students</span>
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
{users
.filter(studentFilter)
{students
.sort(
(a, b) =>
Object.keys(groupByExam(getStatsByStudent(b))).length - Object.keys(groupByExam(getStatsByStudent(a))).length,
@@ -412,7 +407,8 @@ export default function CorporateDashboard({user, linkedCorporate}: Props) {
loggedInUser={user}
onClose={(shouldReload) => {
setSelectedUser(undefined);
if (shouldReload) reload();
if (shouldReload && selectedUser!.type === "student") reloadStudents();
if (shouldReload && selectedUser!.type === "teacher") reloadTeachers();
}}
onViewStudents={
selectedUser.type === "corporate" || selectedUser.type === "teacher"
@@ -463,7 +459,7 @@ export default function CorporateDashboard({user, linkedCorporate}: Props) {
{router.asPath === "/#students" && (
<UserList
user={user}
filters={[(x) => x.type === "student"]}
type="student"
renderHeader={(total) => (
<div className="flex flex-col gap-4">
<div
@@ -480,7 +476,7 @@ export default function CorporateDashboard({user, linkedCorporate}: Props) {
{router.asPath === "/#teachers" && (
<UserList
user={user}
filters={[(x) => x.type === "teacher"]}
type="teacher"
renderHeader={(total) => (
<div className="flex flex-col gap-4">
<div

View File

@@ -1,4 +1,4 @@
import React from "react";
import React, {useMemo} from "react";
import useUsers from "@/hooks/useUsers";
import useGroups from "@/hooks/useGroups";
import {User} from "@/interfaces/user";
@@ -61,29 +61,17 @@ const Card = ({user}: {user: User}) => {
};
const CorporateStudentsLevels = () => {
const {users} = useUsers();
const {groups} = useGroups({});
const corporateUsers = users.filter((u) => u.type === "corporate") as User[];
const [corporateId, setCorporateId] = React.useState<string>("");
const corporate = corporateUsers.find((u) => u.id === corporateId) || corporateUsers[0];
const groupsFromCorporate = corporate ? groups.filter((g) => g.admin === corporate.id) : [];
const {users: students} = useUsers({type: "student"});
const {users: corporates} = useUsers({type: "corporate"});
const groupsParticipants = groupsFromCorporate
.flatMap((g) => g.participants)
.reduce((accm: User[], p) => {
const user = users.find((u) => u.id === p) as User;
if (user) {
return [...accm, user];
}
return accm;
}, []);
const corporate = useMemo(() => corporates.find((u) => u.id === corporateId) || corporates[0], [corporates, corporateId]);
return (
<>
<Select
options={corporateUsers.map((x: User) => ({
options={corporates.map((x: User) => ({
value: x.id,
label: `${x.name} - ${x.email}`,
}))}
@@ -98,7 +86,7 @@ const CorporateStudentsLevels = () => {
}),
}}
/>
{groupsParticipants.map((u) => (
{students.map((u) => (
<Card user={u} key={u.id} />
))}
</>

View File

@@ -9,19 +9,11 @@ interface Props {
tooltip?: string;
onClick?: () => void;
isSelected?: boolean;
isLoading?: boolean;
className?: string;
}
export default function IconCard({
Icon,
label,
value,
color,
tooltip,
onClick,
className,
isSelected,
}: Props) {
export default function IconCard({Icon, label, value, color, tooltip, onClick, className, isLoading, isSelected}: Props) {
const colorClasses: {[key in typeof color]: string} = {
purple: "mti-purple-light",
red: "mti-red-light",
@@ -38,13 +30,12 @@ export default function IconCard({
isSelected && `border border-solid border-${colorClasses[color]}`,
className,
)}
data-tip={tooltip}
>
data-tip={tooltip}>
<Icon className={clsx("text-6xl", `text-${colorClasses[color]}`)} />
<span className="flex flex-col gap-1 items-center text-xl">
<span className="text-lg">{label}</span>
<span className={clsx("font-semibold", `text-${colorClasses[color]}`)}>
{value}
<span className={clsx("font-semibold", `text-${colorClasses[color]}`, isLoading && "animate-pulse")}>
{isLoading ? "..." : value}
</span>
</span>
</div>

View File

@@ -296,21 +296,20 @@ const StudentPerformanceList = ({items, stats, users, groups}: {items: StudentPe
};
export default function MasterCorporateDashboard({user}: Props) {
const [page, setPage] = useState("");
const [selectedUser, setSelectedUser] = useState<User>();
const [showModal, setShowModal] = useState(false);
const [corporateAssignments, setCorporateAssignments] = useState<(Assignment & {corporate?: CorporateUser})[]>([]);
const {data: stats} = useFilterRecordsByUser<Stat[]>();
const {users: students, reload: reloadStudents} = useUsers({type: "student"});
const {users: teachers, reload: reloadTeachers} = useUsers({type: "teacher"});
const {users: corporates, reload: reloadCorporates} = useUsers({type: "corporate"});
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 {groups} = useGroups({admin: user.id, userType: user.type});
const {balance} = useUserBalance();
const users = useMemo(() => [...students, ...teachers, ...corporates], [corporates, students, teachers]);
const users = useMemo(() => uniqBy([...students, ...teachers, ...corporates, user], "id"), [corporates, students, teachers, user]);
const {assignments, isLoading: isAssignmentsLoading, reload: reloadAssignments} = useAssignments({corporate: user.id});
@@ -423,8 +422,22 @@ export default function MasterCorporateDashboard({user}: Props) {
const DefaultDashboard = () => (
<>
<section className="flex flex-wrap gap-2 items-center -lg:justify-center lg:justify-between text-center">
<IconCard onClick={() => router.push("/#students")} Icon={BsPersonFill} label="Students" value={students.length} color="purple" />
<IconCard onClick={() => router.push("/#teachers")} Icon={BsPencilSquare} label="Teachers" value={teachers.length} color="purple" />
<IconCard
onClick={() => router.push("/#students")}
Icon={BsPersonFill}
isLoading={isStudentsLoading}
label="Students"
value={students.length}
color="purple"
/>
<IconCard
onClick={() => router.push("/#teachers")}
Icon={BsPencilSquare}
isLoading={isTeachersLoading}
label="Teachers"
value={teachers.length}
color="purple"
/>
<IconCard
Icon={BsClipboard2Data}
label="Exams Performed"
@@ -453,9 +466,17 @@ export default function MasterCorporateDashboard({user}: Props) {
value={user.subscriptionExpirationDate ? moment(user.subscriptionExpirationDate).format("DD/MM/yyyy") : "Unlimited"}
color="rose"
/>
<IconCard Icon={BsBank} label="Corporate" value={corporates.length} color="purple" onClick={() => router.push("/#corporate")} />
<IconCard
Icon={BsBank}
label="Corporate"
value={corporates.length}
isLoading={isCorporatesLoading}
color="purple"
onClick={() => router.push("/#corporate")}
/>
<IconCard
Icon={BsPersonFillGear}
isLoading={isStudentsLoading}
label="Student Performance"
value={students.length}
color="purple"
@@ -598,7 +619,7 @@ export default function MasterCorporateDashboard({user}: Props) {
{router.asPath === "/#students" && (
<UserList
user={user}
filters={[(x) => x.type === "student"]}
type="student"
renderHeader={(total) => (
<div className="flex flex-col gap-4">
<div
@@ -615,7 +636,7 @@ export default function MasterCorporateDashboard({user}: Props) {
{router.asPath === "/#teachers" && (
<UserList
user={user}
filters={[(x) => x.type === "teacher"]}
type="teacher"
renderHeader={(total) => (
<div className="flex flex-col gap-4">
<div
@@ -633,7 +654,7 @@ export default function MasterCorporateDashboard({user}: Props) {
{router.asPath === "/#corporate" && (
<UserList
user={user}
filters={[(x) => x.type === "corporate"]}
type="corporate"
renderHeader={(total) => (
<div className="flex flex-col gap-4">
<div

View File

@@ -24,7 +24,7 @@ import {capitalize} from "lodash";
import moment from "moment";
import Link from "next/link";
import {useRouter} from "next/router";
import {useEffect, useState} from "react";
import {useEffect, useMemo, useState} from "react";
import {BsArrowRepeat, BsBook, BsClipboard, BsFileEarmarkText, BsHeadphones, BsMegaphone, BsPen, BsPencil, BsStar} from "react-icons/bs";
import {toast} from "react-toastify";
import {activeAssignmentFilter} from "@/utils/assignments";
@@ -33,17 +33,20 @@ import useSessions from "@/hooks/useSessions";
interface Props {
user: User;
users: User[];
linkedCorporate?: CorporateUser | MasterCorporateUser;
}
export default function StudentDashboard({user, users, linkedCorporate}: Props) {
export default function StudentDashboard({user, linkedCorporate}: Props) {
const {gradingSystem} = useGradingSystem();
const {sessions} = useSessions(user.id);
const {data: stats} = useFilterRecordsByUser<Stat[]>(user.id, !user?.id);
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 = useMemo(() => [...teachers, ...corporates], [teachers, corporates]);
const router = useRouter();
const setExams = useExamStore((state) => state.setExams);

View File

@@ -63,11 +63,12 @@ export default function TeacherDashboard({user, linkedCorporate}: Props) {
const [showModal, setShowModal] = useState(false);
const {data: stats} = useFilterRecordsByUser<Stat[]>();
const {users, reload} = useUsers();
const {groups} = useGroups({adminAdmins: user.id});
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 appendUserFilters = useFilterStore((state) => state.appendUserFilter);
const router = useRouter();
@@ -75,25 +76,21 @@ export default function TeacherDashboard({user, linkedCorporate}: Props) {
const assignmentsUsers = useMemo(
() =>
users.filter(
(x) =>
x.type === "student" &&
(!!selectedUser
students.filter((x) =>
!!selectedUser
? groups
.filter((g) => g.admin === selectedUser.id)
.flatMap((g) => g.participants)
.includes(x.id)
: groups.flatMap((g) => g.participants).includes(x.id)),
: groups.flatMap((g) => g.participants).includes(x.id),
),
[groups, users, selectedUser],
[groups, students, selectedUser],
);
useEffect(() => {
setShowModal(!!selectedUser && router.asPath === "/#");
}, [selectedUser, router.asPath]);
const studentFilter = (user: User) => user.type === "student";
const getStatsByStudent = (user: User) => stats.filter((s) => s.user === user.id);
const UserDisplay = (displayUser: User) => (
@@ -131,7 +128,7 @@ export default function TeacherDashboard({user, linkedCorporate}: Props) {
const averageLevelCalculator = (studentStats: Stat[]) => {
const formattedStats = studentStats
.map((s) => ({
focus: users.find((u) => u.id === s.user)?.focus,
focus: students.find((u) => u.id === s.user)?.focus,
score: s.score,
module: s.module,
}))
@@ -167,9 +164,10 @@ export default function TeacherDashboard({user, linkedCorporate}: Props) {
)}>
<IconCard
onClick={() => router.push("/#students")}
isLoading={isStudentsLoading}
Icon={BsPersonFill}
label="Students"
value={users.filter(studentFilter).length}
value={students.length}
color="purple"
/>
<IconCard
@@ -181,6 +179,7 @@ export default function TeacherDashboard({user, linkedCorporate}: Props) {
<IconCard
Icon={BsPaperclip}
label="Average Level"
isLoading={isStudentsLoading}
value={averageLevelCalculator(stats.filter((s) => groups.flatMap((g) => g.participants).includes(s.user))).toFixed(1)}
color="purple"
/>
@@ -208,8 +207,7 @@ export default function TeacherDashboard({user, linkedCorporate}: Props) {
<div className="bg-white shadow flex flex-col rounded-xl w-full">
<span className="p-4">Latest students</span>
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
{users
.filter(studentFilter)
{students
.sort((a, b) => dateSorter(a, b, "desc", "registrationDate"))
.map((x) => (
<UserDisplay key={x.id} {...x} />
@@ -219,8 +217,7 @@ export default function TeacherDashboard({user, linkedCorporate}: Props) {
<div className="bg-white shadow flex flex-col rounded-xl w-full">
<span className="p-4">Highest level students</span>
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
{users
.filter(studentFilter)
{students
.sort((a, b) => calculateAverageLevel(b.levels) - calculateAverageLevel(a.levels))
.map((x) => (
<UserDisplay key={x.id} {...x} />
@@ -230,8 +227,7 @@ export default function TeacherDashboard({user, linkedCorporate}: Props) {
<div className="bg-white shadow flex flex-col rounded-xl w-full">
<span className="p-4">Highest exam count students</span>
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
{users
.filter(studentFilter)
{students
.sort(
(a, b) =>
Object.keys(groupByExam(getStatsByStudent(b))).length - Object.keys(groupByExam(getStatsByStudent(a))).length,
@@ -255,7 +251,7 @@ export default function TeacherDashboard({user, linkedCorporate}: Props) {
loggedInUser={user}
onClose={(shouldReload) => {
setSelectedUser(undefined);
if (shouldReload) reload();
if (shouldReload && selectedUser!.type === "student") reloadStudents();
}}
onViewStudents={
selectedUser.type === "corporate" || selectedUser.type === "teacher"
@@ -306,7 +302,7 @@ export default function TeacherDashboard({user, linkedCorporate}: Props) {
{router.asPath === "/#students" && (
<UserList
user={user}
filters={[(x) => x.type === "student"]}
type="student"
renderHeader={(total) => (
<div className="flex flex-col gap-4">
<div

View File

@@ -1,7 +1,11 @@
import {Group, User} from "@/interfaces/user";
import axios from "axios";
import Axios from "axios";
import {setupCache} from "axios-cache-interceptor";
import {useEffect, useState} from "react";
const instance = Axios.create();
const axios = setupCache(instance);
interface Props {
admin?: string;
userType?: string;

View File

@@ -46,10 +46,12 @@ const CompanyNameCell = ({users, user, groups}: {user: User; users: User[]; grou
export default function UserList({
user,
filters = [],
type,
renderHeader,
}: {
user: User;
filters?: ((user: User) => boolean)[];
type?: Type;
renderHeader?: (total: number) => JSX.Element;
}) {
const [showDemographicInformation, setShowDemographicInformation] = useState(false);
@@ -57,7 +59,7 @@ export default function UserList({
const [displayUsers, setDisplayUsers] = useState<User[]>([]);
const [selectedUser, setSelectedUser] = useState<User>();
const {users, reload} = useUsers();
const {users, reload} = useUsers({type});
const {permissions} = usePermissions(user?.id || "");
const {balance} = useUserBalance();
const {groups} = useGroups({

View File

@@ -56,10 +56,9 @@ export const getServerSideProps = withIronSessionSsr(async ({req, res}) => {
}
const linkedCorporate = (await getUserCorporate(user.id)) || null;
const users = await getUsers();
return {
props: {user, envVariables, linkedCorporate, users},
props: {user, envVariables, linkedCorporate},
};
}, sessionOptions);
@@ -67,10 +66,9 @@ interface Props {
user: User;
envVariables: {[key: string]: string};
linkedCorporate?: CorporateUser | MasterCorporateUser;
users: User[];
}
export default function Home({users, linkedCorporate}: Props) {
export default function Home({linkedCorporate}: Props) {
const [showDiagnostics, setShowDiagnostics] = useState(false);
const [showDemographicInput, setShowDemographicInput] = useState(false);
const [selectedScreen, setSelectedScreen] = useState<Type>("admin");
@@ -176,7 +174,7 @@ export default function Home({users, linkedCorporate}: Props) {
<ToastContainer />
{user && (
<Layout user={user}>
{checkAccess(user, ["student"]) && <StudentDashboard users={users} linkedCorporate={linkedCorporate} user={user} />}
{checkAccess(user, ["student"]) && <StudentDashboard linkedCorporate={linkedCorporate} user={user} />}
{checkAccess(user, ["teacher"]) && <TeacherDashboard linkedCorporate={linkedCorporate} user={user} />}
{checkAccess(user, ["corporate"]) && <CorporateDashboard linkedCorporate={linkedCorporate} user={user as CorporateUser} />}
{checkAccess(user, ["mastercorporate"]) && <MasterCorporateDashboard user={user as MasterCorporateUser} />}
@@ -196,7 +194,7 @@ export default function Home({users, linkedCorporate}: Props) {
onChange={(value) => (value ? setSelectedScreen(value.value) : setSelectedScreen("admin"))}
/>
{selectedScreen === "student" && <StudentDashboard users={users} linkedCorporate={linkedCorporate} user={user} />}
{selectedScreen === "student" && <StudentDashboard linkedCorporate={linkedCorporate} user={user} />}
{selectedScreen === "teacher" && <TeacherDashboard linkedCorporate={linkedCorporate} user={user} />}
{selectedScreen === "corporate" && (
<CorporateDashboard linkedCorporate={linkedCorporate} user={user as unknown as CorporateUser} />

View File

@@ -37,11 +37,9 @@ export const getServerSideProps = withIronSessionSsr(({ req, res }) => {
export default function UsersListPage() {
const {user} = useUser();
const { users } = useUsers();
const [filters, clearFilters] = useFilterStore((state) => [
state.userFilters,
state.clearUserFilters,
]);
const [filters, clearFilters] = useFilterStore((state) => [state.userFilters, state.clearUserFilters]);
const router = useRouter();
return (
@@ -69,8 +67,7 @@ export default function UsersListPage() {
clearFilters();
router.back();
}}
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"
>
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300">
<BsArrowLeft className="text-xl" />
<span>Back</span>
</div>

View File

@@ -53,8 +53,15 @@ export async function getSpecificUsers(ids: string[]) {
}
export async function getLinkedUsers(userID?: string, userType?: Type, type?: Type, page?: number, size?: number) {
const q = [
...(!!type ? [where("type", "==", type)] : []),
orderBy(documentId()),
...(page !== undefined && !!size ? [startAt(page * size)] : []),
...(page !== undefined && !!size ? [limit(page + 1 * size)] : []),
];
if (!userID || userType === "admin" || userType === "developer") {
const snapshot = await getDocs(collection(db, "users"));
const snapshot = await getDocs(query(collection(db, "users"), ...q));
const users = snapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
@@ -73,15 +80,7 @@ export async function getLinkedUsers(userID?: string, userType?: Type, type?: Ty
...(userType === "teacher" ? belongingGroups.flatMap((x) => x.participants) : []),
]);
const q = [
where(documentId(), "in", participants),
...(!!type ? [where("type", "==", type)] : []),
orderBy(documentId()),
...(page !== undefined && !!size ? [startAt(page * size)] : []),
...(page !== undefined && !!size ? [limit(page + 1 * size)] : []),
];
const snapshot = await getDocs(query(collection(db, "users"), ...q));
const snapshot = await getDocs(query(collection(db, "users"), ...[where(documentId(), "in", participants), ...q]));
const users = snapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),