ENCOA-270, ENCOA-265, ENCOA-262, ENCOA-258
This commit is contained in:
@@ -171,7 +171,8 @@ export default function Sidebar({
|
|||||||
badge={totalAssignedTickets}
|
badge={totalAssignedTickets}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{(entitiesAllowGeneration.length > 0 || isAdmin) && (
|
{checkAccess(user, ["admin", "developer", "teacher", 'corporate', 'mastercorporate'])
|
||||||
|
&& (entitiesAllowGeneration.length > 0 || isAdmin) && (
|
||||||
<Nav
|
<Nav
|
||||||
disabled={disableNavigation}
|
disabled={disableNavigation}
|
||||||
Icon={BsCloudFill}
|
Icon={BsCloudFill}
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ export interface GroupWithUsers extends Omit<Group, "participants" | "admin"> {
|
|||||||
export interface Code {
|
export interface Code {
|
||||||
id: string;
|
id: string;
|
||||||
code: string;
|
code: string;
|
||||||
|
entity: string
|
||||||
creator: string;
|
creator: string;
|
||||||
expiryDate: Date;
|
expiryDate: Date;
|
||||||
type: Type;
|
type: Type;
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export default function Lists({ user, entities = [], permissions }: Props) {
|
|||||||
Exam List
|
Exam List
|
||||||
</Tab>
|
</Tab>
|
||||||
)}
|
)}
|
||||||
{checkAccess(user, ["developer", "admin", "corporate"]) && entitiesViewCodes.length > 0 && (
|
{checkAccess(user, ["developer", "admin", "corporate", "mastercorporate"]) && entitiesViewCodes.length > 0 && (
|
||||||
<Tab
|
<Tab
|
||||||
className={({ selected }) =>
|
className={({ selected }) =>
|
||||||
clsx(
|
clsx(
|
||||||
|
|||||||
@@ -15,9 +15,11 @@ import { ToastContainer } from "react-toastify";
|
|||||||
import useDiscounts from "@/hooks/useDiscounts";
|
import useDiscounts from "@/hooks/useDiscounts";
|
||||||
import PaymobPayment from "@/components/PaymobPayment";
|
import PaymobPayment from "@/components/PaymobPayment";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
import { EntityWithRoles } from "@/interfaces/entity";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: User;
|
user: User;
|
||||||
|
entities: EntityWithRoles[]
|
||||||
hasExpired?: boolean;
|
hasExpired?: boolean;
|
||||||
reload: () => void;
|
reload: () => void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import {
|
|||||||
BsPersonFillGear,
|
BsPersonFillGear,
|
||||||
} from "react-icons/bs";
|
} from "react-icons/bs";
|
||||||
import { ToastContainer } from "react-toastify";
|
import { ToastContainer } from "react-toastify";
|
||||||
|
import { useAllowedEntities } from "@/hooks/useEntityPermissions";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: User;
|
user: User;
|
||||||
@@ -67,6 +68,8 @@ export default function Dashboard({ user, users, entities, assignments, stats, g
|
|||||||
const students = useMemo(() => users.filter((u) => u.type === "student"), [users]);
|
const students = useMemo(() => users.filter((u) => u.type === "student"), [users]);
|
||||||
const teachers = useMemo(() => users.filter((u) => u.type === "teacher"), [users]);
|
const teachers = useMemo(() => users.filter((u) => u.type === "teacher"), [users]);
|
||||||
|
|
||||||
|
const allowedEntityStatistics = useAllowedEntities(user, entities, 'view_entity_statistics')
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const averageLevelCalculator = (studentStats: Stat[]) => {
|
const averageLevelCalculator = (studentStats: Stat[]) => {
|
||||||
@@ -94,16 +97,6 @@ export default function Dashboard({ user, users, entities, assignments, stats, g
|
|||||||
return calculateAverageLevel(levels);
|
return calculateAverageLevel(levels);
|
||||||
};
|
};
|
||||||
|
|
||||||
const UserDisplay = (displayUser: User) => (
|
|
||||||
<div className="flex w-full p-4 gap-4 items-center hover:bg-mti-purple-ultralight cursor-pointer transition ease-in-out duration-300">
|
|
||||||
<img src={displayUser.profilePicture} alt={displayUser.name} className="rounded-full w-10 h-10" />
|
|
||||||
<div className="flex flex-col gap-1 items-start">
|
|
||||||
<span>{displayUser.name}</span>
|
|
||||||
<span className="text-sm opacity-75">{displayUser.email}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
@@ -152,7 +145,14 @@ export default function Dashboard({ user, users, entities, assignments, stats, g
|
|||||||
color="purple"
|
color="purple"
|
||||||
/>
|
/>
|
||||||
<IconCard Icon={BsClipboard2Data} label="Exams Performed" value={uniqBy(stats, "exam").length} color="purple" />
|
<IconCard Icon={BsClipboard2Data} label="Exams Performed" value={uniqBy(stats, "exam").length} color="purple" />
|
||||||
<IconCard Icon={BsPaperclip} label="Average Level" value={averageLevelCalculator(stats).toFixed(1)} color="purple" />
|
{allowedEntityStatistics.length > 0 && (
|
||||||
|
<IconCard Icon={BsPersonFillGear}
|
||||||
|
onClick={() => router.push("/statistical")}
|
||||||
|
label="Entity Statistics"
|
||||||
|
value={allowedEntityStatistics.length}
|
||||||
|
color="purple"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<IconCard Icon={BsPersonFillGear}
|
<IconCard Icon={BsPersonFillGear}
|
||||||
onClick={() => router.push("/users/performance")}
|
onClick={() => router.push("/users/performance")}
|
||||||
label="Student Performance"
|
label="Student Performance"
|
||||||
|
|||||||
@@ -21,11 +21,12 @@ import { uniqBy } from "lodash";
|
|||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { BsClipboard2Data, BsEnvelopePaper, BsPaperclip, BsPeople, BsPersonFill } from "react-icons/bs";
|
import { BsClipboard2Data, BsEnvelopePaper, BsPaperclip, BsPeople, BsPersonFill, BsPersonFillGear } from "react-icons/bs";
|
||||||
import { ToastContainer } from "react-toastify";
|
import { ToastContainer } from "react-toastify";
|
||||||
import { requestUser } from "@/utils/api";
|
import { requestUser } from "@/utils/api";
|
||||||
import { useAllowedEntities } from "@/hooks/useEntityPermissions";
|
import { useAllowedEntities } from "@/hooks/useEntityPermissions";
|
||||||
import { filterAllowedUsers } from "@/utils/users.be";
|
import { filterAllowedUsers } from "@/utils/users.be";
|
||||||
|
import { isAdmin } from "@/utils/users";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: User;
|
user: User;
|
||||||
@@ -44,7 +45,7 @@ export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
|
|||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
|
||||||
const entityIDS = mapBy(user.entities, "id") || [];
|
const entityIDS = mapBy(user.entities, "id") || [];
|
||||||
const entities = await getEntitiesWithRoles(entityIDS);
|
const entities = await getEntitiesWithRoles(isAdmin(user) ? undefined : entityIDS);
|
||||||
const users = await filterAllowedUsers(user, entities)
|
const users = await filterAllowedUsers(user, entities)
|
||||||
|
|
||||||
const assignments = await getEntitiesAssignments(entityIDS);
|
const assignments = await getEntitiesAssignments(entityIDS);
|
||||||
@@ -58,6 +59,8 @@ export default function Dashboard({ user, users, entities, assignments, stats, g
|
|||||||
const students = useMemo(() => users.filter((u) => u.type === "student"), [users]);
|
const students = useMemo(() => users.filter((u) => u.type === "student"), [users]);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const allowedEntityStatistics = useAllowedEntities(user, entities, 'view_entity_statistics')
|
||||||
|
|
||||||
const averageLevelCalculator = (studentStats: Stat[]) => {
|
const averageLevelCalculator = (studentStats: Stat[]) => {
|
||||||
const formattedStats = studentStats
|
const formattedStats = studentStats
|
||||||
.map((s) => ({
|
.map((s) => ({
|
||||||
@@ -83,16 +86,6 @@ export default function Dashboard({ user, users, entities, assignments, stats, g
|
|||||||
return calculateAverageLevel(levels);
|
return calculateAverageLevel(levels);
|
||||||
};
|
};
|
||||||
|
|
||||||
const UserDisplay = (displayUser: User) => (
|
|
||||||
<div className="flex w-full p-4 gap-4 items-center hover:bg-mti-purple-ultralight cursor-pointer transition ease-in-out duration-300">
|
|
||||||
<img src={displayUser.profilePicture} alt={displayUser.name} className="rounded-full w-10 h-10" />
|
|
||||||
<div className="flex flex-col gap-1 items-start">
|
|
||||||
<span>{displayUser.name}</span>
|
|
||||||
<span className="text-sm opacity-75">{displayUser.email}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
@@ -128,7 +121,14 @@ export default function Dashboard({ user, users, entities, assignments, stats, g
|
|||||||
color="purple"
|
color="purple"
|
||||||
/>
|
/>
|
||||||
<IconCard Icon={BsClipboard2Data} label="Exams Performed" value={uniqBy(stats, "exam").length} color="purple" />
|
<IconCard Icon={BsClipboard2Data} label="Exams Performed" value={uniqBy(stats, "exam").length} color="purple" />
|
||||||
<IconCard Icon={BsPaperclip} label="Average Level" value={averageLevelCalculator(stats).toFixed(1)} color="purple" />
|
{allowedEntityStatistics.length > 0 && (
|
||||||
|
<IconCard Icon={BsPersonFillGear}
|
||||||
|
onClick={() => router.push("/statistical")}
|
||||||
|
label="Entity Statistics"
|
||||||
|
value={allowedEntityStatistics.length}
|
||||||
|
color="purple"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<IconCard
|
<IconCard
|
||||||
Icon={BsEnvelopePaper}
|
Icon={BsEnvelopePaper}
|
||||||
onClick={() => router.push("/assignments")}
|
onClick={() => router.push("/assignments")}
|
||||||
|
|||||||
@@ -92,7 +92,8 @@ const ENTITY_MANAGEMENT: PermissionLayout[] = [
|
|||||||
{ label: "Edit Role Permissions", key: "edit_role_permissions" },
|
{ label: "Edit Role Permissions", key: "edit_role_permissions" },
|
||||||
{ label: "Assign Role to User", key: "assign_to_role" },
|
{ label: "Assign Role to User", key: "assign_to_role" },
|
||||||
{ label: "Delete Entity Role", key: "delete_entity_role" },
|
{ label: "Delete Entity Role", key: "delete_entity_role" },
|
||||||
{ label: "Download Statistics Report", key: "download_statistics_report" }
|
{ label: "Download Statistics Report", key: "download_statistics_report" },
|
||||||
|
{ label: "Edit Grading System", key: "edit_grading_system" }
|
||||||
]
|
]
|
||||||
|
|
||||||
const ASSIGNMENT_MANAGEMENT: PermissionLayout[] = [
|
const ASSIGNMENT_MANAGEMENT: PermissionLayout[] = [
|
||||||
|
|||||||
@@ -6,19 +6,30 @@ import useUser from "@/hooks/useUser";
|
|||||||
import PaymentDue from "./(status)/PaymentDue";
|
import PaymentDue from "./(status)/PaymentDue";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { requestUser } from "@/utils/api";
|
import { requestUser } from "@/utils/api";
|
||||||
import { redirect } from "@/utils";
|
import { mapBy, redirect, serialize } from "@/utils";
|
||||||
|
import { getEntities } from "@/utils/entities.be";
|
||||||
|
import { isAdmin } from "@/utils/users";
|
||||||
|
import { EntityWithRoles } from "@/interfaces/entity";
|
||||||
|
import { User } from "@/interfaces/user";
|
||||||
|
|
||||||
export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
|
export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
|
||||||
const user = await requestUser(req, res)
|
const user = await requestUser(req, res)
|
||||||
if (!user) return redirect("/login")
|
if (!user) return redirect("/login")
|
||||||
|
|
||||||
|
const entityIDs = mapBy(user.entities, 'id')
|
||||||
|
const entities = await getEntities(isAdmin(user) ? undefined : entityIDs)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {user},
|
props: serialize({ user, entities }),
|
||||||
};
|
};
|
||||||
}, sessionOptions);
|
}, sessionOptions);
|
||||||
|
|
||||||
export default function Home() {
|
interface Props {
|
||||||
const {user} = useUser({redirectTo: "/login"});
|
user: User,
|
||||||
|
entities: EntityWithRoles[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Home({ user, entities }: Props) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -32,7 +43,7 @@ export default function Home() {
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
</Head>
|
</Head>
|
||||||
{user && <PaymentDue user={user} reload={router.reload} />}
|
<PaymentDue entities={entities} user={user} reload={router.reload} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ export default function Admin({ user, entities, permissions, allUsers, entitiesG
|
|||||||
const entitiesAllowCreateUsers = useAllowedEntities(user, entities, 'create_user_batch')
|
const entitiesAllowCreateUsers = useAllowedEntities(user, entities, 'create_user_batch')
|
||||||
const entitiesAllowCreateCode = useAllowedEntities(user, entities, 'create_code')
|
const entitiesAllowCreateCode = useAllowedEntities(user, entities, 'create_code')
|
||||||
const entitiesAllowCreateCodes = useAllowedEntities(user, entities, 'create_code_batch')
|
const entitiesAllowCreateCodes = useAllowedEntities(user, entities, 'create_code_batch')
|
||||||
|
const entitiesAllowEditGrading = useAllowedEntities(user, entities, 'edit_grading_system')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -111,7 +112,7 @@ export default function Admin({ user, entities, permissions, allUsers, entitiesG
|
|||||||
<CorporateGradingSystem
|
<CorporateGradingSystem
|
||||||
user={user}
|
user={user}
|
||||||
entitiesGrading={entitiesGrading}
|
entitiesGrading={entitiesGrading}
|
||||||
entities={entities}
|
entities={entitiesAllowEditGrading}
|
||||||
mutate={() => router.replace(router.asPath)}
|
mutate={() => router.replace(router.asPath)}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
@@ -159,6 +160,7 @@ export default function Admin({ user, entities, permissions, allUsers, entitiesG
|
|||||||
color="purple"
|
color="purple"
|
||||||
className="w-full h-full col-span-2"
|
className="w-full h-full col-span-2"
|
||||||
onClick={() => setModalOpen("gradingSystem")}
|
onClick={() => setModalOpen("gradingSystem")}
|
||||||
|
disabled={entitiesAllowEditGrading.length === 0}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ export type RolePermission =
|
|||||||
"view_code_list" |
|
"view_code_list" |
|
||||||
"delete_code" |
|
"delete_code" |
|
||||||
"view_statistics" |
|
"view_statistics" |
|
||||||
"download_statistics_report"
|
"download_statistics_report" |
|
||||||
|
"edit_grading_system"
|
||||||
|
|
||||||
export const DEFAULT_PERMISSIONS: RolePermission[] = [
|
export const DEFAULT_PERMISSIONS: RolePermission[] = [
|
||||||
"view_students",
|
"view_students",
|
||||||
@@ -128,5 +129,6 @@ export const ADMIN_PERMISSIONS: RolePermission[] = [
|
|||||||
"view_code_list",
|
"view_code_list",
|
||||||
"delete_code",
|
"delete_code",
|
||||||
"view_statistics",
|
"view_statistics",
|
||||||
"download_statistics_report"
|
"download_statistics_report",
|
||||||
|
"edit_grading_system"
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user