Merge branch 'feature/ExamGenRework' of https://bitbucket.org/ecropdev/ielts-ui into feature/ExamGenRework
This commit is contained in:
@@ -27,7 +27,7 @@ import useTicketsListener from "@/hooks/useTicketsListener";
|
|||||||
import { checkAccess, getTypesOfUser } from "@/utils/permissions";
|
import { checkAccess, getTypesOfUser } from "@/utils/permissions";
|
||||||
import usePermissions from "@/hooks/usePermissions";
|
import usePermissions from "@/hooks/usePermissions";
|
||||||
import { EntityWithRoles } from "@/interfaces/entity";
|
import { EntityWithRoles } from "@/interfaces/entity";
|
||||||
import { useAllowedEntitiesSomePermissions } from "@/hooks/useEntityPermissions";
|
import { useAllowedEntities, useAllowedEntitiesSomePermissions } from "@/hooks/useEntityPermissions";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -95,6 +95,8 @@ export default function Sidebar({
|
|||||||
const { totalAssignedTickets } = useTicketsListener(user.id);
|
const { totalAssignedTickets } = useTicketsListener(user.id);
|
||||||
const { permissions } = usePermissions(user.id);
|
const { permissions } = usePermissions(user.id);
|
||||||
|
|
||||||
|
const entitiesAllowStatistics = useAllowedEntities(user, entities, "view_statistics")
|
||||||
|
|
||||||
const entitiesAllowGeneration = useAllowedEntitiesSomePermissions(user, entities, [
|
const entitiesAllowGeneration = useAllowedEntitiesSomePermissions(user, entities, [
|
||||||
"generate_reading", "generate_listening", "generate_writing", "generate_speaking", "generate_level"
|
"generate_reading", "generate_listening", "generate_writing", "generate_speaking", "generate_level"
|
||||||
])
|
])
|
||||||
@@ -119,7 +121,7 @@ export default function Sidebar({
|
|||||||
{checkAccess(user, ["student", "teacher", "developer"], permissions, "viewExams") && (
|
{checkAccess(user, ["student", "teacher", "developer"], permissions, "viewExams") && (
|
||||||
<Nav disabled={disableNavigation} Icon={BsFileEarmarkText} label="Practice" path={path} keyPath="/exam" isMinimized={isMinimized} />
|
<Nav disabled={disableNavigation} Icon={BsFileEarmarkText} label="Practice" path={path} keyPath="/exam" isMinimized={isMinimized} />
|
||||||
)}
|
)}
|
||||||
{checkAccess(user, getTypesOfUser(["agent"]), permissions, "viewStats") && (
|
{checkAccess(user, getTypesOfUser(["agent"])) && entitiesAllowStatistics.length > 0 && (
|
||||||
<Nav disabled={disableNavigation} Icon={BsGraphUp} label="Stats" path={path} keyPath="/stats" isMinimized={isMinimized} />
|
<Nav disabled={disableNavigation} Icon={BsGraphUp} label="Stats" path={path} keyPath="/stats" isMinimized={isMinimized} />
|
||||||
)}
|
)}
|
||||||
{checkAccess(user, ["developer", "admin", "mastercorporate", "corporate", "teacher", "student"], permissions) && (
|
{checkAccess(user, ["developer", "admin", "mastercorporate", "corporate", "teacher", "student"], permissions) && (
|
||||||
|
|||||||
@@ -4,22 +4,22 @@ import Select from "@/components/Low/Select";
|
|||||||
import useCodes from "@/hooks/useCodes";
|
import useCodes from "@/hooks/useCodes";
|
||||||
import useUser from "@/hooks/useUser";
|
import useUser from "@/hooks/useUser";
|
||||||
import useUsers from "@/hooks/useUsers";
|
import useUsers from "@/hooks/useUsers";
|
||||||
import {Code, User} from "@/interfaces/user";
|
import { Code, User } from "@/interfaces/user";
|
||||||
import {USER_TYPE_LABELS} from "@/resources/user";
|
import { USER_TYPE_LABELS } from "@/resources/user";
|
||||||
import {createColumnHelper, flexRender, getCoreRowModel, useReactTable} from "@tanstack/react-table";
|
import { createColumnHelper, flexRender, getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import {useEffect, useState, useMemo} from "react";
|
import { useEffect, useState, useMemo } from "react";
|
||||||
import {BsTrash} from "react-icons/bs";
|
import { BsTrash } from "react-icons/bs";
|
||||||
import {toast} from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import ReactDatePicker from "react-datepicker";
|
import ReactDatePicker from "react-datepicker";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import {checkAccess} from "@/utils/permissions";
|
import { checkAccess } from "@/utils/permissions";
|
||||||
import usePermissions from "@/hooks/usePermissions";
|
import usePermissions from "@/hooks/usePermissions";
|
||||||
|
|
||||||
const columnHelper = createColumnHelper<Code>();
|
const columnHelper = createColumnHelper<Code>();
|
||||||
|
|
||||||
const CreatorCell = ({id, users}: {id: string; users: User[]}) => {
|
const CreatorCell = ({ id, users }: { id: string; users: User[] }) => {
|
||||||
const [creatorUser, setCreatorUser] = useState<User>();
|
const [creatorUser, setCreatorUser] = useState<User>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -34,18 +34,16 @@ const CreatorCell = ({id, users}: {id: string; users: User[]}) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function CodeList({user}: {user: User}) {
|
export default function CodeList({ user, canDeleteCodes }: { user: User, canDeleteCodes?: boolean }) {
|
||||||
const [selectedCodes, setSelectedCodes] = useState<string[]>([]);
|
const [selectedCodes, setSelectedCodes] = useState<string[]>([]);
|
||||||
|
|
||||||
const [filteredCorporate, setFilteredCorporate] = useState<User | undefined>(user?.type === "corporate" ? user : undefined);
|
const [filteredCorporate, setFilteredCorporate] = useState<User | undefined>(user?.type === "corporate" ? user : undefined);
|
||||||
const [filterAvailability, setFilterAvailability] = useState<"in-use" | "unused">();
|
const [filterAvailability, setFilterAvailability] = useState<"in-use" | "unused">();
|
||||||
|
|
||||||
const {permissions} = usePermissions(user?.id || "");
|
const { permissions } = usePermissions(user?.id || "");
|
||||||
|
|
||||||
// const [filteredCodes, setFilteredCodes] = useState<Code[]>([]);
|
const { users } = useUsers();
|
||||||
|
const { codes, reload } = useCodes(user?.type === "corporate" ? user?.id : undefined);
|
||||||
const {users} = useUsers();
|
|
||||||
const {codes, reload} = useCodes(user?.type === "corporate" ? user?.id : undefined);
|
|
||||||
|
|
||||||
const [startDate, setStartDate] = useState<Date | null>(moment("01/01/2023").toDate());
|
const [startDate, setStartDate] = useState<Date | null>(moment("01/01/2023").toDate());
|
||||||
const [endDate, setEndDate] = useState<Date | null>(moment().endOf("day").toDate());
|
const [endDate, setEndDate] = useState<Date | null>(moment().endOf("day").toDate());
|
||||||
@@ -80,6 +78,7 @@ export default function CodeList({user}: {user: User}) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const deleteCodes = async (codes: string[]) => {
|
const deleteCodes = async (codes: string[]) => {
|
||||||
|
if (!canDeleteCodes) return
|
||||||
if (!confirm(`Are you sure you want to delete these ${codes.length} code(s)?`)) return;
|
if (!confirm(`Are you sure you want to delete these ${codes.length} code(s)?`)) return;
|
||||||
|
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
@@ -108,6 +107,7 @@ export default function CodeList({user}: {user: User}) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const deleteCode = async (code: Code) => {
|
const deleteCode = async (code: Code) => {
|
||||||
|
if (!canDeleteCodes) return
|
||||||
if (!confirm(`Are you sure you want to delete this "${code.code}" code?`)) return;
|
if (!confirm(`Are you sure you want to delete this "${code.code}" code?`)) return;
|
||||||
|
|
||||||
axios
|
axios
|
||||||
@@ -129,8 +129,6 @@ export default function CodeList({user}: {user: User}) {
|
|||||||
.finally(reload);
|
.finally(reload);
|
||||||
};
|
};
|
||||||
|
|
||||||
const allowedToDelete = checkAccess(user, ["developer", "admin", "corporate", "mastercorporate"], permissions, "deleteCodes");
|
|
||||||
|
|
||||||
const defaultColumns = [
|
const defaultColumns = [
|
||||||
columnHelper.accessor("code", {
|
columnHelper.accessor("code", {
|
||||||
id: "codeCheckbox",
|
id: "codeCheckbox",
|
||||||
@@ -183,10 +181,10 @@ export default function CodeList({user}: {user: User}) {
|
|||||||
{
|
{
|
||||||
header: "",
|
header: "",
|
||||||
id: "actions",
|
id: "actions",
|
||||||
cell: ({row}: {row: {original: Code}}) => {
|
cell: ({ row }: { row: { original: Code } }) => {
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
{allowedToDelete && !row.original.userId && (
|
{canDeleteCodes && !row.original.userId && (
|
||||||
<div data-tip="Delete" className="cursor-pointer tooltip" onClick={() => deleteCode(row.original)}>
|
<div data-tip="Delete" className="cursor-pointer tooltip" onClick={() => deleteCode(row.original)}>
|
||||||
<BsTrash className="hover:text-mti-purple-light transition ease-in-out duration-300" />
|
<BsTrash className="hover:text-mti-purple-light transition ease-in-out duration-300" />
|
||||||
</div>
|
</div>
|
||||||
@@ -215,21 +213,19 @@ export default function CodeList({user}: {user: User}) {
|
|||||||
value={
|
value={
|
||||||
filteredCorporate
|
filteredCorporate
|
||||||
? {
|
? {
|
||||||
label: `${
|
label: `${filteredCorporate?.type === "corporate"
|
||||||
filteredCorporate?.type === "corporate"
|
? filteredCorporate.corporateInformation?.companyInformation?.name || filteredCorporate.name
|
||||||
? filteredCorporate.corporateInformation?.companyInformation?.name || filteredCorporate.name
|
: filteredCorporate.name
|
||||||
: filteredCorporate.name
|
|
||||||
} (${USER_TYPE_LABELS[filteredCorporate?.type]})`,
|
} (${USER_TYPE_LABELS[filteredCorporate?.type]})`,
|
||||||
value: filteredCorporate.id,
|
value: filteredCorporate.id,
|
||||||
}
|
}
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
options={users
|
options={users
|
||||||
.filter((x) => ["admin", "developer", "corporate"].includes(x.type))
|
.filter((x) => ["admin", "developer", "corporate"].includes(x.type))
|
||||||
.map((x) => ({
|
.map((x) => ({
|
||||||
label: `${x.type === "corporate" ? x.corporateInformation?.companyInformation?.name || x.name : x.name} (${
|
label: `${x.type === "corporate" ? x.corporateInformation?.companyInformation?.name || x.name : x.name} (${USER_TYPE_LABELS[x.type]
|
||||||
USER_TYPE_LABELS[x.type]
|
})`,
|
||||||
})`,
|
|
||||||
value: x.id,
|
value: x.id,
|
||||||
user: x,
|
user: x,
|
||||||
}))}
|
}))}
|
||||||
@@ -240,8 +236,8 @@ export default function CodeList({user}: {user: User}) {
|
|||||||
placeholder="Availability"
|
placeholder="Availability"
|
||||||
isClearable
|
isClearable
|
||||||
options={[
|
options={[
|
||||||
{label: "In Use", value: "in-use"},
|
{ label: "In Use", value: "in-use" },
|
||||||
{label: "Unused", value: "unused"},
|
{ label: "Unused", value: "unused" },
|
||||||
]}
|
]}
|
||||||
onChange={(value) => setFilterAvailability(value ? (value.value as typeof filterAvailability) : undefined)}
|
onChange={(value) => setFilterAvailability(value ? (value.value as typeof filterAvailability) : undefined)}
|
||||||
/>
|
/>
|
||||||
@@ -266,7 +262,7 @@ export default function CodeList({user}: {user: User}) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{allowedToDelete && (
|
{canDeleteCodes && (
|
||||||
<div className="flex gap-4 items-center">
|
<div className="flex gap-4 items-center">
|
||||||
<span>{selectedCodes.length} code(s) selected</span>
|
<span>{selectedCodes.length} code(s) selected</span>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {User} from "@/interfaces/user";
|
import { User } from "@/interfaces/user";
|
||||||
import {Tab, TabGroup, TabList, TabPanel, TabPanels} from "@headlessui/react";
|
import { Tab, TabGroup, TabList, TabPanel, TabPanels } from "@headlessui/react";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import CodeList from "./CodeList";
|
import CodeList from "./CodeList";
|
||||||
import DiscountList from "./DiscountList";
|
import DiscountList from "./DiscountList";
|
||||||
@@ -7,10 +7,10 @@ import ExamList from "./ExamList";
|
|||||||
import GroupList from "./GroupList";
|
import GroupList from "./GroupList";
|
||||||
import PackageList from "./PackageList";
|
import PackageList from "./PackageList";
|
||||||
import UserList from "./UserList";
|
import UserList from "./UserList";
|
||||||
import {checkAccess} from "@/utils/permissions";
|
import { checkAccess } from "@/utils/permissions";
|
||||||
import {PermissionType} from "@/interfaces/permissions";
|
import { PermissionType } from "@/interfaces/permissions";
|
||||||
import { EntityWithRoles } from "@/interfaces/entity";
|
import { EntityWithRoles } from "@/interfaces/entity";
|
||||||
import { useAllowedEntitiesSomePermissions } from "@/hooks/useEntityPermissions";
|
import { useAllowedEntities, useAllowedEntitiesSomePermissions } from "@/hooks/useEntityPermissions";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -19,7 +19,9 @@ interface Props {
|
|||||||
permissions: PermissionType[];
|
permissions: PermissionType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Lists({user, entities = [], permissions}: Props) {
|
export default function Lists({ user, entities = [], permissions }: Props) {
|
||||||
|
const entitiesViewCodes = useAllowedEntities(user, entities, 'view_code_list')
|
||||||
|
const entitiesDeleteCodes = useAllowedEntities(user, entities, 'delete_code')
|
||||||
const entitiesViewExams = useAllowedEntitiesSomePermissions(user, entities, [
|
const entitiesViewExams = useAllowedEntitiesSomePermissions(user, entities, [
|
||||||
'view_reading', 'view_listening', 'view_writing', 'view_speaking', 'view_level'
|
'view_reading', 'view_listening', 'view_writing', 'view_speaking', 'view_level'
|
||||||
])
|
])
|
||||||
@@ -30,7 +32,7 @@ export default function Lists({user, entities = [], permissions}: Props) {
|
|||||||
<TabGroup>
|
<TabGroup>
|
||||||
<TabList className="flex space-x-1 rounded-xl bg-mti-purple-ultralight/40 p-1">
|
<TabList className="flex space-x-1 rounded-xl bg-mti-purple-ultralight/40 p-1">
|
||||||
<Tab
|
<Tab
|
||||||
className={({selected}) =>
|
className={({ selected }) =>
|
||||||
clsx(
|
clsx(
|
||||||
"w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-mti-purple-light",
|
"w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-mti-purple-light",
|
||||||
"ring-white ring-opacity-60 ring-offset-2 ring-offset-mti-purple-light focus:outline-none focus:ring-2",
|
"ring-white ring-opacity-60 ring-offset-2 ring-offset-mti-purple-light focus:outline-none focus:ring-2",
|
||||||
@@ -42,7 +44,7 @@ export default function Lists({user, entities = [], permissions}: Props) {
|
|||||||
</Tab>
|
</Tab>
|
||||||
{canViewExams && (
|
{canViewExams && (
|
||||||
<Tab
|
<Tab
|
||||||
className={({selected}) =>
|
className={({ selected }) =>
|
||||||
clsx(
|
clsx(
|
||||||
"w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-mti-purple-light",
|
"w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-mti-purple-light",
|
||||||
"ring-white ring-opacity-60 ring-offset-2 ring-offset-mti-purple-light focus:outline-none focus:ring-2",
|
"ring-white ring-opacity-60 ring-offset-2 ring-offset-mti-purple-light focus:outline-none focus:ring-2",
|
||||||
@@ -53,9 +55,9 @@ export default function Lists({user, entities = [], permissions}: Props) {
|
|||||||
Exam List
|
Exam List
|
||||||
</Tab>
|
</Tab>
|
||||||
)}
|
)}
|
||||||
{checkAccess(user, ["developer", "admin", "corporate"]) && (
|
{checkAccess(user, ["developer", "admin", "corporate"]) && entitiesViewCodes.length > 0 && (
|
||||||
<Tab
|
<Tab
|
||||||
className={({selected}) =>
|
className={({ selected }) =>
|
||||||
clsx(
|
clsx(
|
||||||
"w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-mti-purple-light",
|
"w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-mti-purple-light",
|
||||||
"ring-white ring-opacity-60 ring-offset-2 ring-offset-mti-purple-light focus:outline-none focus:ring-2",
|
"ring-white ring-opacity-60 ring-offset-2 ring-offset-mti-purple-light focus:outline-none focus:ring-2",
|
||||||
@@ -68,7 +70,7 @@ export default function Lists({user, entities = [], permissions}: Props) {
|
|||||||
)}
|
)}
|
||||||
{checkAccess(user, ["developer", "admin"]) && (
|
{checkAccess(user, ["developer", "admin"]) && (
|
||||||
<Tab
|
<Tab
|
||||||
className={({selected}) =>
|
className={({ selected }) =>
|
||||||
clsx(
|
clsx(
|
||||||
"w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-mti-purple-light",
|
"w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-mti-purple-light",
|
||||||
"ring-white ring-opacity-60 ring-offset-2 ring-offset-mti-purple-light focus:outline-none focus:ring-2",
|
"ring-white ring-opacity-60 ring-offset-2 ring-offset-mti-purple-light focus:outline-none focus:ring-2",
|
||||||
@@ -81,7 +83,7 @@ export default function Lists({user, entities = [], permissions}: Props) {
|
|||||||
)}
|
)}
|
||||||
{checkAccess(user, ["developer", "admin"]) && (
|
{checkAccess(user, ["developer", "admin"]) && (
|
||||||
<Tab
|
<Tab
|
||||||
className={({selected}) =>
|
className={({ selected }) =>
|
||||||
clsx(
|
clsx(
|
||||||
"w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-mti-purple-light",
|
"w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-mti-purple-light",
|
||||||
"ring-white ring-opacity-60 ring-offset-2 ring-offset-mti-purple-light focus:outline-none focus:ring-2",
|
"ring-white ring-opacity-60 ring-offset-2 ring-offset-mti-purple-light focus:outline-none focus:ring-2",
|
||||||
@@ -102,9 +104,9 @@ export default function Lists({user, entities = [], permissions}: Props) {
|
|||||||
<ExamList user={user} entities={entities} />
|
<ExamList user={user} entities={entities} />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
)}
|
)}
|
||||||
{checkAccess(user, ["developer", "admin", "corporate", "mastercorporate"], permissions, "viewCodes") && (
|
{checkAccess(user, ["developer", "admin", "corporate", "mastercorporate"]) && entitiesViewCodes.length > 0 && (
|
||||||
<TabPanel className="overflow-y-scroll max-h-[600px] rounded-xl scrollbar-hide">
|
<TabPanel className="overflow-y-scroll max-h-[600px] rounded-xl scrollbar-hide">
|
||||||
<CodeList user={user} />
|
<CodeList user={user} canDeleteCodes={entitiesDeleteCodes.length > 0} />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
)}
|
)}
|
||||||
{checkAccess(user, ["developer", "admin"]) && (
|
{checkAccess(user, ["developer", "admin"]) && (
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ const USER_MANAGEMENT: PermissionLayout[] = [
|
|||||||
{ label: "Create Users in Batch", key: "create_user_batch" },
|
{ label: "Create Users in Batch", key: "create_user_batch" },
|
||||||
{ label: "Create a Single Code", key: "create_code" },
|
{ label: "Create a Single Code", key: "create_code" },
|
||||||
{ label: "Create Codes in Batch", key: "create_code_batch" },
|
{ label: "Create Codes in Batch", key: "create_code_batch" },
|
||||||
|
{ label: "View Code List", key: "view_code_list" },
|
||||||
|
{ label: "Delete Code", key: "delete_code" },
|
||||||
]
|
]
|
||||||
|
|
||||||
const EXAM_MANAGEMENT: PermissionLayout[] = [
|
const EXAM_MANAGEMENT: PermissionLayout[] = [
|
||||||
@@ -65,6 +67,7 @@ const EXAM_MANAGEMENT: PermissionLayout[] = [
|
|||||||
{ label: "View Level", key: "view_level" },
|
{ label: "View Level", key: "view_level" },
|
||||||
{ label: "Generate Level", key: "generate_level" },
|
{ label: "Generate Level", key: "generate_level" },
|
||||||
{ label: "Delete Level", key: "delete_level" },
|
{ label: "Delete Level", key: "delete_level" },
|
||||||
|
{ label: "View Statistics", key: "view_statistics" },
|
||||||
]
|
]
|
||||||
|
|
||||||
const CLASSROOM_MANAGEMENT: PermissionLayout[] = [
|
const CLASSROOM_MANAGEMENT: PermissionLayout[] = [
|
||||||
@@ -89,6 +92,7 @@ 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" }
|
||||||
]
|
]
|
||||||
|
|
||||||
const ASSIGNMENT_MANAGEMENT: PermissionLayout[] = [
|
const ASSIGNMENT_MANAGEMENT: PermissionLayout[] = [
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import Layout from "@/components/High/Layout";
|
|||||||
import Table from "@/components/High/Table";
|
import Table from "@/components/High/Table";
|
||||||
import Checkbox from "@/components/Low/Checkbox";
|
import Checkbox from "@/components/Low/Checkbox";
|
||||||
import Separator from "@/components/Low/Separator";
|
import Separator from "@/components/Low/Separator";
|
||||||
|
import { useAllowedEntities } from "@/hooks/useEntityPermissions";
|
||||||
import { Session } from "@/hooks/useSessions";
|
import { Session } from "@/hooks/useSessions";
|
||||||
import { Entity, EntityWithRoles } from "@/interfaces/entity";
|
import { Entity, EntityWithRoles } from "@/interfaces/entity";
|
||||||
import { Exam } from "@/interfaces/exam";
|
import { Exam } from "@/interfaces/exam";
|
||||||
@@ -84,6 +85,8 @@ export default function Statistical({ user, students, entities, assignments, ses
|
|||||||
const [selectedEntities, setSelectedEntities] = useState<string[]>([])
|
const [selectedEntities, setSelectedEntities] = useState<string[]>([])
|
||||||
const [isDownloading, setIsDownloading] = useState(false)
|
const [isDownloading, setIsDownloading] = useState(false)
|
||||||
|
|
||||||
|
const entitiesAllowDownload = useAllowedEntities(user, entities, 'download_statistics_report')
|
||||||
|
|
||||||
const resetDateRange = () => {
|
const resetDateRange = () => {
|
||||||
const orderedAssignments = orderBy(assignments, ['startDate'], ['asc'])
|
const orderedAssignments = orderBy(assignments, ['startDate'], ['asc'])
|
||||||
setStartDate(moment(orderedAssignments.shift()?.startDate || "2024-01-01T00:00:01.986Z").toDate())
|
setStartDate(moment(orderedAssignments.shift()?.startDate || "2024-01-01T00:00:01.986Z").toDate())
|
||||||
@@ -297,7 +300,7 @@ export default function Statistical({ user, students, entities, assignments, ses
|
|||||||
data={sortedData}
|
data={sortedData}
|
||||||
searchFields={[["student", "name"], ["student", "email"], ["student", "studentID"], ["exams", "id"], ["assignment", "name"]]}
|
searchFields={[["student", "name"], ["student", "email"], ["student", "studentID"], ["exams", "id"], ["assignment", "name"]]}
|
||||||
searchPlaceholder="Search by student, assignment or exam..."
|
searchPlaceholder="Search by student, assignment or exam..."
|
||||||
onDownload={downloadExcel}
|
onDownload={entitiesAllowDownload.length > 0 ? downloadExcel : undefined}
|
||||||
isDownloadLoading={isDownloading}
|
isDownloadLoading={isDownloading}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -53,14 +53,20 @@ export type RolePermission =
|
|||||||
"create_user" |
|
"create_user" |
|
||||||
"create_user_batch" |
|
"create_user_batch" |
|
||||||
"create_code" |
|
"create_code" |
|
||||||
"create_code_batch"
|
"create_code_batch" |
|
||||||
|
"view_code_list" |
|
||||||
|
"delete_code" |
|
||||||
|
"view_statistics" |
|
||||||
|
"download_statistics_report"
|
||||||
|
|
||||||
export const DEFAULT_PERMISSIONS: RolePermission[] = [
|
export const DEFAULT_PERMISSIONS: RolePermission[] = [
|
||||||
"view_students",
|
"view_students",
|
||||||
"view_teachers",
|
"view_teachers",
|
||||||
"view_assignments",
|
"view_assignments",
|
||||||
"view_classrooms",
|
"view_classrooms",
|
||||||
"view_entity_roles"
|
"view_entity_roles",
|
||||||
|
"view_statistics",
|
||||||
|
"download_statistics_report"
|
||||||
]
|
]
|
||||||
|
|
||||||
export const ADMIN_PERMISSIONS: RolePermission[] = [
|
export const ADMIN_PERMISSIONS: RolePermission[] = [
|
||||||
@@ -118,5 +124,9 @@ export const ADMIN_PERMISSIONS: RolePermission[] = [
|
|||||||
"create_user",
|
"create_user",
|
||||||
"create_user_batch",
|
"create_user_batch",
|
||||||
"create_code",
|
"create_code",
|
||||||
"create_code_batch"
|
"create_code_batch",
|
||||||
|
"view_code_list",
|
||||||
|
"delete_code",
|
||||||
|
"view_statistics",
|
||||||
|
"download_statistics_report"
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user