ENCOA-126: Corporate should not be allowed to edit is own name
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
import Modal from "@/components/Modal";
|
import Modal from "@/components/Modal";
|
||||||
import useFilterRecordsByUser from "@/hooks/useFilterRecordsByUser";
|
import useFilterRecordsByUser from "@/hooks/useFilterRecordsByUser";
|
||||||
import useUsers from "@/hooks/useUsers";
|
import useUsers from "@/hooks/useUsers";
|
||||||
import {CorporateUser, Group, Stat, User} from "@/interfaces/user";
|
import {CorporateUser, Group, MasterCorporateUser, Stat, User} from "@/interfaces/user";
|
||||||
import UserList from "@/pages/(admin)/Lists/UserList";
|
import UserList from "@/pages/(admin)/Lists/UserList";
|
||||||
import {dateSorter} from "@/utils";
|
import {dateSorter} from "@/utils";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
@@ -54,6 +54,7 @@ import useUserBalance from "@/hooks/useUserBalance";
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: CorporateUser;
|
user: CorporateUser;
|
||||||
|
linkedCorporate?: CorporateUser | MasterCorporateUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
type StudentPerformanceItem = User & {corporateName: string; group: string};
|
type StudentPerformanceItem = User & {corporateName: string; group: string};
|
||||||
@@ -154,11 +155,10 @@ const StudentPerformanceList = ({items, stats, users}: {items: StudentPerformanc
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function CorporateDashboard({user}: Props) {
|
export default function CorporateDashboard({user, linkedCorporate}: 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);
|
||||||
const [corporateUserToShow, setCorporateUserToShow] = useState<CorporateUser>();
|
|
||||||
const [selectedAssignment, setSelectedAssignment] = useState<Assignment>();
|
const [selectedAssignment, setSelectedAssignment] = useState<Assignment>();
|
||||||
const [isCreatingAssignment, setIsCreatingAssignment] = useState(false);
|
const [isCreatingAssignment, setIsCreatingAssignment] = useState(false);
|
||||||
|
|
||||||
@@ -193,11 +193,6 @@ export default function CorporateDashboard({user}: Props) {
|
|||||||
setShowModal(!!selectedUser && page === "");
|
setShowModal(!!selectedUser && page === "");
|
||||||
}, [selectedUser, page]);
|
}, [selectedUser, page]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// in this case it fetches the master corporate account
|
|
||||||
getUserCorporate(user.id).then(setCorporateUserToShow);
|
|
||||||
}, [user]);
|
|
||||||
|
|
||||||
const studentFilter = (user: User) => user.type === "student" && groups.flatMap((g) => g.participants).includes(user.id);
|
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 teacherFilter = (user: User) => user.type === "teacher" && groups.flatMap((g) => g.participants).includes(user.id);
|
||||||
|
|
||||||
@@ -455,9 +450,9 @@ export default function CorporateDashboard({user}: Props) {
|
|||||||
|
|
||||||
const DefaultDashboard = () => (
|
const DefaultDashboard = () => (
|
||||||
<>
|
<>
|
||||||
{corporateUserToShow && (
|
{!!linkedCorporate && (
|
||||||
<div className="absolute top-4 right-4 bg-neutral-200 px-2 rounded-lg py-1">
|
<div className="absolute top-4 right-4 bg-neutral-200 px-2 rounded-lg py-1">
|
||||||
Linked to: <b>{corporateUserToShow?.corporateInformation?.companyInformation.name || corporateUserToShow.name}</b>
|
Linked to: <b>{linkedCorporate?.corporateInformation?.companyInformation.name || linkedCorporate.name}</b>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<section className="grid grid-cols-5 -md:grid-cols-2 gap-4 text-center">
|
<section className="grid grid-cols-5 -md:grid-cols-2 gap-4 text-center">
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import useFilterRecordsByUser from "@/hooks/useFilterRecordsByUser";
|
|||||||
import useUsers from "@/hooks/useUsers";
|
import useUsers from "@/hooks/useUsers";
|
||||||
import {Invite} from "@/interfaces/invite";
|
import {Invite} from "@/interfaces/invite";
|
||||||
import {Assignment} from "@/interfaces/results";
|
import {Assignment} from "@/interfaces/results";
|
||||||
import {CorporateUser, Stat, User} from "@/interfaces/user";
|
import {CorporateUser, MasterCorporateUser, Stat, User} from "@/interfaces/user";
|
||||||
import useExamStore from "@/stores/examStore";
|
import useExamStore from "@/stores/examStore";
|
||||||
import {getExamById} from "@/utils/exams";
|
import {getExamById} from "@/utils/exams";
|
||||||
import {getUserCorporate} from "@/utils/groups";
|
import {getUserCorporate} from "@/utils/groups";
|
||||||
@@ -30,11 +30,10 @@ import {toast} from "react-toastify";
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: User;
|
user: User;
|
||||||
|
linkedCorporate?: CorporateUser | MasterCorporateUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function StudentDashboard({user}: Props) {
|
export default function StudentDashboard({user, linkedCorporate}: Props) {
|
||||||
const [corporateUserToShow, setCorporateUserToShow] = useState<CorporateUser>();
|
|
||||||
|
|
||||||
const {users} = useUsers();
|
const {users} = useUsers();
|
||||||
const {gradingSystem} = useGradingSystem();
|
const {gradingSystem} = useGradingSystem();
|
||||||
const {data: stats} = useFilterRecordsByUser<Stat[]>(user.id, !user?.id);
|
const {data: stats} = useFilterRecordsByUser<Stat[]>(user.id, !user?.id);
|
||||||
@@ -49,10 +48,6 @@ export default function StudentDashboard({user}: Props) {
|
|||||||
const setSelectedModules = useExamStore((state) => state.setSelectedModules);
|
const setSelectedModules = useExamStore((state) => state.setSelectedModules);
|
||||||
const setAssignment = useExamStore((state) => state.setAssignment);
|
const setAssignment = useExamStore((state) => state.setAssignment);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
getUserCorporate(user.id).then(setCorporateUserToShow);
|
|
||||||
}, [user]);
|
|
||||||
|
|
||||||
const startAssignment = (assignment: Assignment) => {
|
const startAssignment = (assignment: Assignment) => {
|
||||||
const examPromises = assignment.exams.filter((e) => e.assignee === user.id).map((e) => getExamById(e.module, e.id));
|
const examPromises = assignment.exams.filter((e) => e.assignee === user.id).map((e) => getExamById(e.module, e.id));
|
||||||
|
|
||||||
@@ -76,9 +71,9 @@ export default function StudentDashboard({user}: Props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{corporateUserToShow && (
|
{linkedCorporate && (
|
||||||
<div className="absolute right-4 top-4 rounded-lg bg-neutral-200 px-2 py-1">
|
<div className="absolute right-4 top-4 rounded-lg bg-neutral-200 px-2 py-1">
|
||||||
Linked to: <b>{corporateUserToShow?.corporateInformation?.companyInformation.name || corporateUserToShow.name}</b>
|
Linked to: <b>{linkedCorporate?.corporateInformation?.companyInformation.name || linkedCorporate.name}</b>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<ProfileSummary
|
<ProfileSummary
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import Modal from "@/components/Modal";
|
import Modal from "@/components/Modal";
|
||||||
import useFilterRecordsByUser from "@/hooks/useFilterRecordsByUser";
|
import useFilterRecordsByUser from "@/hooks/useFilterRecordsByUser";
|
||||||
import useUsers from "@/hooks/useUsers";
|
import useUsers from "@/hooks/useUsers";
|
||||||
import {CorporateUser, Group, Stat, User} from "@/interfaces/user";
|
import {CorporateUser, Group, MasterCorporateUser, Stat, User} from "@/interfaces/user";
|
||||||
import UserList from "@/pages/(admin)/Lists/UserList";
|
import UserList from "@/pages/(admin)/Lists/UserList";
|
||||||
import {dateSorter} from "@/utils";
|
import {dateSorter} from "@/utils";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
@@ -52,15 +52,15 @@ import {futureAssignmentFilter, pastAssignmentFilter, archivedAssignmentFilter,
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: User;
|
user: User;
|
||||||
|
linkedCorporate?: CorporateUser | MasterCorporateUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function TeacherDashboard({user}: Props) {
|
export default function TeacherDashboard({user, linkedCorporate}: 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);
|
||||||
const [selectedAssignment, setSelectedAssignment] = useState<Assignment>();
|
const [selectedAssignment, setSelectedAssignment] = useState<Assignment>();
|
||||||
const [isCreatingAssignment, setIsCreatingAssignment] = useState(false);
|
const [isCreatingAssignment, setIsCreatingAssignment] = useState(false);
|
||||||
const [corporateUserToShow, setCorporateUserToShow] = useState<CorporateUser>();
|
|
||||||
|
|
||||||
const {data: stats} = useFilterRecordsByUser<Stat[]>();
|
const {data: stats} = useFilterRecordsByUser<Stat[]>();
|
||||||
const {users, reload} = useUsers();
|
const {users, reload} = useUsers();
|
||||||
@@ -89,10 +89,6 @@ export default function TeacherDashboard({user}: Props) {
|
|||||||
setShowModal(!!selectedUser && page === "");
|
setShowModal(!!selectedUser && page === "");
|
||||||
}, [selectedUser, page]);
|
}, [selectedUser, page]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
getUserCorporate(user.id).then(setCorporateUserToShow);
|
|
||||||
}, [user]);
|
|
||||||
|
|
||||||
const studentFilter = (user: User) => user.type === "student" && groups.flatMap((g) => g.participants).includes(user.id);
|
const studentFilter = (user: User) => user.type === "student" && groups.flatMap((g) => g.participants).includes(user.id);
|
||||||
|
|
||||||
const getStatsByStudent = (user: User) => stats.filter((s) => s.user === user.id);
|
const getStatsByStudent = (user: User) => stats.filter((s) => s.user === user.id);
|
||||||
@@ -290,15 +286,15 @@ export default function TeacherDashboard({user}: Props) {
|
|||||||
|
|
||||||
const DefaultDashboard = () => (
|
const DefaultDashboard = () => (
|
||||||
<>
|
<>
|
||||||
{corporateUserToShow && (
|
{linkedCorporate && (
|
||||||
<div className="absolute top-4 right-4 bg-neutral-200 px-2 rounded-lg py-1">
|
<div className="absolute top-4 right-4 bg-neutral-200 px-2 rounded-lg py-1">
|
||||||
Linked to: <b>{corporateUserToShow?.corporateInformation?.companyInformation.name || corporateUserToShow.name}</b>
|
Linked to: <b>{linkedCorporate?.corporateInformation?.companyInformation.name || linkedCorporate.name}</b>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<section
|
<section
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"flex -lg:flex-wrap gap-4 items-center -lg:justify-center lg:justify-start text-center",
|
"flex -lg:flex-wrap gap-4 items-center -lg:justify-center lg:justify-start text-center",
|
||||||
!!corporateUserToShow && "mt-12 xl:mt-6",
|
!!linkedCorporate && "mt-12 xl:mt-6",
|
||||||
)}>
|
)}>
|
||||||
<IconCard
|
<IconCard
|
||||||
onClick={() => setPage("students")}
|
onClick={() => setPage("students")}
|
||||||
|
|||||||
@@ -1,32 +1,24 @@
|
|||||||
/* eslint-disable @next/next/no-img-element */
|
/* eslint-disable @next/next/no-img-element */
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import Navbar from "@/components/Navbar";
|
import Navbar from "@/components/Navbar";
|
||||||
import {
|
import {BsFileEarmarkText, BsPencil, BsStar, BsBook, BsHeadphones, BsPen, BsMegaphone} from "react-icons/bs";
|
||||||
BsFileEarmarkText,
|
import {withIronSessionSsr} from "iron-session/next";
|
||||||
BsPencil,
|
import {sessionOptions} from "@/lib/session";
|
||||||
BsStar,
|
import {useEffect, useState} from "react";
|
||||||
BsBook,
|
import {averageScore, groupBySession, totalExams} from "@/utils/stats";
|
||||||
BsHeadphones,
|
|
||||||
BsPen,
|
|
||||||
BsMegaphone,
|
|
||||||
} from "react-icons/bs";
|
|
||||||
import { withIronSessionSsr } from "iron-session/next";
|
|
||||||
import { sessionOptions } from "@/lib/session";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { averageScore, groupBySession, totalExams } from "@/utils/stats";
|
|
||||||
import useUser from "@/hooks/useUser";
|
import useUser from "@/hooks/useUser";
|
||||||
import Diagnostic from "@/components/Diagnostic";
|
import Diagnostic from "@/components/Diagnostic";
|
||||||
import { ToastContainer } from "react-toastify";
|
import {ToastContainer} from "react-toastify";
|
||||||
import { capitalize } from "lodash";
|
import {capitalize} from "lodash";
|
||||||
import { Module } from "@/interfaces";
|
import {Module} from "@/interfaces";
|
||||||
import ProgressBar from "@/components/Low/ProgressBar";
|
import ProgressBar from "@/components/Low/ProgressBar";
|
||||||
import Layout from "@/components/High/Layout";
|
import Layout from "@/components/High/Layout";
|
||||||
import { calculateAverageLevel } from "@/utils/score";
|
import {calculateAverageLevel} from "@/utils/score";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import DemographicInformationInput from "@/components/DemographicInformationInput";
|
import DemographicInformationInput from "@/components/DemographicInformationInput";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import Link from "next/link";
|
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 AdminDashboard from "@/dashboards/Admin";
|
import AdminDashboard from "@/dashboards/Admin";
|
||||||
@@ -35,209 +27,184 @@ import TeacherDashboard from "@/dashboards/Teacher";
|
|||||||
import AgentDashboard from "@/dashboards/Agent";
|
import AgentDashboard from "@/dashboards/Agent";
|
||||||
import MasterCorporateDashboard from "@/dashboards/MasterCorporate";
|
import MasterCorporateDashboard from "@/dashboards/MasterCorporate";
|
||||||
import PaymentDue from "./(status)/PaymentDue";
|
import PaymentDue from "./(status)/PaymentDue";
|
||||||
import { useRouter } from "next/router";
|
import {useRouter} from "next/router";
|
||||||
import { PayPalScriptProvider } from "@paypal/react-paypal-js";
|
import {PayPalScriptProvider} from "@paypal/react-paypal-js";
|
||||||
import {
|
import {CorporateUser, MasterCorporateUser, Type, userTypes} from "@/interfaces/user";
|
||||||
CorporateUser,
|
|
||||||
MasterCorporateUser,
|
|
||||||
Type,
|
|
||||||
userTypes,
|
|
||||||
} from "@/interfaces/user";
|
|
||||||
import Select from "react-select";
|
import Select from "react-select";
|
||||||
import { USER_TYPE_LABELS } from "@/resources/user";
|
import {USER_TYPE_LABELS} from "@/resources/user";
|
||||||
import { checkAccess, getTypesOfUser } from "@/utils/permissions";
|
import {checkAccess, getTypesOfUser} from "@/utils/permissions";
|
||||||
|
import {getUserCorporate} from "@/utils/groups.be";
|
||||||
|
|
||||||
export const getServerSideProps = withIronSessionSsr(({ req, res }) => {
|
export const getServerSideProps = withIronSessionSsr(async ({req, res}) => {
|
||||||
const user = req.session.user;
|
const user = req.session.user;
|
||||||
|
|
||||||
const envVariables: { [key: string]: string } = {};
|
const envVariables: {[key: string]: string} = {};
|
||||||
Object.keys(process.env)
|
Object.keys(process.env)
|
||||||
.filter((x) => x.startsWith("NEXT_PUBLIC"))
|
.filter((x) => x.startsWith("NEXT_PUBLIC"))
|
||||||
.forEach((x: string) => {
|
.forEach((x: string) => {
|
||||||
envVariables[x] = process.env[x]!;
|
envVariables[x] = process.env[x]!;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!user || !user.isVerified) {
|
if (!user || !user.isVerified) {
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
destination: "/login",
|
destination: "/login",
|
||||||
permanent: false,
|
permanent: false,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
const linkedCorporate = await getUserCorporate(user.id);
|
||||||
props: { user: req.session.user, envVariables },
|
|
||||||
};
|
return {
|
||||||
|
props: {user, envVariables, linkedCorporate},
|
||||||
|
};
|
||||||
}, sessionOptions);
|
}, sessionOptions);
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: any;
|
user: any;
|
||||||
envVariables: { [key: string]: string };
|
envVariables: {[key: string]: string};
|
||||||
|
linkedCorporate?: CorporateUser | MasterCorporateUser;
|
||||||
}
|
}
|
||||||
export default function Home(props: Props) {
|
|
||||||
const { envVariables } = props;
|
|
||||||
const [showDiagnostics, setShowDiagnostics] = useState(false);
|
|
||||||
const [showDemographicInput, setShowDemographicInput] = useState(false);
|
|
||||||
const [selectedScreen, setSelectedScreen] = useState<Type>("admin");
|
|
||||||
|
|
||||||
const { user, mutateUser } = useUser({ redirectTo: "/login" });
|
export default function Home({linkedCorporate}: Props) {
|
||||||
const router = useRouter();
|
const [showDiagnostics, setShowDiagnostics] = useState(false);
|
||||||
|
const [showDemographicInput, setShowDemographicInput] = useState(false);
|
||||||
|
const [selectedScreen, setSelectedScreen] = useState<Type>("admin");
|
||||||
|
|
||||||
useEffect(() => {
|
const {user, mutateUser} = useUser({redirectTo: "/login"});
|
||||||
if (user) {
|
const router = useRouter();
|
||||||
setShowDemographicInput(
|
|
||||||
!user.demographicInformation ||
|
|
||||||
!user.demographicInformation.country ||
|
|
||||||
!user.demographicInformation.gender ||
|
|
||||||
!user.demographicInformation.phone
|
|
||||||
);
|
|
||||||
setShowDiagnostics(user.isFirstLogin && user.type === "student");
|
|
||||||
}
|
|
||||||
}, [user]);
|
|
||||||
|
|
||||||
const checkIfUserExpired = () => {
|
useEffect(() => {
|
||||||
const expirationDate = user!.subscriptionExpirationDate;
|
if (user) {
|
||||||
|
setShowDemographicInput(
|
||||||
|
!user.demographicInformation ||
|
||||||
|
!user.demographicInformation.country ||
|
||||||
|
!user.demographicInformation.gender ||
|
||||||
|
!user.demographicInformation.phone,
|
||||||
|
);
|
||||||
|
setShowDiagnostics(user.isFirstLogin && user.type === "student");
|
||||||
|
}
|
||||||
|
}, [user]);
|
||||||
|
|
||||||
if (expirationDate === null || expirationDate === undefined) return false;
|
const checkIfUserExpired = () => {
|
||||||
if (moment(expirationDate).isAfter(moment(new Date()))) return false;
|
const expirationDate = user!.subscriptionExpirationDate;
|
||||||
|
|
||||||
return true;
|
if (expirationDate === null || expirationDate === undefined) return false;
|
||||||
};
|
if (moment(expirationDate).isAfter(moment(new Date()))) return false;
|
||||||
|
|
||||||
if (
|
return true;
|
||||||
user &&
|
};
|
||||||
(user.status === "paymentDue" ||
|
|
||||||
user.status === "disabled" ||
|
|
||||||
checkIfUserExpired())
|
|
||||||
) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Head>
|
|
||||||
<title>EnCoach</title>
|
|
||||||
<meta
|
|
||||||
name="description"
|
|
||||||
content="A training platform for the IELTS exam provided by the Muscat Training Institute and developed by eCrop."
|
|
||||||
/>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<link rel="icon" href="/favicon.ico" />
|
|
||||||
</Head>
|
|
||||||
{user.status === "disabled" && (
|
|
||||||
<Layout user={user} navDisabled>
|
|
||||||
<div className="flex flex-col items-center justify-center text-center w-full gap-4">
|
|
||||||
<span className="font-bold text-lg">
|
|
||||||
Your account has been disabled!
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
Please contact an administrator if you believe this to be a
|
|
||||||
mistake.
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</Layout>
|
|
||||||
)}
|
|
||||||
{(user.status === "paymentDue" || checkIfUserExpired()) && (
|
|
||||||
<PaymentDue hasExpired user={user} reload={router.reload} />
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user && showDemographicInput) {
|
if (user && (user.status === "paymentDue" || user.status === "disabled" || checkIfUserExpired())) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
<title>EnCoach</title>
|
<title>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."
|
||||||
/>
|
/>
|
||||||
<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>
|
||||||
<Layout user={user} navDisabled>
|
{user.status === "disabled" && (
|
||||||
<DemographicInformationInput mutateUser={mutateUser} user={user} />
|
<Layout user={user} navDisabled>
|
||||||
</Layout>
|
<div className="flex flex-col items-center justify-center text-center w-full gap-4">
|
||||||
</>
|
<span className="font-bold text-lg">Your account has been disabled!</span>
|
||||||
);
|
<span>Please contact an administrator if you believe this to be a mistake.</span>
|
||||||
}
|
</div>
|
||||||
|
</Layout>
|
||||||
|
)}
|
||||||
|
{(user.status === "paymentDue" || checkIfUserExpired()) && <PaymentDue hasExpired user={user} reload={router.reload} />}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (user && showDiagnostics) {
|
if (user && showDemographicInput) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
<title>EnCoach</title>
|
<title>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."
|
||||||
/>
|
/>
|
||||||
<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>
|
||||||
<Layout user={user} navDisabled>
|
<Layout user={user} navDisabled>
|
||||||
<Diagnostic user={user} onFinish={() => setShowDiagnostics(false)} />
|
<DemographicInformationInput mutateUser={mutateUser} user={user} />
|
||||||
</Layout>
|
</Layout>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
if (user && showDiagnostics) {
|
||||||
<>
|
return (
|
||||||
<Head>
|
<>
|
||||||
<title>EnCoach</title>
|
<Head>
|
||||||
<meta
|
<title>EnCoach</title>
|
||||||
name="description"
|
<meta
|
||||||
content="A training platform for the IELTS exam provided by the Muscat Training Institute and developed by eCrop."
|
name="description"
|
||||||
/>
|
content="A training platform for the IELTS exam provided by the Muscat Training Institute and developed by eCrop."
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
/>
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
</Head>
|
<link rel="icon" href="/favicon.ico" />
|
||||||
<ToastContainer />
|
</Head>
|
||||||
{user && (
|
<Layout user={user} navDisabled>
|
||||||
<Layout user={user}>
|
<Diagnostic user={user} onFinish={() => setShowDiagnostics(false)} />
|
||||||
{checkAccess(user, ["student"]) && <StudentDashboard user={user} />}
|
</Layout>
|
||||||
{checkAccess(user, ["teacher"]) && <TeacherDashboard user={user} />}
|
</>
|
||||||
{checkAccess(user, ["corporate"]) && (
|
);
|
||||||
<CorporateDashboard user={user as CorporateUser} />
|
}
|
||||||
)}
|
|
||||||
{checkAccess(user, ["mastercorporate"]) && (
|
|
||||||
<MasterCorporateDashboard user={user as MasterCorporateUser} />
|
|
||||||
)}
|
|
||||||
{checkAccess(user, ["agent"]) && <AgentDashboard user={user} />}
|
|
||||||
{checkAccess(user, ["admin"]) && <AdminDashboard user={user} />}
|
|
||||||
{checkAccess(user, ["developer"]) && (
|
|
||||||
<>
|
|
||||||
<Select
|
|
||||||
options={userTypes.map((u) => ({
|
|
||||||
value: u,
|
|
||||||
label: USER_TYPE_LABELS[u],
|
|
||||||
}))}
|
|
||||||
value={{
|
|
||||||
value: selectedScreen,
|
|
||||||
label: USER_TYPE_LABELS[selectedScreen],
|
|
||||||
}}
|
|
||||||
onChange={(value) =>
|
|
||||||
value
|
|
||||||
? setSelectedScreen(value.value)
|
|
||||||
: setSelectedScreen("admin")
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{selectedScreen === "student" && <StudentDashboard user={user} />}
|
return (
|
||||||
{selectedScreen === "teacher" && <TeacherDashboard user={user} />}
|
<>
|
||||||
{selectedScreen === "corporate" && (
|
<Head>
|
||||||
<CorporateDashboard user={user as unknown as CorporateUser} />
|
<title>EnCoach</title>
|
||||||
)}
|
<meta
|
||||||
{selectedScreen === "mastercorporate" && (
|
name="description"
|
||||||
<MasterCorporateDashboard
|
content="A training platform for the IELTS exam provided by the Muscat Training Institute and developed by eCrop."
|
||||||
user={user as unknown as MasterCorporateUser}
|
/>
|
||||||
/>
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
)}
|
<link rel="icon" href="/favicon.ico" />
|
||||||
{selectedScreen === "agent" && <AgentDashboard user={user} />}
|
</Head>
|
||||||
{selectedScreen === "admin" && <AdminDashboard user={user} />}
|
<ToastContainer />
|
||||||
</>
|
{user && (
|
||||||
)}
|
<Layout user={user}>
|
||||||
</Layout>
|
{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} />}
|
||||||
|
{checkAccess(user, ["agent"]) && <AgentDashboard user={user} />}
|
||||||
|
{checkAccess(user, ["admin"]) && <AdminDashboard user={user} />}
|
||||||
|
{checkAccess(user, ["developer"]) && (
|
||||||
|
<>
|
||||||
|
<Select
|
||||||
|
options={userTypes.map((u) => ({
|
||||||
|
value: u,
|
||||||
|
label: USER_TYPE_LABELS[u],
|
||||||
|
}))}
|
||||||
|
value={{
|
||||||
|
value: selectedScreen,
|
||||||
|
label: USER_TYPE_LABELS[selectedScreen],
|
||||||
|
}}
|
||||||
|
onChange={(value) => (value ? setSelectedScreen(value.value) : setSelectedScreen("admin"))}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{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} />
|
||||||
|
)}
|
||||||
|
{selectedScreen === "mastercorporate" && <MasterCorporateDashboard user={user as unknown as MasterCorporateUser} />}
|
||||||
|
{selectedScreen === "agent" && <AgentDashboard user={user} />}
|
||||||
|
{selectedScreen === "admin" && <AdminDashboard user={user} />}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Layout>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import Link from "next/link";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {ErrorMessage} from "@/constants/errors";
|
import {ErrorMessage} from "@/constants/errors";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import {CorporateUser, EmploymentStatus, EMPLOYMENT_STATUS, Gender, User, DemographicInformation} from "@/interfaces/user";
|
import {CorporateUser, EmploymentStatus, EMPLOYMENT_STATUS, Gender, User, DemographicInformation, MasterCorporateUser} from "@/interfaces/user";
|
||||||
import CountrySelect from "@/components/Low/CountrySelect";
|
import CountrySelect from "@/components/Low/CountrySelect";
|
||||||
import {shouldRedirectHome} from "@/utils/navigation.disabled";
|
import {shouldRedirectHome} from "@/utils/navigation.disabled";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
@@ -34,8 +34,10 @@ import {capitalize} from "lodash";
|
|||||||
import TopicModal from "@/components/Medium/TopicModal";
|
import TopicModal from "@/components/Medium/TopicModal";
|
||||||
import {v4} from "uuid";
|
import {v4} from "uuid";
|
||||||
import {checkAccess, getTypesOfUser} from "@/utils/permissions";
|
import {checkAccess, getTypesOfUser} from "@/utils/permissions";
|
||||||
|
import {getUserCorporate} from "@/utils/groups.be";
|
||||||
|
import {InferGetServerSidePropsType} from "next";
|
||||||
|
|
||||||
export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
export const getServerSideProps = withIronSessionSsr(async ({req, res}) => {
|
||||||
const user = req.session.user;
|
const user = req.session.user;
|
||||||
|
|
||||||
if (!user || !user.isVerified) {
|
if (!user || !user.isVerified) {
|
||||||
@@ -57,18 +59,19 @@ export const getServerSideProps = withIronSessionSsr(({req, res}) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {user: req.session.user},
|
props: {user, linkedCorporate: await getUserCorporate(user.id)},
|
||||||
};
|
};
|
||||||
}, sessionOptions);
|
}, sessionOptions);
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: User;
|
user: User;
|
||||||
mutateUser: Function;
|
mutateUser: Function;
|
||||||
|
linkedCorporate?: CorporateUser | MasterCorporateUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DoubleColumnRow = ({children}: {children: ReactNode}) => <div className="flex flex-col lg:flex-row gap-8 w-full">{children}</div>;
|
const DoubleColumnRow = ({children}: {children: ReactNode}) => <div className="flex flex-col lg:flex-row gap-8 w-full">{children}</div>;
|
||||||
|
|
||||||
function UserProfile({user, mutateUser}: Props) {
|
function UserProfile({user, mutateUser, linkedCorporate}: Props) {
|
||||||
const [bio, setBio] = useState(user.bio || "");
|
const [bio, setBio] = useState(user.bio || "");
|
||||||
const [name, setName] = useState(user.name || "");
|
const [name, setName] = useState(user.name || "");
|
||||||
const [email, setEmail] = useState(user.email || "");
|
const [email, setEmail] = useState(user.email || "");
|
||||||
@@ -245,7 +248,7 @@ function UserProfile({user, mutateUser}: Props) {
|
|||||||
<h1 className="text-4xl font-bold mb-6 -md:hidden">Edit Profile</h1>
|
<h1 className="text-4xl font-bold mb-6 -md:hidden">Edit Profile</h1>
|
||||||
<form className="flex flex-col items-center gap-6 w-full" onSubmit={(e) => e.preventDefault()}>
|
<form className="flex flex-col items-center gap-6 w-full" onSubmit={(e) => e.preventDefault()}>
|
||||||
<DoubleColumnRow>
|
<DoubleColumnRow>
|
||||||
{user.type !== "corporate" ? (
|
{user.type !== "corporate" && user.type !== "mastercorporate" ? (
|
||||||
<Input
|
<Input
|
||||||
label={user.type === "agent" ? "English name" : "Name"}
|
label={user.type === "agent" ? "English name" : "Name"}
|
||||||
type="text"
|
type="text"
|
||||||
@@ -260,6 +263,7 @@ function UserProfile({user, mutateUser}: Props) {
|
|||||||
label="Company name"
|
label="Company name"
|
||||||
type="text"
|
type="text"
|
||||||
name="name"
|
name="name"
|
||||||
|
disabled={!!linkedCorporate}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setCorporateInformation((prev) => ({
|
setCorporateInformation((prev) => ({
|
||||||
...prev!,
|
...prev!,
|
||||||
@@ -502,6 +506,7 @@ function UserProfile({user, mutateUser}: Props) {
|
|||||||
label="Department"
|
label="Department"
|
||||||
placeholder="CEO, Head of Marketing..."
|
placeholder="CEO, Head of Marketing..."
|
||||||
required
|
required
|
||||||
|
disabled={!!linkedCorporate}
|
||||||
/>
|
/>
|
||||||
</DoubleColumnRow>
|
</DoubleColumnRow>
|
||||||
</>
|
</>
|
||||||
@@ -638,7 +643,7 @@ function UserProfile({user, mutateUser}: Props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home({linkedCorporate}: {linkedCorporate?: CorporateUser | MasterCorporateUser}) {
|
||||||
const {user, mutateUser} = useUser({redirectTo: "/login"});
|
const {user, mutateUser} = useUser({redirectTo: "/login"});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -653,7 +658,7 @@ export default function Home() {
|
|||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
</Head>
|
</Head>
|
||||||
<ToastContainer />
|
<ToastContainer />
|
||||||
{user && <UserProfile user={user} mutateUser={mutateUser} />}
|
{user && <UserProfile linkedCorporate={linkedCorporate} user={user} mutateUser={mutateUser} />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {app} from "@/firebase";
|
import {app} from "@/firebase";
|
||||||
import {CorporateUser, Group, StudentUser, TeacherUser} from "@/interfaces/user";
|
import {CorporateUser, Group, MasterCorporateUser, StudentUser, TeacherUser} from "@/interfaces/user";
|
||||||
import {collection, doc, getDoc, getDocs, getFirestore, query, setDoc, where} from "firebase/firestore";
|
import {collection, doc, getDoc, getDocs, getFirestore, query, setDoc, where} from "firebase/firestore";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import {getUser} from "./users.be";
|
import {getUser} from "./users.be";
|
||||||
@@ -35,14 +35,14 @@ export const updateExpiryDateOnGroup = async (participantID: string, corporateID
|
|||||||
|
|
||||||
export const getUserCorporate = async (id: string) => {
|
export const getUserCorporate = async (id: string) => {
|
||||||
const user = await getUser(id);
|
const user = await getUser(id);
|
||||||
if (user.type === "corporate" || user.type === "mastercorporate") return user;
|
if (user.type === "mastercorporate") return user;
|
||||||
|
|
||||||
const groups = await getParticipantGroups(id);
|
const groups = await getParticipantGroups(id);
|
||||||
const admins = await Promise.all(groups.map((x) => x.admin).map(getUser));
|
const admins = await Promise.all(groups.map((x) => x.admin).map(getUser));
|
||||||
const corporates = admins.filter((x) => x.type === "corporate");
|
const corporates = admins.filter((x) => x.type === "corporate" || x.type === "mastercorporate");
|
||||||
|
|
||||||
if (corporates.length === 0) return undefined;
|
if (corporates.length === 0) return undefined;
|
||||||
return corporates.shift() as CorporateUser;
|
return corporates.shift() as CorporateUser | MasterCorporateUser;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getGroups = async () => {
|
export const getGroups = async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user