Merge branch 'develop' into feature/exam-generation

This commit is contained in:
Tiago Ribeiro
2023-11-21 00:31:51 +00:00
15 changed files with 59 additions and 52 deletions

View File

@@ -105,12 +105,12 @@ export default function MobileMenu({isOpen, onClose, path, user}: Props) {
</Link> </Link>
{user.type !== "student" && ( {user.type !== "student" && (
<Link <Link
href="/admin" href="/manage"
className={clsx( className={clsx(
"transition ease-in-out duration-300 w-fit", "transition ease-in-out duration-300 w-fit",
path === "/admin" && "text-mti-purple-light font-semibold border-b-2 border-b-mti-purple-light ", path === "/manage" && "text-mti-purple-light font-semibold border-b-2 border-b-mti-purple-light ",
)}> )}>
Admin Management
</Link> </Link>
)} )}
<Link <Link

View File

@@ -90,7 +90,14 @@ export default function Sidebar({path, navDisabled = false, focusMode = false, u
<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} />
<Nav disabled={disableNavigation} Icon={BsClockHistory} label="Record" path={path} keyPath="/record" isMinimized={isMinimized} /> <Nav disabled={disableNavigation} Icon={BsClockHistory} label="Record" path={path} keyPath="/record" isMinimized={isMinimized} />
{userType !== "student" && ( {userType !== "student" && (
<Nav disabled={disableNavigation} Icon={BsShieldFill} label="Admin" path={path} keyPath="/admin" isMinimized={isMinimized} /> <Nav
disabled={disableNavigation}
Icon={BsShieldFill}
label="Management"
path={path}
keyPath="/manage"
isMinimized={isMinimized}
/>
)} )}
{userType === "developer" && ( {userType === "developer" && (
<Nav <Nav
@@ -110,7 +117,7 @@ export default function Sidebar({path, navDisabled = false, focusMode = false, u
<Nav disabled={disableNavigation} Icon={BsGraphUp} label="Stats" path={path} keyPath="/stats" isMinimized={true} /> <Nav disabled={disableNavigation} Icon={BsGraphUp} label="Stats" path={path} keyPath="/stats" isMinimized={true} />
<Nav disabled={disableNavigation} Icon={BsClockHistory} label="Record" path={path} keyPath="/record" isMinimized={true} /> <Nav disabled={disableNavigation} Icon={BsClockHistory} label="Record" path={path} keyPath="/record" isMinimized={true} />
{userType !== "student" && ( {userType !== "student" && (
<Nav disabled={disableNavigation} Icon={BsShieldFill} label="Admin" path={path} keyPath="/admin" isMinimized={true} /> <Nav disabled={disableNavigation} Icon={BsShieldFill} label="Management" path={path} keyPath="/manage" isMinimized={true} />
)} )}
{userType === "developer" && ( {userType === "developer" && (
<Nav disabled={disableNavigation} Icon={BsCloudFill} label="Generation" path={path} keyPath="/generation" isMinimized={true} /> <Nav disabled={disableNavigation} Icon={BsCloudFill} label="Generation" path={path} keyPath="/generation" isMinimized={true} />

View File

@@ -234,7 +234,7 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers}:
</div> </div>
</div> </div>
</div> </div>
{(loggedInUser.type === "developer" || loggedInUser.type === "owner") && ( {(loggedInUser.type === "developer" || loggedInUser.type === "admin") && (
<> <>
<Divider className="w-full" /> <Divider className="w-full" />
<div className="flex flex-col md:flex-row gap-8 w-full"> <div className="flex flex-col md:flex-row gap-8 w-full">
@@ -259,7 +259,7 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers}:
<option value="teacher">Teacher</option> <option value="teacher">Teacher</option>
<option value="corporate">Corporate</option> <option value="corporate">Corporate</option>
<option value="agent">Country Agent</option> <option value="agent">Country Agent</option>
<option value="owner">Owner</option> <option value="admin">Admin</option>
<option value="developer">Developer</option> <option value="developer">Developer</option>
</select> </select>
</div> </div>

View File

@@ -2,38 +2,38 @@ import {Type} from "@/interfaces/user";
export const PERMISSIONS = { export const PERMISSIONS = {
generateCode: { generateCode: {
student: ["corporate", "developer", "owner"], student: ["corporate", "developer", "admin"],
teacher: ["corporate", "developer", "owner"], teacher: ["corporate", "developer", "admin"],
corporate: ["owner", "developer"], corporate: ["admin", "developer"],
owner: ["developer", "owner"], admin: ["developer", "admin"],
agent: ["developer", "owner"], agent: ["developer", "admin"],
developer: ["developer"], developer: ["developer"],
}, },
deleteUser: { deleteUser: {
student: ["teacher", "corporate", "developer", "owner"], student: ["teacher", "corporate", "developer", "admin"],
teacher: ["corporate", "developer", "owner"], teacher: ["corporate", "developer", "admin"],
corporate: ["owner", "developer"], corporate: ["admin", "developer"],
owner: ["developer", "owner"], admin: ["developer", "admin"],
agent: ["developer", "owner"], agent: ["developer", "admin"],
developer: ["developer"], developer: ["developer"],
}, },
updateUser: { updateUser: {
student: ["teacher", "corporate", "developer", "owner"], student: ["teacher", "corporate", "developer", "admin"],
teacher: ["corporate", "developer", "owner"], teacher: ["corporate", "developer", "admin"],
corporate: ["owner", "developer"], corporate: ["admin", "developer"],
owner: ["developer", "owner"], admin: ["developer", "admin"],
agent: ["developer", "owner"], agent: ["developer", "admin"],
developer: ["developer"], developer: ["developer"],
}, },
updateExpiryDate: { updateExpiryDate: {
student: ["developer", "owner"], student: ["developer", "admin"],
teacher: ["developer", "owner"], teacher: ["developer", "admin"],
corporate: ["owner", "developer"], corporate: ["admin", "developer"],
owner: ["developer", "owner"], admin: ["developer", "admin"],
agent: ["developer", "owner"], agent: ["developer", "admin"],
developer: ["developer"], developer: ["developer"],
}, },
examManagement: { examManagement: {
delete: ["developer", "owner"], delete: ["developer", "admin"],
}, },
}; };

View File

@@ -16,7 +16,7 @@ interface Props {
user: User; user: User;
} }
export default function OwnerDashboard({user}: Props) { export default function AdminDashboard({user}: Props) {
const [page, setPage] = useState(""); const [page, setPage] = useState("");
const [selectedUser, setSelectedUser] = useState<User>(); const [selectedUser, setSelectedUser] = useState<User>();
const [showModal, setShowModal] = useState(false); const [showModal, setShowModal] = useState(false);

View File

@@ -80,5 +80,5 @@ export interface Group {
disableEditing?: boolean; disableEditing?: boolean;
} }
export type Type = "student" | "teacher" | "corporate" | "owner" | "developer" | "agent"; export type Type = "student" | "teacher" | "corporate" | "admin" | "developer" | "agent";
export const userTypes: Type[] = ["student", "teacher", "corporate", "owner", "developer", "agent"]; export const userTypes: Type[] = ["student", "teacher", "corporate", "admin", "developer", "agent"];

View File

@@ -83,7 +83,7 @@ export default function BatchCodeGenerator({user}: {user: User}) {
<Button onClick={openFilePicker} isLoading={isLoading} disabled={isLoading}> <Button onClick={openFilePicker} isLoading={isLoading} disabled={isLoading}>
{filesContent.length > 0 ? filesContent[0].name : "Choose a file"} {filesContent.length > 0 ? filesContent[0].name : "Choose a file"}
</Button> </Button>
{user && (user.type === "developer" || user.type === "owner") && ( {user && (user.type === "developer" || user.type === "admin") && (
<> <>
<div className="flex -md:flex-row md:flex-col -md:items-center 2xl:flex-row 2xl:items-center justify-between gap-2"> <div className="flex -md:flex-row md:flex-col -md:items-center 2xl:flex-row 2xl:items-center justify-between gap-2">
<label className="font-normal text-base text-mti-gray-dim">Expiry Date</label> <label className="font-normal text-base text-mti-gray-dim">Expiry Date</label>
@@ -133,9 +133,9 @@ export default function BatchCodeGenerator({user}: {user: User}) {
<Button <Button
className="w-44 2xl:w-48" className="w-44 2xl:w-48"
variant="outline" variant="outline"
onClick={() => generateCode("owner")} onClick={() => generateCode("admin")}
disabled={emails.length === 0 || isLoading || !PERMISSIONS.generateCode.owner.includes(user.type)}> disabled={emails.length === 0 || isLoading || !PERMISSIONS.generateCode.admin.includes(user.type)}>
Owner Admin
</Button> </Button>
</div> </div>
)} )}

View File

@@ -82,13 +82,13 @@ export default function CodeGenerator({user}: {user: User}) {
<Button <Button
className="w-44 md:w-48" className="w-44 md:w-48"
variant="outline" variant="outline"
onClick={() => generateCode("owner")} onClick={() => generateCode("admin")}
disabled={!PERMISSIONS.generateCode.owner.includes(user.type) || (isExpiryDateEnabled && expiryDate === null)}> disabled={!PERMISSIONS.generateCode.admin.includes(user.type) || (isExpiryDateEnabled && expiryDate === null)}>
Owner Admin
</Button> </Button>
</div> </div>
)} )}
{user && (user.type === "developer" || user.type === "owner") && ( {user && (user.type === "developer" || user.type === "admin") && (
<> <>
<div className="flex -md:flex-row md:flex-col -md:items-center 2xl:flex-row 2xl:items-center justify-between gap-2"> <div className="flex -md:flex-row md:flex-col -md:items-center 2xl:flex-row 2xl:items-center justify-between gap-2">
<label className="font-normal text-base text-mti-gray-dim">Expiry Date</label> <label className="font-normal text-base text-mti-gray-dim">Expiry Date</label>

View File

@@ -51,7 +51,7 @@ const CreatePanel = ({user, users, group, onCreate}: CreateDialogProps) => {
const emailUsers = [...new Set(emails)].map((x) => users.find((y) => y.email.toLowerCase() === x)).filter((x) => x !== undefined); const emailUsers = [...new Set(emails)].map((x) => users.find((y) => y.email.toLowerCase() === x)).filter((x) => x !== undefined);
const filteredUsers = emailUsers.filter( const filteredUsers = emailUsers.filter(
(x) => (x) =>
((user.type === "developer" || user.type === "owner" || user.type === "corporate") && ((user.type === "developer" || user.type === "admin" || user.type === "corporate") &&
(x?.type === "student" || x?.type === "teacher")) || (x?.type === "student" || x?.type === "teacher")) ||
(user.type === "teacher" && x?.type === "student"), (user.type === "teacher" && x?.type === "student"),
); );
@@ -216,7 +216,7 @@ export default function GroupList({user}: {user: User}) {
cell: ({row}: {row: {original: Group}}) => { cell: ({row}: {row: {original: Group}}) => {
return ( return (
<> <>
{(user?.type === "developer" || user?.type === "owner" || user.id === row.original.admin) && ( {(user?.type === "developer" || user?.type === "admin" || user.id === row.original.admin) && (
<div className="flex gap-2"> <div className="flex gap-2">
{editingID !== row.original.id && ( {editingID !== row.original.id && (
<div data-tip="Edit" className="cursor-pointer tooltip" onClick={() => setEditingID(row.original.id)}> <div data-tip="Edit" className="cursor-pointer tooltip" onClick={() => setEditingID(row.original.id)}>

View File

@@ -162,10 +162,10 @@ export default function UserList({user, filter}: {user: User; filter?: (user: Us
Admin Admin
</Button> </Button>
<Button <Button
onClick={() => updateAccountType(row.original, "owner")} onClick={() => updateAccountType(row.original, "admin")}
className="text-sm !py-2 !px-4" className="text-sm !py-2 !px-4"
disabled={row.original.type === "owner" || !PERMISSIONS.generateCode["owner"].includes(user.type)}> disabled={row.original.type === "admin" || !PERMISSIONS.generateCode["admin"].includes(user.type)}>
Owner Admin
</Button> </Button>
</div> </div>
</Popover.Panel> </Popover.Panel>

View File

@@ -47,7 +47,7 @@ async function del(req: NextApiRequest, res: NextApiResponse) {
const group = {...snapshot.data(), id: snapshot.id} as Group; const group = {...snapshot.data(), id: snapshot.id} as Group;
const user = req.session.user; const user = req.session.user;
if (user.type === "owner" || user.type === "developer" || user.id === group.admin) { if (user.type === "admin" || user.type === "developer" || user.id === group.admin) {
await deleteDoc(snapshot.ref); await deleteDoc(snapshot.ref);
res.status(200).json({ok: true}); res.status(200).json({ok: true});
@@ -69,7 +69,7 @@ async function patch(req: NextApiRequest, res: NextApiResponse) {
const group = {...snapshot.data(), id: snapshot.id} as Group; const group = {...snapshot.data(), id: snapshot.id} as Group;
const user = req.session.user; const user = req.session.user;
if (user.type === "owner" || user.type === "developer" || user.id === group.admin) { if (user.type === "admin" || user.type === "developer" || user.id === group.admin) {
await setDoc(snapshot.ref, req.body, {merge: true}); await setDoc(snapshot.ref, req.body, {merge: true});
res.status(200).json({ok: true}); res.status(200).json({ok: true});

View File

@@ -23,7 +23,7 @@ import Link from "next/link";
import {MODULE_ARRAY} from "@/utils/moduleUtils"; import {MODULE_ARRAY} from "@/utils/moduleUtils";
import ProfileSummary from "@/components/ProfileSummary"; import ProfileSummary from "@/components/ProfileSummary";
import StudentDashboard from "@/dashboards/Student"; import StudentDashboard from "@/dashboards/Student";
import OwnerDashboard from "@/dashboards/Owner"; import AdminDashboard from "@/dashboards/Admin";
import CorporateDashboard from "@/dashboards/Corporate"; import CorporateDashboard from "@/dashboards/Corporate";
import TeacherDashboard from "@/dashboards/Teacher"; import TeacherDashboard from "@/dashboards/Teacher";
@@ -166,8 +166,8 @@ export default function Home() {
{user.type === "student" && <StudentDashboard user={user} />} {user.type === "student" && <StudentDashboard user={user} />}
{user.type === "teacher" && <TeacherDashboard user={user} />} {user.type === "teacher" && <TeacherDashboard user={user} />}
{user.type === "corporate" && <CorporateDashboard user={user} />} {user.type === "corporate" && <CorporateDashboard user={user} />}
{user.type === "owner" && <OwnerDashboard user={user} />} {user.type === "admin" && <AdminDashboard user={user} />}
{user.type === "developer" && <OwnerDashboard user={user} />} {user.type === "developer" && <AdminDashboard user={user} />}
</Layout> </Layout>
)} )}
</> </>

View File

@@ -50,7 +50,7 @@ export default function Admin() {
return ( return (
<> <>
<Head> <Head>
<title>Admin Panel | EnCoach</title> <title>Management Panel | EnCoach</title>
<meta <meta
name="description" name="description"
content="A training platform for the IELTS exam provided by the Muscat Training Institute and developed by eCrop." content="A training platform for the IELTS exam provided by the Muscat Training Institute and developed by eCrop."

View File

@@ -296,7 +296,7 @@ export default function History({user}: {user: User}) {
<Layout user={user}> <Layout user={user}>
<div className="w-full flex -xl:flex-col -xl:gap-4 justify-between items-center"> <div className="w-full flex -xl:flex-col -xl:gap-4 justify-between items-center">
<div className="xl:w-3/4"> <div className="xl:w-3/4">
{(user.type === "developer" || user.type === "owner") && ( {(user.type === "developer" || user.type === "admin") && (
<Select <Select
options={users.map((x) => ({value: x.id, label: `${x.name} - ${x.email}`}))} options={users.map((x) => ({value: x.id, label: `${x.name} - ${x.email}`}))}
defaultValue={{value: user.id, label: `${user.name} - ${user.email}`}} defaultValue={{value: user.id, label: `${user.name} - ${user.email}`}}

View File

@@ -169,7 +169,7 @@ export default function Stats() {
<section className="flex flex-col gap-3"> <section className="flex flex-col gap-3">
<div className="w-full flex justify-between gap-8 items-center"> <div className="w-full flex justify-between gap-8 items-center">
<> <>
{(user.type === "developer" || user.type === "owner") && ( {(user.type === "developer" || user.type === "admin") && (
<Select <Select
className="w-full" className="w-full"
options={users.map((x) => ({value: x.id, label: `${x.name} - ${x.email}`}))} options={users.map((x) => ({value: x.id, label: `${x.name} - ${x.email}`}))}