Corrected a bug related to groups of a master corporate

This commit is contained in:
Tiago Ribeiro
2024-08-20 14:37:33 +01:00
parent 247f192a0a
commit 4315a7b17c
2 changed files with 304 additions and 367 deletions

View File

@@ -4,9 +4,9 @@ import useStats from "@/hooks/useStats";
import useUsers from "@/hooks/useUsers"; import useUsers from "@/hooks/useUsers";
import {CorporateUser, Group, MasterCorporateUser, 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";
import { useEffect, useState } from "react"; import {useEffect, useState} from "react";
import { import {
BsArrowLeft, BsArrowLeft,
BsClipboard2Data, BsClipboard2Data,
@@ -22,7 +22,7 @@ import {
BsPlus, BsPlus,
BsPersonFillGear, BsPersonFillGear,
BsFilter, BsFilter,
BsDatabase BsDatabase,
} from "react-icons/bs"; } from "react-icons/bs";
import UserCard from "@/components/UserCard"; import UserCard from "@/components/UserCard";
import useGroups from "@/hooks/useGroups"; import useGroups from "@/hooks/useGroups";
@@ -34,10 +34,10 @@ import {groupByExam} from "@/utils/stats";
import IconCard from "./IconCard"; import IconCard from "./IconCard";
import GroupList from "@/pages/(admin)/Lists/GroupList"; import GroupList from "@/pages/(admin)/Lists/GroupList";
import useFilterStore from "@/stores/listFilterStore"; import useFilterStore from "@/stores/listFilterStore";
import { useRouter } from "next/router"; import {useRouter} from "next/router";
import useCodes from "@/hooks/useCodes"; import useCodes from "@/hooks/useCodes";
import useAssignments from "@/hooks/useAssignments"; import useAssignments from "@/hooks/useAssignments";
import { Assignment } from "@/interfaces/results"; import {Assignment} from "@/interfaces/results";
import AssignmentView from "./AssignmentView"; import AssignmentView from "./AssignmentView";
import AssignmentCreator from "./AssignmentCreator"; import AssignmentCreator from "./AssignmentCreator";
import clsx from "clsx"; import clsx from "clsx";
@@ -54,7 +54,7 @@ import {Popover, PopoverContent, PopoverTrigger} from "@/components/ui/popover";
import MasterStatistical from "./MasterStatistical"; import MasterStatistical from "./MasterStatistical";
interface Props { interface Props {
user: MasterCorporateUser; user: MasterCorporateUser;
} }
const activeFilter = (a: Assignment) => const activeFilter = (a: Assignment) =>
@@ -309,28 +309,18 @@ export default function MasterCorporateDashboard({user}: Props) {
const {codes} = useCodes(user.id); const {codes} = useCodes(user.id);
const {groups} = useGroups({admin: user.id, userType: user.type}); const {groups} = useGroups({admin: user.id, userType: user.type});
const masterCorporateUserGroups = [ const masterCorporateUserGroups = [...new Set(groups.filter((u) => u.admin === user.id).flatMap((g) => g.participants))];
...new Set(
groups.filter((u) => u.admin === user.id).flatMap((g) => g.participants)
),
];
const corporateUserGroups = [ const corporateUserGroups = [...new Set(groups.flatMap((g) => g.participants))];
...new Set(groups.flatMap((g) => g.participants)),
];
const { const {assignments, isLoading: isAssignmentsLoading, reload: reloadAssignments} = useAssignments({corporate: user.id});
assignments,
isLoading: isAssignmentsLoading,
reload: reloadAssignments,
} = useAssignments({ corporate: user.id });
const appendUserFilters = useFilterStore((state) => state.appendUserFilter); const appendUserFilters = useFilterStore((state) => state.appendUserFilter);
const router = useRouter(); const router = useRouter();
useEffect(() => { useEffect(() => {
setShowModal(!!selectedUser && page === ""); setShowModal(!!selectedUser && page === "");
}, [selectedUser, page]); }, [selectedUser, page]);
useEffect(() => { useEffect(() => {
setCorporateAssignments( setCorporateAssignments(
@@ -347,135 +337,117 @@ export default function MasterCorporateDashboard({user}: Props) {
const teacherFilter = (user: User) => user.type === "teacher" && corporateUserGroups.includes(user.id); const teacherFilter = (user: User) => user.type === "teacher" && corporateUserGroups.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);
const UserDisplay = (displayUser: User) => ( const UserDisplay = (displayUser: User) => (
<div <div
onClick={() => setSelectedUser(displayUser)} onClick={() => setSelectedUser(displayUser)}
className="flex w-full p-4 gap-4 items-center hover:bg-mti-purple-ultralight cursor-pointer transition ease-in-out duration-300" className="flex w-full p-4 gap-4 items-center hover:bg-mti-purple-ultralight cursor-pointer transition ease-in-out duration-300">
> <img src={displayUser.profilePicture} alt={displayUser.name} className="rounded-full w-10 h-10" />
<img <div className="flex flex-col gap-1 items-start">
src={displayUser.profilePicture} <span>{displayUser.name}</span>
alt={displayUser.name} <span className="text-sm opacity-75">{displayUser.email}</span>
className="rounded-full w-10 h-10" </div>
/> </div>
<div className="flex flex-col gap-1 items-start"> );
<span>{displayUser.name}</span>
<span className="text-sm opacity-75">{displayUser.email}</span>
</div>
</div>
);
const StudentsList = () => { const StudentsList = () => {
const filter = (x: User) => const filter = (x: User) =>
x.type === "student" && x.type === "student" && (!!selectedUser ? corporateUserGroups.includes(x.id) || false : corporateUserGroups.includes(x.id));
(!!selectedUser
? corporateUserGroups.includes(x.id) || false
: corporateUserGroups.includes(x.id));
return ( return (
<UserList <UserList
user={user} user={user}
filters={[filter]} filters={[filter]}
renderHeader={(total) => ( renderHeader={(total) => (
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<div <div
onClick={() => setPage("")} onClick={() => setPage("")}
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300">
> <BsArrowLeft className="text-xl" />
<BsArrowLeft className="text-xl" /> <span>Back</span>
<span>Back</span> </div>
</div> <h2 className="text-2xl font-semibold">Students ({total})</h2>
<h2 className="text-2xl font-semibold">Students ({total})</h2> </div>
</div> )}
)} />
/> );
); };
};
const TeachersList = () => { const TeachersList = () => {
const filter = (x: User) => const filter = (x: User) =>
x.type === "teacher" && x.type === "teacher" && (!!selectedUser ? corporateUserGroups.includes(x.id) || false : corporateUserGroups.includes(x.id));
(!!selectedUser
? corporateUserGroups.includes(x.id) || false
: corporateUserGroups.includes(x.id));
return ( return (
<UserList <UserList
user={user} user={user}
filters={[filter]} filters={[filter]}
renderHeader={(total) => ( renderHeader={(total) => (
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<div <div
onClick={() => setPage("")} onClick={() => setPage("")}
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300">
> <BsArrowLeft className="text-xl" />
<BsArrowLeft className="text-xl" /> <span>Back</span>
<span>Back</span> </div>
</div> <h2 className="text-2xl font-semibold">Teachers ({total})</h2>
<h2 className="text-2xl font-semibold">Teachers ({total})</h2> </div>
</div> )}
)} />
/> );
); };
};
const corporateUserFilter = (x: User) => const corporateUserFilter = (x: User) =>
x.type === "corporate" && x.type === "corporate" && (!!selectedUser ? masterCorporateUserGroups.includes(x.id) || false : masterCorporateUserGroups.includes(x.id));
(!!selectedUser
? masterCorporateUserGroups.includes(x.id) || false
: masterCorporateUserGroups.includes(x.id));
const CorporateList = () => { const CorporateList = () => {
return ( return (
<UserList <UserList
user={user} user={user}
filters={[corporateUserFilter]} filters={[corporateUserFilter]}
renderHeader={(total) => ( renderHeader={(total) => (
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<div <div
onClick={() => setPage("")} onClick={() => setPage("")}
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300">
> <BsArrowLeft className="text-xl" />
<BsArrowLeft className="text-xl" /> <span>Back</span>
<span>Back</span> </div>
</div> <h2 className="text-2xl font-semibold">Corporates ({total})</h2>
<h2 className="text-2xl font-semibold">Corporates ({total})</h2> </div>
</div> )}
)} />
/> );
); };
};
const GroupsList = () => { const GroupsList = () => {
return ( return (
<> <>
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<div <div
onClick={() => setPage("")} onClick={() => setPage("")}
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300">
> <BsArrowLeft className="text-xl" />
<BsArrowLeft className="text-xl" /> <span>Back</span>
<span>Back</span> </div>
</div> <h2 className="text-2xl font-semibold">Groups ({groups.length})</h2>
<h2 className="text-2xl font-semibold">Groups ({groups.length})</h2> </div>
</div>
<GroupList user={user} /> <GroupList user={user} />
</> </>
); );
}; };
// const AssignmentsPage = () => { // const AssignmentsPage = () => {
// const activeFilter = (a: Assignment) => // const activeFilter = (a: Assignment) =>
// moment(a.endDate).isAfter(moment()) && // moment(a.endDate).isAfter(moment()) &&
// moment(a.startDate).isBefore(moment()) && // moment(a.startDate).isBefore(moment()) &&
// a.assignees.length > a.results.length; // a.assignees.length > a.results.length;
// const pastFilter = (a: Assignment) => // const pastFilter = (a: Assignment) =>
// (moment(a.endDate).isBefore(moment()) || // (moment(a.endDate).isBefore(moment()) ||
// a.assignees.length === a.results.length) && // a.assignees.length === a.results.length) &&
// !a.archived; // !a.archived;
// const archivedFilter = (a: Assignment) => a.archived; // const archivedFilter = (a: Assignment) => a.archived;
// const futureFilter = (a: Assignment) => // const futureFilter = (a: Assignment) =>
// moment(a.startDate).isAfter(moment()); // moment(a.startDate).isAfter(moment());
const StudentPerformancePage = () => { const StudentPerformancePage = () => {
const students = users const students = users
@@ -614,7 +586,7 @@ export default function MasterCorporateDashboard({user}: Props) {
allowDownload allowDownload
reload={reloadAssignments} reload={reloadAssignments}
allowArchive allowArchive
allowExcelDownload allowExcelDownload
/> />
))} ))}
</div> </div>
@@ -631,7 +603,7 @@ export default function MasterCorporateDashboard({user}: Props) {
allowDownload allowDownload
reload={reloadAssignments} reload={reloadAssignments}
allowUnarchive allowUnarchive
allowExcelDownload allowExcelDownload
/> />
))} ))}
</div> </div>
@@ -640,32 +612,28 @@ export default function MasterCorporateDashboard({user}: Props) {
); );
}; };
const MasterStatisticalPage = () => { const MasterStatisticalPage = () => {
return ( return (
<> <>
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<div <div
onClick={() => setPage("")} onClick={() => setPage("")}
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300">
> <BsArrowLeft className="text-xl" />
<BsArrowLeft className="text-xl" /> <span>Back</span>
<span>Back</span> </div>
</div> <h2 className="text-2xl font-semibold">Master Statistical</h2>
<h2 className="text-2xl font-semibold">Master Statistical</h2> </div>
</div> <MasterStatistical
<MasterStatistical users={masterCorporateUserGroups.reduce((accm: CorporateUser[], id) => {
users={masterCorporateUserGroups.reduce( const user = users.find((u) => u.id === id) as CorporateUser;
(accm: CorporateUser[], id) => { if (user) return [...accm, user];
const user = users.find((u) => u.id === id) as CorporateUser; return accm;
if (user) return [...accm, user]; }, [])}
return accm; />
}, </>
[] );
)} };
/>
</>
);
};
const DefaultDashboard = () => ( const DefaultDashboard = () => (
<> <>
@@ -726,13 +694,13 @@ export default function MasterCorporateDashboard({user}: Props) {
color="purple" color="purple"
onClick={() => setPage("studentsPerformance")} onClick={() => setPage("studentsPerformance")}
/> />
<IconCard <IconCard
Icon={BsDatabase} Icon={BsDatabase}
label="Master Statistical" label="Master Statistical"
// value={masterCorporateUserGroups.length} // value={masterCorporateUserGroups.length}
color="purple" color="purple"
onClick={() => setPage("statistical")} onClick={() => setPage("statistical")}
/> />
<button <button
disabled={isAssignmentsLoading} disabled={isAssignmentsLoading}
onClick={() => setPage("assignments")} onClick={() => setPage("assignments")}
@@ -747,120 +715,105 @@ export default function MasterCorporateDashboard({user}: Props) {
</button> </button>
</section> </section>
<section className="grid grid-cols-1 md:grid-cols-2 gap-4 w-full justify-between"> <section className="grid grid-cols-1 md:grid-cols-2 gap-4 w-full justify-between">
<div className="bg-white shadow flex flex-col rounded-xl w-full"> <div className="bg-white shadow flex flex-col rounded-xl w-full">
<span className="p-4">Latest students</span> <span className="p-4">Latest students</span>
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide"> <div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
{users {users
.filter(studentFilter) .filter(studentFilter)
.sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) .sort((a, b) => dateSorter(a, b, "desc", "registrationDate"))
.map((x) => ( .map((x) => (
<UserDisplay key={x.id} {...x} /> <UserDisplay key={x.id} {...x} />
))} ))}
</div> </div>
</div> </div>
<div className="bg-white shadow flex flex-col rounded-xl w-full"> <div className="bg-white shadow flex flex-col rounded-xl w-full">
<span className="p-4">Latest teachers</span> <span className="p-4">Latest teachers</span>
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide"> <div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
{users {users
.filter(teacherFilter) .filter(teacherFilter)
.sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) .sort((a, b) => dateSorter(a, b, "desc", "registrationDate"))
.map((x) => ( .map((x) => (
<UserDisplay key={x.id} {...x} /> <UserDisplay key={x.id} {...x} />
))} ))}
</div> </div>
</div> </div>
<div className="bg-white shadow flex flex-col rounded-xl w-full"> <div className="bg-white shadow flex flex-col rounded-xl w-full">
<span className="p-4">Highest level students</span> <span className="p-4">Highest level students</span>
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide"> <div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
{users {users
.filter(studentFilter) .filter(studentFilter)
.sort( .sort((a, b) => calculateAverageLevel(b.levels) - calculateAverageLevel(a.levels))
(a, b) => .map((x) => (
calculateAverageLevel(b.levels) - <UserDisplay key={x.id} {...x} />
calculateAverageLevel(a.levels) ))}
) </div>
.map((x) => ( </div>
<UserDisplay key={x.id} {...x} /> <div className="bg-white shadow flex flex-col rounded-xl w-full">
))} <span className="p-4">Highest exam count students</span>
</div> <div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
</div> {users
<div className="bg-white shadow flex flex-col rounded-xl w-full"> .filter(studentFilter)
<span className="p-4">Highest exam count students</span> .sort(
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide"> (a, b) =>
{users Object.keys(groupByExam(getStatsByStudent(b))).length - Object.keys(groupByExam(getStatsByStudent(a))).length,
.filter(studentFilter) )
.sort( .map((x) => (
(a, b) => <UserDisplay key={x.id} {...x} />
Object.keys(groupByExam(getStatsByStudent(b))).length - ))}
Object.keys(groupByExam(getStatsByStudent(a))).length </div>
) </div>
.map((x) => ( </section>
<UserDisplay key={x.id} {...x} /> </>
))} );
</div>
</div>
</section>
</>
);
return ( return (
<> <>
<Modal isOpen={showModal} onClose={() => setSelectedUser(undefined)}> <Modal isOpen={showModal} onClose={() => setSelectedUser(undefined)}>
<> <>
{selectedUser && ( {selectedUser && (
<div className="w-full flex flex-col gap-8"> <div className="w-full flex flex-col gap-8">
<UserCard <UserCard
loggedInUser={user} loggedInUser={user}
onClose={(shouldReload) => { onClose={(shouldReload) => {
setSelectedUser(undefined); setSelectedUser(undefined);
if (shouldReload) reload(); if (shouldReload) reload();
}} }}
onViewStudents={ onViewStudents={
selectedUser.type === "corporate" || selectedUser.type === "corporate" || selectedUser.type === "teacher"
selectedUser.type === "teacher" ? () => {
? () => { appendUserFilters({
appendUserFilters({ id: "view-students",
id: "view-students", filter: (x: User) => x.type === "student",
filter: (x: User) => x.type === "student", });
}); appendUserFilters({
appendUserFilters({ id: "belongs-to-admin",
id: "belongs-to-admin", filter: (x: User) =>
filter: (x: User) => groups
groups .filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id))
.filter( .flatMap((g) => g.participants)
(g) => .includes(x.id),
g.admin === selectedUser.id || });
g.participants.includes(selectedUser.id)
)
.flatMap((g) => g.participants)
.includes(x.id),
});
router.push("/list/users"); router.push("/list/users");
} }
: undefined : undefined
} }
onViewTeachers={ onViewTeachers={
selectedUser.type === "corporate" || selectedUser.type === "corporate" || selectedUser.type === "student"
selectedUser.type === "student" ? () => {
? () => { appendUserFilters({
appendUserFilters({ id: "view-teachers",
id: "view-teachers", filter: (x: User) => x.type === "teacher",
filter: (x: User) => x.type === "teacher", });
}); appendUserFilters({
appendUserFilters({ id: "belongs-to-admin",
id: "belongs-to-admin", filter: (x: User) =>
filter: (x: User) => groups
groups .filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id))
.filter( .flatMap((g) => g.participants)
(g) => .includes(x.id),
g.admin === selectedUser.id || });
g.participants.includes(selectedUser.id)
)
.flatMap((g) => g.participants)
.includes(x.id),
});
router.push("/list/users"); router.push("/list/users");
} }
@@ -878,7 +831,7 @@ export default function MasterCorporateDashboard({user}: Props) {
{page === "corporate" && <CorporateList />} {page === "corporate" && <CorporateList />}
{page === "assignments" && <AssignmentsPage />} {page === "assignments" && <AssignmentsPage />}
{page === "studentsPerformance" && <StudentPerformancePage />} {page === "studentsPerformance" && <StudentPerformancePage />}
{page === "statistical" && <MasterStatisticalPage />} {page === "statistical" && <MasterStatisticalPage />}
{page === "" && <DefaultDashboard />} {page === "" && <DefaultDashboard />}
</> </>
); );

View File

@@ -1,94 +1,78 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from "next"; import type {NextApiRequest, NextApiResponse} from "next";
import { app } from "@/firebase"; import {app} from "@/firebase";
import { import {getFirestore, collection, getDocs, setDoc, doc, query, where} from "firebase/firestore";
getFirestore, import {withIronSessionApiRoute} from "iron-session/next";
collection, import {sessionOptions} from "@/lib/session";
getDocs, import {Group} from "@/interfaces/user";
setDoc, import {v4} from "uuid";
doc, import {updateExpiryDateOnGroup, getGroupsForUser} from "@/utils/groups.be";
query,
where,
} from "firebase/firestore";
import { withIronSessionApiRoute } from "iron-session/next";
import { sessionOptions } from "@/lib/session";
import { Group } from "@/interfaces/user";
import { v4 } from "uuid";
import { updateExpiryDateOnGroup, getGroupsForUser } from "@/utils/groups.be";
const db = getFirestore(app); const db = getFirestore(app);
export default withIronSessionApiRoute(handler, sessionOptions); export default withIronSessionApiRoute(handler, sessionOptions);
async function handler(req: NextApiRequest, res: NextApiResponse) { async function handler(req: NextApiRequest, res: NextApiResponse) {
if (!req.session.user) { if (!req.session.user) {
res.status(401).json({ ok: false }); res.status(401).json({ok: false});
return; return;
} }
if (req.method === "GET") await get(req, res); if (req.method === "GET") await get(req, res);
if (req.method === "POST") await post(req, res); if (req.method === "POST") await post(req, res);
} }
async function get(req: NextApiRequest, res: NextApiResponse) { async function get(req: NextApiRequest, res: NextApiResponse) {
const { admin, participant } = req.query as { const {admin, participant} = req.query as {
admin: string; admin: string;
participant: string; participant: string;
}; };
if (req.session?.user?.type === "mastercorporate") { if (req.session?.user?.type === "mastercorporate") {
try { try {
const masterCorporateGroups = await getGroupsForUser(admin, participant); const masterCorporateGroups = await getGroupsForUser(admin, participant);
const corporatesFromMaster = masterCorporateGroups const corporatesFromMaster = masterCorporateGroups.filter((g) => g.name === "Corporate").flatMap((g) => g.participants);
.filter((g) => g.name === "Corporate")
.flatMap((g) => g.participants);
if (corporatesFromMaster.length === 0) { if (corporatesFromMaster.length === 0) {
res.status(200).json([]); res.status(200).json(masterCorporateGroups);
return; return;
} }
Promise.all( Promise.all(corporatesFromMaster.map((c) => getGroupsForUser(c, participant)))
corporatesFromMaster.map((c) => getGroupsForUser(c, participant)) .then((groups) => {
) res.status(200).json([...masterCorporateGroups, ...groups.flat()]);
.then((groups) => { return;
res.status(200).json([...masterCorporateGroups, ...groups.flat()]); })
return; .catch((e) => {
}) console.error(e);
.catch((e) => { res.status(500).json({ok: false});
console.error(e); return;
res.status(500).json({ ok: false }); });
return; } catch (e) {
}); console.error(e);
} catch (e) { res.status(500).json({ok: false});
console.error(e); return;
res.status(500).json({ ok: false }); }
return; return;
} }
return;
}
try { try {
const groups = await getGroupsForUser(admin, participant); const groups = await getGroupsForUser(admin, participant);
res.status(200).json(groups); res.status(200).json(groups);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
res.status(500).json({ ok: false }); res.status(500).json({ok: false});
} }
} }
async function post(req: NextApiRequest, res: NextApiResponse) { async function post(req: NextApiRequest, res: NextApiResponse) {
const body = req.body as Group; const body = req.body as Group;
await Promise.all( await Promise.all(body.participants.map(async (p) => await updateExpiryDateOnGroup(p, body.admin)));
body.participants.map(
async (p) => await updateExpiryDateOnGroup(p, body.admin)
)
);
await setDoc(doc(db, "groups", v4()), { await setDoc(doc(db, "groups", v4()), {
name: body.name, name: body.name,
admin: body.admin, admin: body.admin,
participants: body.participants, participants: body.participants,
}); });
res.status(200).json({ ok: true }); res.status(200).json({ok: true});
} }