From 8eb8a7af46aef812707173c67a4ffe00658320b1 Mon Sep 17 00:00:00 2001 From: Tiago Ribeiro Date: Sat, 20 Jan 2024 15:09:42 +0000 Subject: [PATCH] Added a new card for the Corporate to show their user balance --- src/dashboards/Corporate.tsx | 17 ++++++++++++++--- src/dashboards/IconCard.tsx | 9 +++++++-- src/dashboards/Teacher.tsx | 3 ++- src/hooks/useCodes.tsx | 21 +++++++++++++++++++++ src/interfaces/user.ts | 11 +++++++++++ src/pages/api/code/index.ts | 20 ++++++++++++++++++++ 6 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 src/hooks/useCodes.tsx diff --git a/src/dashboards/Corporate.tsx b/src/dashboards/Corporate.tsx index 600d0f89..49bad1e8 100644 --- a/src/dashboards/Corporate.tsx +++ b/src/dashboards/Corporate.tsx @@ -2,7 +2,7 @@ import Modal from "@/components/Modal"; import useStats from "@/hooks/useStats"; import useUsers from "@/hooks/useUsers"; -import {Group, Stat, User} from "@/interfaces/user"; +import {CorporateUser, Group, Stat, User} from "@/interfaces/user"; import UserList from "@/pages/(admin)/Lists/UserList"; import {dateSorter} from "@/utils"; import moment from "moment"; @@ -20,6 +20,9 @@ import { BsPersonFillGear, BsPersonGear, BsPencilSquare, + BsPersonBadge, + BsPersonCheck, + BsPeople, } from "react-icons/bs"; import UserCard from "@/components/UserCard"; import useGroups from "@/hooks/useGroups"; @@ -31,9 +34,10 @@ import IconCard from "./IconCard"; import GroupList from "@/pages/(admin)/Lists/GroupList"; import useFilterStore from "@/stores/listFilterStore"; import {useRouter} from "next/router"; +import useCodes from "@/hooks/useCodes"; interface Props { - user: User; + user: CorporateUser; } export default function CorporateDashboard({user}: Props) { @@ -43,6 +47,7 @@ export default function CorporateDashboard({user}: Props) { const {stats} = useStats(); const {users, reload} = useUsers(); + const {codes} = useCodes(user.id); const {groups} = useGroups(user.id); const appendUserFilters = useFilterStore((state) => state.appendUserFilter); @@ -187,7 +192,13 @@ export default function CorporateDashboard({user}: Props) { value={averageLevelCalculator(stats.filter((s) => groups.flatMap((g) => g.participants).includes(s.user))).toFixed(1)} color="purple" /> - setPage("groups")} Icon={BsPersonAdd} label="Groups" value={groups.length} color="purple" /> + setPage("groups")} Icon={BsPeople} label="Groups" value={groups.length} color="purple" /> + void; } -export default function IconCard({Icon, label, value, color, onClick}: Props) { +export default function IconCard({Icon, label, value, color, tooltip, onClick}: Props) { const colorClasses: {[key in typeof color]: string} = { purple: "text-mti-purple-light", red: "text-mti-red-light", @@ -19,7 +20,11 @@ export default function IconCard({Icon, label, value, color, onClick}: Props) { return (
+ className={clsx( + "bg-white rounded-xl shadow p-4 flex flex-col gap-4 items-center text-center w-52 h-52 justify-center cursor-pointer hover:shadow-xl transition ease-in-out duration-300", + tooltip && "tooltip tooltip-bottom", + )} + data-tip={tooltip}> {label} diff --git a/src/dashboards/Teacher.tsx b/src/dashboards/Teacher.tsx index be616639..e40d5a28 100644 --- a/src/dashboards/Teacher.tsx +++ b/src/dashboards/Teacher.tsx @@ -19,6 +19,7 @@ import { BsEnvelopePaper, BsGlobeCentralSouthAsia, BsPaperclip, + BsPeople, BsPerson, BsPersonAdd, BsPersonFill, @@ -271,7 +272,7 @@ export default function TeacherDashboard({user}: Props) { value={averageLevelCalculator(stats.filter((s) => groups.flatMap((g) => g.participants).includes(s.user))).toFixed(1)} color="purple" /> - setPage("groups")} /> + setPage("groups")} />
setPage("assignments")} className="bg-white rounded-xl shadow p-4 flex flex-col gap-4 items-center w-96 h-52 justify-center cursor-pointer hover:shadow-xl transition ease-in-out duration-300"> diff --git a/src/hooks/useCodes.tsx b/src/hooks/useCodes.tsx new file mode 100644 index 00000000..b88416a1 --- /dev/null +++ b/src/hooks/useCodes.tsx @@ -0,0 +1,21 @@ +import {Code, Group, User} from "@/interfaces/user"; +import axios from "axios"; +import {useEffect, useState} from "react"; + +export default function useCodes(creator?: string) { + const [codes, setCodes] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [isError, setIsError] = useState(false); + + const getData = () => { + setIsLoading(true); + axios + .get(`/api/code${creator ? `?creator=${creator}` : ""}`) + .then((response) => setCodes(response.data)) + .finally(() => setIsLoading(false)); + }; + + useEffect(getData, [creator]); + + return {codes, isLoading, isError, reload: getData}; +} diff --git a/src/interfaces/user.ts b/src/interfaces/user.ts index dec052ef..b14bf510 100644 --- a/src/interfaces/user.ts +++ b/src/interfaces/user.ts @@ -127,5 +127,16 @@ export interface Group { disableEditing?: boolean; } +export interface Code { + code: string; + creator: string; + expiryDate: Date; + type: Type; + userId?: string; + email?: string; + name?: string; + passport_id?: string; +} + export type Type = "student" | "teacher" | "corporate" | "admin" | "developer" | "agent"; export const userTypes: Type[] = ["student", "teacher", "corporate", "admin", "developer", "agent"]; diff --git a/src/pages/api/code/index.ts b/src/pages/api/code/index.ts index 2e315cb6..39787f11 100644 --- a/src/pages/api/code/index.ts +++ b/src/pages/api/code/index.ts @@ -14,6 +14,26 @@ const db = getFirestore(app); export default withIronSessionApiRoute(handler, sessionOptions); async function handler(req: NextApiRequest, res: NextApiResponse) { + if (req.method === "GET") return get(req, res); + if (req.method === "POST") return post(req, res); + + return res.status(404).json({ok: false}); +} + +async function get(req: NextApiRequest, res: NextApiResponse) { + if (!req.session.user) { + res.status(401).json({ok: false, reason: "You must be logged in to generate a code!"}); + return; + } + + const {creator} = req.query as {creator?: string}; + const q = query(collection(db, "codes"), where("creator", "==", creator)); + const snapshot = await getDocs(creator ? q : collection(db, "codes")); + + res.status(200).json(snapshot.docs.map((doc) => doc.data())); +} + +async function post(req: NextApiRequest, res: NextApiResponse) { if (!req.session.user) { res.status(401).json({ok: false, reason: "You must be logged in to generate a code!"}); return;