Refactor most getServerProps to fetch independent request in parallel and projected the data only to return the necessary fields and changed some functions
This commit is contained in:
@@ -27,132 +27,182 @@ import StudentClassroomTransfer from "@/components/Imports/StudentClassroomTrans
|
||||
import Modal from "@/components/Modal";
|
||||
|
||||
export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
|
||||
const user = await requestUser(req, res)
|
||||
if (!user) return redirect("/login")
|
||||
const user = await requestUser(req, res);
|
||||
if (!user) return redirect("/login");
|
||||
|
||||
if (shouldRedirectHome(user)) return redirect("/")
|
||||
if (shouldRedirectHome(user)) return redirect("/");
|
||||
|
||||
const entityIDS = mapBy(user.entities, "id");
|
||||
const entities = await getEntitiesWithRoles(isAdmin(user) ? undefined : entityIDS)
|
||||
const allowedEntities = findAllowedEntities(user, entities, "view_classrooms")
|
||||
const entityIDS = mapBy(user.entities, "id");
|
||||
const entities = await getEntitiesWithRoles(
|
||||
isAdmin(user) ? undefined : entityIDS
|
||||
);
|
||||
|
||||
const groups = await getGroupsForEntities(mapBy(allowedEntities, 'id'));
|
||||
const allowedEntities = findAllowedEntities(
|
||||
user,
|
||||
entities,
|
||||
"view_classrooms"
|
||||
);
|
||||
|
||||
const users = await getSpecificUsers(uniq(groups.flatMap((g) => [...g.participants, g.admin])));
|
||||
const groupsWithUsers: GroupWithUsers[] = groups.map((g) => convertToUsers(g, users.filter(x => isAdmin(user) ? true : !isAdmin(x))));
|
||||
const groups = await getGroupsForEntities(mapBy(allowedEntities, "id"));
|
||||
|
||||
return {
|
||||
props: serialize({ user, groups: groupsWithUsers, entities: allowedEntities }),
|
||||
};
|
||||
const users = await getSpecificUsers(
|
||||
uniq(groups.flatMap((g) => [...g.participants, g.admin])),
|
||||
{ _id: 0, id: 1, name: 1, email: 1, corporateInformation: 1, type: 1 }
|
||||
);
|
||||
const groupsWithUsers: GroupWithUsers[] = groups.map((g) =>
|
||||
convertToUsers(
|
||||
g,
|
||||
users.filter((x) => (isAdmin(user) ? true : !isAdmin(x)))
|
||||
)
|
||||
);
|
||||
|
||||
return {
|
||||
props: serialize({
|
||||
user,
|
||||
groups: groupsWithUsers,
|
||||
entities: allowedEntities,
|
||||
}),
|
||||
};
|
||||
}, sessionOptions);
|
||||
|
||||
const SEARCH_FIELDS = [
|
||||
["name"],
|
||||
["admin", "name"],
|
||||
["admin", "email"],
|
||||
["admin", "corporateInformation", "companyInformation", "name"],
|
||||
["participants", "name"],
|
||||
["participants", "email"],
|
||||
["participants", "corporateInformation", "companyInformation", "name"],
|
||||
["name"],
|
||||
["admin", "name"],
|
||||
["admin", "email"],
|
||||
["admin", "corporateInformation", "companyInformation", "name"],
|
||||
["participants", "name"],
|
||||
["participants", "email"],
|
||||
["participants", "corporateInformation", "companyInformation", "name"],
|
||||
];
|
||||
|
||||
interface Props {
|
||||
user: User;
|
||||
groups: GroupWithUsers[];
|
||||
entities: EntityWithRoles[]
|
||||
user: User;
|
||||
groups: GroupWithUsers[];
|
||||
entities: EntityWithRoles[];
|
||||
}
|
||||
export default function Home({ user, groups, entities }: Props) {
|
||||
const entitiesAllowCreate = useAllowedEntities(user, entities, 'create_classroom');
|
||||
const [showImport, setShowImport] = useState(false);
|
||||
const entitiesAllowCreate = useAllowedEntities(
|
||||
user,
|
||||
entities,
|
||||
"create_classroom"
|
||||
);
|
||||
const [showImport, setShowImport] = useState(false);
|
||||
|
||||
const renderCard = (group: GroupWithUsers) => (
|
||||
<Link
|
||||
href={`/classrooms/${group.id}`}
|
||||
key={group.id}
|
||||
className="p-4 border-2 border-mti-purple-light/20 rounded-xl flex gap-2 justify-between hover:border-mti-purple group transition ease-in-out duration-300 text-left cursor-pointer">
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
<span className="flex items-center gap-1">
|
||||
<span className="bg-mti-purple text-white font-semibold px-2">Classroom</span>
|
||||
{group.name}
|
||||
</span>
|
||||
<span className="flex items-center gap-1">
|
||||
<span className="bg-mti-purple text-white font-semibold px-2">Admin</span>
|
||||
{getUserName(group.admin)}
|
||||
</span>
|
||||
{!!group.entity && (
|
||||
<span className="flex items-center gap-1">
|
||||
<span className="bg-mti-purple text-white font-semibold px-2">Entity</span>
|
||||
{findBy(entities, 'id', group.entity)?.label}
|
||||
</span>
|
||||
)}
|
||||
<span className="flex items-center gap-1">
|
||||
<span className="bg-mti-purple text-white font-semibold px-2">Participants</span>
|
||||
<span className="bg-mti-purple-light/50 px-2">{group.participants.length}</span>
|
||||
</span>
|
||||
<span>
|
||||
{group.participants.slice(0, 3).map(getUserName).join(", ")}{' '}
|
||||
{group.participants.length > 3 ? <span className="opacity-50 bg-mti-purple-light/50 px-1 text-sm">and {group.participants.length - 3} more</span> : ""}
|
||||
</span>
|
||||
</div>
|
||||
<div className="w-fit">
|
||||
<FaPersonChalkboard className="w-full h-20 -translate-y-[15%] group-hover:text-mti-purple transition ease-in-out duration-300" />
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
const renderCard = (group: GroupWithUsers) => (
|
||||
<Link
|
||||
href={`/classrooms/${group.id}`}
|
||||
key={group.id}
|
||||
className="p-4 border-2 border-mti-purple-light/20 rounded-xl flex gap-2 justify-between hover:border-mti-purple group transition ease-in-out duration-300 text-left cursor-pointer"
|
||||
>
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
<span className="flex items-center gap-1">
|
||||
<span className="bg-mti-purple text-white font-semibold px-2">
|
||||
Classroom
|
||||
</span>
|
||||
{group.name}
|
||||
</span>
|
||||
<span className="flex items-center gap-1">
|
||||
<span className="bg-mti-purple text-white font-semibold px-2">
|
||||
Admin
|
||||
</span>
|
||||
{getUserName(group.admin)}
|
||||
</span>
|
||||
{!!group.entity && (
|
||||
<span className="flex items-center gap-1">
|
||||
<span className="bg-mti-purple text-white font-semibold px-2">
|
||||
Entity
|
||||
</span>
|
||||
{findBy(entities, "id", group.entity)?.label}
|
||||
</span>
|
||||
)}
|
||||
<span className="flex items-center gap-1">
|
||||
<span className="bg-mti-purple text-white font-semibold px-2">
|
||||
Participants
|
||||
</span>
|
||||
<span className="bg-mti-purple-light/50 px-2">
|
||||
{group.participants.length}
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
{group.participants.slice(0, 3).map(getUserName).join(", ")}{" "}
|
||||
{group.participants.length > 3 ? (
|
||||
<span className="opacity-50 bg-mti-purple-light/50 px-1 text-sm">
|
||||
and {group.participants.length - 3} more
|
||||
</span>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="w-fit">
|
||||
<FaPersonChalkboard className="w-full h-20 -translate-y-[15%] group-hover:text-mti-purple transition ease-in-out duration-300" />
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
|
||||
const firstCard = () => (
|
||||
<Link
|
||||
href={`/classrooms/create`}
|
||||
className="p-4 border-2 hover:text-mti-purple rounded-xl flex flex-col items-center justify-center gap-0 hover:border-mti-purple transition ease-in-out duration-300 text-left cursor-pointer">
|
||||
<BsPlus size={40} />
|
||||
<span className="font-semibold">Create Classroom</span>
|
||||
</Link>
|
||||
);
|
||||
const firstCard = () => (
|
||||
<Link
|
||||
href={`/classrooms/create`}
|
||||
className="p-4 border-2 hover:text-mti-purple rounded-xl flex flex-col items-center justify-center gap-0 hover:border-mti-purple transition ease-in-out duration-300 text-left cursor-pointer"
|
||||
>
|
||||
<BsPlus size={40} />
|
||||
<span className="font-semibold">Create Classroom</span>
|
||||
</Link>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Classrooms | 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>
|
||||
<ToastContainer />
|
||||
<>
|
||||
<section className="flex flex-col gap-4 w-full h-full">
|
||||
<Modal isOpen={showImport} onClose={() => setShowImport(false)} maxWidth="max-w-[85%]">
|
||||
<StudentClassroomTransfer user={user} entities={entities} onFinish={() => setShowImport(false)} />
|
||||
</Modal>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex justify-between">
|
||||
<h2 className="font-bold text-2xl">Classrooms</h2>
|
||||
{entitiesAllowCreate.length !== 0 && <button
|
||||
className={clsx(
|
||||
"flex flex-row gap-3 items-center py-1.5 px-4 text-lg",
|
||||
"bg-mti-purple-light border border-mti-purple-light rounded-xl text-white",
|
||||
"hover:bg-white hover:text-mti-purple-light transition duration-300 ease-in-out",
|
||||
)}
|
||||
onClick={() => setShowImport(true)}
|
||||
>
|
||||
<FaFileUpload className="w-5 h-5" />
|
||||
Transfer Students
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
<Separator />
|
||||
</div>
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Classrooms | 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>
|
||||
<ToastContainer />
|
||||
<>
|
||||
<section className="flex flex-col gap-4 w-full h-full">
|
||||
<Modal
|
||||
isOpen={showImport}
|
||||
onClose={() => setShowImport(false)}
|
||||
maxWidth="max-w-[85%]"
|
||||
>
|
||||
<StudentClassroomTransfer
|
||||
user={user}
|
||||
entities={entities}
|
||||
onFinish={() => setShowImport(false)}
|
||||
/>
|
||||
</Modal>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex justify-between">
|
||||
<h2 className="font-bold text-2xl">Classrooms</h2>
|
||||
{entitiesAllowCreate.length !== 0 && (
|
||||
<button
|
||||
className={clsx(
|
||||
"flex flex-row gap-3 items-center py-1.5 px-4 text-lg",
|
||||
"bg-mti-purple-light border border-mti-purple-light rounded-xl text-white",
|
||||
"hover:bg-white hover:text-mti-purple-light transition duration-300 ease-in-out"
|
||||
)}
|
||||
onClick={() => setShowImport(true)}
|
||||
>
|
||||
<FaFileUpload className="w-5 h-5" />
|
||||
Transfer Students
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<Separator />
|
||||
</div>
|
||||
|
||||
<CardList<GroupWithUsers>
|
||||
list={groups}
|
||||
searchFields={SEARCH_FIELDS}
|
||||
renderCard={renderCard}
|
||||
firstCard={entitiesAllowCreate.length === 0 ? undefined : firstCard}
|
||||
/>
|
||||
</section>
|
||||
</>
|
||||
</>
|
||||
);
|
||||
<CardList<GroupWithUsers>
|
||||
list={groups}
|
||||
searchFields={SEARCH_FIELDS}
|
||||
renderCard={renderCard}
|
||||
firstCard={entitiesAllowCreate.length === 0 ? undefined : firstCard}
|
||||
/>
|
||||
</section>
|
||||
</>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user