ENCOA-126: Corporate should not be allowed to edit is own name

This commit is contained in:
Tiago Ribeiro
2024-08-29 13:18:11 +01:00
parent cd1caf0f53
commit 2b71f2467c
6 changed files with 203 additions and 245 deletions

View File

@@ -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">

View File

@@ -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

View File

@@ -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")}

View File

@@ -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>
)}
</>
);
} }

View File

@@ -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} />}
</> </>
); );
} }

View File

@@ -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 () => {