diff --git a/src/dashboards/Agent.tsx b/src/dashboards/Agent.tsx index 3affaffe..b32158c4 100644 --- a/src/dashboards/Agent.tsx +++ b/src/dashboards/Agent.tsx @@ -2,20 +2,17 @@ import Modal from "@/components/Modal"; import useStats from "@/hooks/useStats"; import useUsers from "@/hooks/useUsers"; -import {Group, Stat, User} from "@/interfaces/user"; +import { User} from "@/interfaces/user"; import UserList from "@/pages/(admin)/Lists/UserList"; import {dateSorter} from "@/utils"; import moment from "moment"; import {useEffect, useState} from "react"; -import {BsArrowLeft, BsPersonFill, BsBank} from "react-icons/bs"; +import {BsArrowLeft, BsPersonFill, BsBank, BsCurrencyDollar} from "react-icons/bs"; import UserCard from "@/components/UserCard"; import useGroups from "@/hooks/useGroups"; -import {calculateAverageLevel, calculateBandScore} from "@/utils/score"; -import {MODULE_ARRAY} from "@/utils/moduleUtils"; -import {Module} from "@/interfaces"; -import {groupByExam} from "@/utils/stats"; + import IconCard from "./IconCard"; -import GroupList from "@/pages/(admin)/Lists/GroupList"; +import usePaymentStatusUsers from '@/hooks/usePaymentStatusUsers'; interface Props { user: User; @@ -29,6 +26,7 @@ export default function AgentDashboard({user}: Props) { const {stats} = useStats(); const {users, reload} = useUsers(); const {groups} = useGroups(user.id); + const { pending, done } = usePaymentStatusUsers(); useEffect(() => { setShowModal(!!selectedUser && page === ""); @@ -106,7 +104,26 @@ export default function AgentDashboard({user}: Props) {

Corporate ({users.filter(filter).length})

+ + + ); + }; + const CorporatePaidStatusList = ({ paid }: {paid: Boolean}) => { + const list = paid ? done : pending; + const filter = (x: User) => x.type === "corporate" && list.includes(x.id); + + return ( + <> +
+
setPage("")} + className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> + + Back +
+

{paid ? 'Payment Done' : 'Pending Payment'} ({list.length})

+
); @@ -136,6 +153,20 @@ export default function AgentDashboard({user}: Props) { value={users.filter(corporateFilter).length} color="purple" /> + setPage("paymentdone")} + Icon={BsCurrencyDollar} + label="Payment Done" + value={done.length} + color="purple" + /> + setPage("paymentdone")} + Icon={BsCurrencyDollar} + label="Pending Payment" + value={pending.length} + color="rose" + />
@@ -205,6 +236,8 @@ export default function AgentDashboard({user}: Props) { {page === "referredCorporate" && } {page === "corporate" && } {page === "inactiveReferredCorporate" && } + {page === "paymentdone" && } + {page === "paymentpending" && } {page === "" && } ); diff --git a/src/hooks/usePaymentStatusUsers.tsx b/src/hooks/usePaymentStatusUsers.tsx new file mode 100644 index 00000000..5b2bbd94 --- /dev/null +++ b/src/hooks/usePaymentStatusUsers.tsx @@ -0,0 +1,20 @@ +import axios from "axios"; +import { useEffect, useState } from "react"; +import { PaymentsStatus } from "@/interfaces/user.payments"; + +export default function usePaymentStatusUsers() { + const [{ pending, done }, setStatus] = useState({ + pending: [], + done: [], + }); + + const getData = () => { + axios.get("/api/payments/assigned").then((response) => { + setStatus(response.data); + }); + }; + + useEffect(getData, []); + + return { pending, done }; +} diff --git a/src/interfaces/user.payments.ts b/src/interfaces/user.payments.ts new file mode 100644 index 00000000..c555b919 --- /dev/null +++ b/src/interfaces/user.payments.ts @@ -0,0 +1,5 @@ +// these arrays contain the ids of the corporates that have paid or not paid +export interface PaymentsStatus { + pending: string[]; + done: string[]; +} \ No newline at end of file diff --git a/src/pages/api/payments/assigned.ts b/src/pages/api/payments/assigned.ts new file mode 100644 index 00000000..107e619e --- /dev/null +++ b/src/pages/api/payments/assigned.ts @@ -0,0 +1,81 @@ +// Next.js API route support: https://nextjs.org/docs/api-routes/introduction +import type { NextApiRequest, NextApiResponse } from "next"; +import { app } from "@/firebase"; +import { + getFirestore, + collection, + getDocs, + query, + where, +} from "firebase/firestore"; +import { withIronSessionApiRoute } from "iron-session/next"; +import { sessionOptions } from "@/lib/session"; +import { Payment } from "@/interfaces/paypal"; +import { PaymentsStatus } from "@/interfaces/user.payments"; + +const db = getFirestore(app); + +export default withIronSessionApiRoute(handler, sessionOptions); + +async function handler(req: NextApiRequest, res: NextApiResponse) { + if (req.method === "GET") return await get(req, res); + + res.status(404).json(undefined); +} + +// user can fetch payments assigned to him as an agent +async function get(req: NextApiRequest, res: NextApiResponse) { + if (!req.session.user) { + res.status(401).json({ ok: false }); + return; + } + + const codeQuery = query( + collection(db, "payments"), + // where("agent", "==", "xRMirufz6PPQqxKBgvPTWiWKBD63"), + where(req.session.user.type, "==", req.session.user.id) + // Based on the logic of query we should be able to do this: + // where("isPaid", "==", paid === "paid"), + // but for some reason it is ignoring all but the first clause + // I opted into only fetching relevant content for the user + // and then filter it with JS + ); + + const snapshot = await getDocs(codeQuery); + if (snapshot.empty) { + res.status(200).json({ + pending: [], + done: [], + }); + return; + } + + const docs = snapshot.docs.map((doc) => ({ + id: doc.id, + ...doc.data(), + })) as Payment[]; + + const paidStatusEntries = docs.reduce( + (acc: PaymentsStatus, doc) => { + if (doc.isPaid) { + return { + ...acc, + done: [...acc.done, doc.corporate], + }; + } + + return { + ...acc, + pending: [...acc.pending, doc.corporate], + }; + }, + { + pending: [], + done: [], + } + ); + res.status(200).json({ + pending: [...new Set(paidStatusEntries.pending)], + done: [...new Set(paidStatusEntries.done)], + }); +}