/* eslint-disable @next/next/no-img-element */ import Modal from "@/components/Modal"; import useStats from "@/hooks/useStats"; import useUsers 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"; import {useEffect, useState} from "react"; import { BsArrowLeft, BsClipboard2Data, BsClock, BsPaperclip, BsPersonFill, BsPencilSquare, BsPersonCheck, BsPeople, BsBank, BsEnvelopePaper, BsArrowRepeat, BsPlus, BsPersonFillGear, BsFilter, BsDatabase, } from "react-icons/bs"; import UserCard from "@/components/UserCard"; import useGroups from "@/hooks/useGroups"; import {averageLevelCalculator, calculateAverageLevel, calculateBandScore} from "@/utils/score"; import {MODULE_ARRAY} from "@/utils/moduleUtils"; import {Module} from "@/interfaces"; import {groupByExam} from "@/utils/stats"; import IconCard from "./IconCard"; import GroupList from "@/pages/(admin)/Lists/GroupList"; import useFilterStore from "@/stores/listFilterStore"; import {useRouter} from "next/router"; import useCodes from "@/hooks/useCodes"; import useAssignments from "@/hooks/useAssignments"; import {Assignment} from "@/interfaces/results"; import AssignmentView from "./AssignmentView"; import AssignmentCreator from "./AssignmentCreator"; import clsx from "clsx"; import AssignmentCard from "./AssignmentCard"; import {createColumn, createColumnHelper} from "@tanstack/react-table"; import List from "@/components/List"; import {getUserCorporate} from "@/utils/groups"; import {getCorporateUser, getUserCompanyName} from "@/resources/user"; import Checkbox from "@/components/Low/Checkbox"; import {groupBy, uniq, uniqBy} from "lodash"; import Select from "@/components/Low/Select"; import {Menu, MenuButton, MenuItem, MenuItems} from "@headlessui/react"; import {Popover, PopoverContent, PopoverTrigger} from "@/components/ui/popover"; import MasterStatistical from "./MasterStatistical"; interface Props { user: MasterCorporateUser; } const activeFilter = (a: Assignment) => moment(a.endDate).isAfter(moment()) && moment(a.startDate).isBefore(moment()) && a.assignees.length > a.results.length; const pastFilter = (a: Assignment) => (moment(a.endDate).isBefore(moment()) || a.assignees.length === a.results.length) && !a.archived; const archivedFilter = (a: Assignment) => a.archived; const futureFilter = (a: Assignment) => moment(a.startDate).isAfter(moment()); type StudentPerformanceItem = User & {corporate?: CorporateUser; group?: Group}; const StudentPerformanceList = ({items, stats, users, groups}: {items: StudentPerformanceItem[]; stats: Stat[]; users: User[]; groups: Group[]}) => { const [isShowingAmount, setIsShowingAmount] = useState(false); const [availableCorporates] = useState( uniqBy( items.map((x) => x.corporate), "id", ), ); const [availableGroups] = useState( uniqBy( items.map((x) => x.group), "id", ), ); const [selectedCorporate, setSelectedCorporate] = useState(null); const [selectedGroup, setSelectedGroup] = useState(null); const columnHelper = createColumnHelper(); const columns = [ columnHelper.accessor("name", { header: "Student Name", cell: (info) => info.getValue(), }), columnHelper.accessor("email", { header: "E-mail", cell: (info) => info.getValue(), }), columnHelper.accessor("demographicInformation.passport_id", { header: "ID", cell: (info) => info.getValue() || "N/A", }), columnHelper.accessor("group", { header: "Group", cell: (info) => info.getValue()?.name || "N/A", }), columnHelper.accessor("corporate", { header: "Corporate", cell: (info) => (!!info.getValue() ? getUserCompanyName(info.getValue() as User, users, groups) : "N/A"), }), columnHelper.accessor("levels.reading", { header: "Reading", cell: (info) => !isShowingAmount ? calculateBandScore( stats .filter((x) => x.module === "reading" && x.user === info.row.original.id) .reduce((acc, curr) => acc + curr.score.correct, 0), stats .filter((x) => x.module === "reading" && x.user === info.row.original.id) .reduce((acc, curr) => acc + curr.score.total, 0), "level", info.row.original.focus || "academic", ) || 0 : `${Object.keys(groupByExam(stats.filter((x) => x.module === "reading" && x.user === info.row.original.id))).length} exams`, }), columnHelper.accessor("levels.listening", { header: "Listening", cell: (info) => !isShowingAmount ? calculateBandScore( stats .filter((x) => x.module === "listening" && x.user === info.row.original.id) .reduce((acc, curr) => acc + curr.score.correct, 0), stats .filter((x) => x.module === "listening" && x.user === info.row.original.id) .reduce((acc, curr) => acc + curr.score.total, 0), "level", info.row.original.focus || "academic", ) || 0 : `${Object.keys(groupByExam(stats.filter((x) => x.module === "listening" && x.user === info.row.original.id))).length} exams`, }), columnHelper.accessor("levels.writing", { header: "Writing", cell: (info) => !isShowingAmount ? calculateBandScore( stats .filter((x) => x.module === "writing" && x.user === info.row.original.id) .reduce((acc, curr) => acc + curr.score.correct, 0), stats .filter((x) => x.module === "writing" && x.user === info.row.original.id) .reduce((acc, curr) => acc + curr.score.total, 0), "level", info.row.original.focus || "academic", ) || 0 : `${Object.keys(groupByExam(stats.filter((x) => x.module === "writing" && x.user === info.row.original.id))).length} exams`, }), columnHelper.accessor("levels.speaking", { header: "Speaking", cell: (info) => !isShowingAmount ? calculateBandScore( stats .filter((x) => x.module === "speaking" && x.user === info.row.original.id) .reduce((acc, curr) => acc + curr.score.correct, 0), stats .filter((x) => x.module === "speaking" && x.user === info.row.original.id) .reduce((acc, curr) => acc + curr.score.total, 0), "level", info.row.original.focus || "academic", ) || 0 : `${Object.keys(groupByExam(stats.filter((x) => x.module === "speaking" && x.user === info.row.original.id))).length} exams`, }), columnHelper.accessor("levels.level", { header: "Level", cell: (info) => !isShowingAmount ? calculateBandScore( stats .filter((x) => x.module === "level" && x.user === info.row.original.id) .reduce((acc, curr) => acc + curr.score.correct, 0), stats .filter((x) => x.module === "level" && x.user === info.row.original.id) .reduce((acc, curr) => acc + curr.score.total, 0), "level", info.row.original.focus || "academic", ) || 0 : `${Object.keys(groupByExam(stats.filter((x) => x.module === "level" && x.user === info.row.original.id))).length} exams`, }), columnHelper.accessor("levels", { id: "overall_level", header: "Overall", cell: (info) => !isShowingAmount ? averageLevelCalculator( users, stats.filter((x) => x.user === info.row.original.id), ).toFixed(1) : `${Object.keys(groupByExam(stats.filter((x) => x.user === info.row.original.id))).length} exams`, }), ]; const filterUsers = (data: StudentPerformanceItem[]) => { console.log(data, selectedCorporate); const filterByCorporate = (item: StudentPerformanceItem) => item.corporate?.id === selectedCorporate?.id; const filterByGroup = (item: StudentPerformanceItem) => item.group?.id === selectedGroup?.id; const filters: ((item: StudentPerformanceItem) => boolean)[] = []; if (selectedCorporate !== null) filters.push(filterByCorporate); if (selectedGroup !== null) filters.push(filterByGroup); return filters.reduce((d, f) => d.filter(f), data); }; return (
Show Utilization
Filters ({ value: x?.id || "N/A", label: x?.name || "N/A", }))} isClearable value={ selectedGroup === null ? null : { value: selectedGroup?.id || "N/A", label: selectedGroup?.name || "N/A", } } placeholder="Select a Group..." onChange={(value) => !value ? setSelectedGroup(null) : setSelectedGroup(value.value === "N/A" ? undefined : availableGroups.find((x) => x?.id === value.value)) } />
data={filterUsers( items.sort( (a, b) => averageLevelCalculator( users, stats.filter((x) => x.user === b.id), ) - averageLevelCalculator( users, stats.filter((x) => x.user === a.id), ), ), )} columns={columns} />
); }; export default function MasterCorporateDashboard({user}: Props) { const [page, setPage] = useState(""); const [selectedUser, setSelectedUser] = useState(); const [showModal, setShowModal] = useState(false); const [selectedAssignment, setSelectedAssignment] = useState(); const [isCreatingAssignment, setIsCreatingAssignment] = useState(false); const [corporateAssignments, setCorporateAssignments] = useState<(Assignment & {corporate?: CorporateUser})[]>([]); const {stats} = useStats(); const {users, reload} = useUsers(); const {codes} = useCodes(user.id); const {groups} = useGroups({admin: user.id, userType: user.type}); const masterCorporateUserGroups = [...new Set(groups.filter((u) => u.admin === user.id).flatMap((g) => g.participants))]; const corporateUserGroups = [...new Set(groups.flatMap((g) => g.participants))]; const {assignments, isLoading: isAssignmentsLoading, reload: reloadAssignments} = useAssignments({corporate: user.id}); const appendUserFilters = useFilterStore((state) => state.appendUserFilter); const router = useRouter(); useEffect(() => { setShowModal(!!selectedUser && page === ""); }, [selectedUser, page]); useEffect(() => { setCorporateAssignments( assignments.filter(activeFilter).map((a) => ({ ...a, corporate: !!users.find((x) => x.id === a.assigner) ? getCorporateUser(users.find((x) => x.id === a.assigner)!, users, groups) : undefined, })), ); }, [assignments, groups, users]); const studentFilter = (user: User) => user.type === "student" && corporateUserGroups.includes(user.id); const teacherFilter = (user: User) => user.type === "teacher" && corporateUserGroups.includes(user.id); const getStatsByStudent = (user: User) => stats.filter((s) => s.user === user.id); const UserDisplay = (displayUser: User) => (
setSelectedUser(displayUser)} className="flex w-full p-4 gap-4 items-center hover:bg-mti-purple-ultralight cursor-pointer transition ease-in-out duration-300"> {displayUser.name}
{displayUser.name} {displayUser.email}
); const StudentsList = () => { const filter = (x: User) => x.type === "student" && (!!selectedUser ? corporateUserGroups.includes(x.id) || false : corporateUserGroups.includes(x.id)); return ( (
setPage("")} className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> Back

Students ({total})

)} /> ); }; const TeachersList = () => { const filter = (x: User) => x.type === "teacher" && (!!selectedUser ? corporateUserGroups.includes(x.id) || false : corporateUserGroups.includes(x.id)); return ( (
setPage("")} className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> Back

Teachers ({total})

)} /> ); }; const corporateUserFilter = (x: User) => x.type === "corporate" && (!!selectedUser ? masterCorporateUserGroups.includes(x.id) || false : masterCorporateUserGroups.includes(x.id)); const CorporateList = () => { return ( (
setPage("")} className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> Back

Corporates ({total})

)} /> ); }; const GroupsList = () => { return ( <>
setPage("")} className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> Back

Groups ({groups.length})

); }; // const AssignmentsPage = () => { // const activeFilter = (a: Assignment) => // moment(a.endDate).isAfter(moment()) && // moment(a.startDate).isBefore(moment()) && // a.assignees.length > a.results.length; // const pastFilter = (a: Assignment) => // (moment(a.endDate).isBefore(moment()) || // a.assignees.length === a.results.length) && // !a.archived; // const archivedFilter = (a: Assignment) => a.archived; // const futureFilter = (a: Assignment) => // moment(a.startDate).isAfter(moment()); const StudentPerformancePage = () => { const students = users .filter((x) => x.type === "student" && groups.flatMap((g) => g.participants).includes(x.id)) .map((u) => ({ ...u, group: groups.find((x) => x.participants.includes(u.id)), corporate: getCorporateUser(u, users, groups), })); return ( <>
setPage("")} className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> Back
Reload
); }; const AssignmentsPage = () => { return ( <> { setSelectedAssignment(undefined); setIsCreatingAssignment(false); reloadAssignments(); }} assignment={selectedAssignment} /> x.admin === user.id || x.participants.includes(user.id))} users={users.filter( (x) => x.type === "student" && (!!selectedUser ? groups .filter((g) => g.admin === selectedUser.id) .flatMap((g) => g.participants) .includes(x.id) || false : groups.flatMap((g) => g.participants).includes(x.id)), )} assigner={user.id} isCreating={isCreatingAssignment} cancelCreation={() => { setIsCreatingAssignment(false); setSelectedAssignment(undefined); reloadAssignments(); }} />
setPage("")} className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> Back
Reload
Active Assignments Status
Total: {assignments.filter(activeFilter).reduce((acc, curr) => acc + curr.results.length, 0)}/ {assignments.filter(activeFilter).reduce((acc, curr) => curr.exams.length + acc, 0)} {Object.keys(groupBy(corporateAssignments, (x) => x.corporate?.id)).map((x) => (
{getUserCompanyName(users.find((u) => u.id === x)!, users, groups)}: {groupBy(corporateAssignments, (x) => x.corporate?.id)[x].reduce((acc, curr) => curr.results.length + acc, 0)}/ {groupBy(corporateAssignments, (x) => x.corporate?.id)[x].reduce((acc, curr) => curr.exams.length + acc, 0)}
))}

Active Assignments ({assignments.filter(activeFilter).length})

{assignments.filter(activeFilter).map((a) => ( setSelectedAssignment(a)} key={a.id} /> ))}

Planned Assignments ({assignments.filter(futureFilter).length})

setIsCreatingAssignment(true)} className="w-[250px] h-[200px] flex flex-col gap-2 items-center justify-center bg-white hover:bg-mti-purple-ultralight text-mti-purple-light hover:text-mti-purple-dark border border-mti-gray-platinum hover:drop-shadow p-4 cursor-pointer rounded-xl transition ease-in-out duration-300"> New Assignment
{assignments.filter(futureFilter).map((a) => ( { setSelectedAssignment(a); setIsCreatingAssignment(true); }} key={a.id} /> ))}

Past Assignments ({assignments.filter(pastFilter).length})

{assignments.filter(pastFilter).map((a) => ( setSelectedAssignment(a)} key={a.id} allowDownload reload={reloadAssignments} allowArchive allowExcelDownload /> ))}

Archived Assignments ({assignments.filter(archivedFilter).length})

{assignments.filter(archivedFilter).map((a) => ( setSelectedAssignment(a)} key={a.id} allowDownload reload={reloadAssignments} allowUnarchive allowExcelDownload /> ))}
); }; const MasterStatisticalPage = () => { return ( <>
setPage("")} className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> Back

Master Statistical

{ const user = users.find((u) => u.id === id) as CorporateUser; if (user) return [...accm, user]; return accm; }, [])} /> ); }; const DefaultDashboard = () => ( <>
setPage("students")} Icon={BsPersonFill} label="Students" value={users.filter(studentFilter).length} color="purple" /> setPage("teachers")} Icon={BsPencilSquare} label="Teachers" value={users.filter(teacherFilter).length} color="purple" /> groups.flatMap((g) => g.participants).includes(s.user)).length} color="purple" /> groups.flatMap((g) => g.participants).includes(s.user)), ).toFixed(1)} color="purple" /> setPage("groups")} Icon={BsPeople} label="Groups" value={groups.length} color="purple" /> setPage("corporate")} /> setPage("studentsPerformance")} /> setPage("statistical")} />
Latest students
{users .filter(studentFilter) .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) .map((x) => ( ))}
Latest teachers
{users .filter(teacherFilter) .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) .map((x) => ( ))}
Highest level students
{users .filter(studentFilter) .sort((a, b) => calculateAverageLevel(b.levels) - calculateAverageLevel(a.levels)) .map((x) => ( ))}
Highest exam count students
{users .filter(studentFilter) .sort( (a, b) => Object.keys(groupByExam(getStatsByStudent(b))).length - Object.keys(groupByExam(getStatsByStudent(a))).length, ) .map((x) => ( ))}
); return ( <> setSelectedUser(undefined)}> <> {selectedUser && (
{ setSelectedUser(undefined); if (shouldReload) reload(); }} onViewStudents={ selectedUser.type === "corporate" || selectedUser.type === "teacher" ? () => { appendUserFilters({ id: "view-students", filter: (x: User) => x.type === "student", }); appendUserFilters({ id: "belongs-to-admin", filter: (x: User) => groups .filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id)) .flatMap((g) => g.participants) .includes(x.id), }); router.push("/list/users"); } : undefined } onViewTeachers={ selectedUser.type === "corporate" || selectedUser.type === "student" ? () => { appendUserFilters({ id: "view-teachers", filter: (x: User) => x.type === "teacher", }); appendUserFilters({ id: "belongs-to-admin", filter: (x: User) => groups .filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id)) .flatMap((g) => g.participants) .includes(x.id), }); router.push("/list/users"); } : undefined } user={selectedUser} />
)}
{page === "students" && } {page === "teachers" && } {page === "groups" && } {page === "corporate" && } {page === "assignments" && } {page === "studentsPerformance" && } {page === "statistical" && } {page === "" && } ); }