From 34c1041182569f416b0710cd5a935a24660a3cf3 Mon Sep 17 00:00:00 2001 From: Tiago Ribeiro Date: Thu, 11 Jan 2024 23:10:51 +0000 Subject: [PATCH 1/7] Hard coded the CORS for the EnCoach website --- next.config.js | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/next.config.js b/next.config.js index 6eefe6ab..4a6bb16f 100644 --- a/next.config.js +++ b/next.config.js @@ -1,27 +1,26 @@ /** @type {import('next').NextConfig} */ const nextConfig = { - reactStrictMode: true, - output: "standalone", - async headers() { - return [ - { - source: "/api/packages", - headers: [ - { key: "Access-Control-Allow-Credentials", value: "false" }, - { key: "Access-Control-Allow-Origin", value: process.env.WEBSITE_URL }, - { - key: "Access-Control-Allow-Methods", - value: "GET", - }, - { - key: "Access-Control-Allow-Headers", - value: - "Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date", - }, - ], - }, - ]; - }, + reactStrictMode: true, + output: "standalone", + async headers() { + return [ + { + source: "/api/packages", + headers: [ + {key: "Access-Control-Allow-Credentials", value: "false"}, + {key: "Access-Control-Allow-Origin", value: "https://encoach.com"}, + { + key: "Access-Control-Allow-Methods", + value: "GET", + }, + { + key: "Access-Control-Allow-Headers", + value: "Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date", + }, + ], + }, + ]; + }, }; module.exports = nextConfig; From bb1a2e477a77cb4ef646d088f178b349581716aa Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Thu, 11 Jan 2024 23:56:23 +0000 Subject: [PATCH 2/7] Revert "Removed references to Referred corporated" This reverts commit 21b612eaa4cb904220a9a8d75750f5d1be969938. --- src/dashboards/Agent.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/dashboards/Agent.tsx b/src/dashboards/Agent.tsx index dbfb56cc..43ed0f88 100644 --- a/src/dashboards/Agent.tsx +++ b/src/dashboards/Agent.tsx @@ -66,7 +66,7 @@ export default function AgentDashboard({user}: Props) { Back -

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

+

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

@@ -84,7 +84,7 @@ export default function AgentDashboard({user}: Props) { Back -

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

+

Inactive Referred Corporate ({users.filter(inactiveReferredCorporateFilter).length})

@@ -104,7 +104,7 @@ export default function AgentDashboard({user}: Props) { Back -

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

+

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

@@ -118,14 +118,14 @@ export default function AgentDashboard({user}: Props) { setPage("referredCorporate")} Icon={BsPersonFill} - label="Corporate" + label="Referred Corporate" value={users.filter(referredCorporateFilter).length} color="purple" /> setPage("inactiveReferredCorporate")} Icon={BsPersonFill} - label="Inactive Corporate" + label="Inactive Referred Corporate" value={users.filter(inactiveReferredCorporateFilter).length} color="rose" /> @@ -140,7 +140,7 @@ export default function AgentDashboard({user}: Props) {
- Latest Corporate + Latest Referred Corporate
{users .filter(referredCorporateFilter) @@ -162,7 +162,7 @@ export default function AgentDashboard({user}: Props) {
- Corporate expiring in 1 month + Referenced corporate expiring in 1 month
{users .filter( From 39ea11bc9b1a7d3b8324a6d3b42bebba4fc96617 Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Fri, 12 Jan 2024 00:20:03 +0000 Subject: [PATCH 3/7] Fixed naming of the table --- src/dashboards/Agent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dashboards/Agent.tsx b/src/dashboards/Agent.tsx index 43ed0f88..c2dcff5d 100644 --- a/src/dashboards/Agent.tsx +++ b/src/dashboards/Agent.tsx @@ -104,7 +104,7 @@ export default function AgentDashboard({user}: Props) { Back
-

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

+

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

From 5379cdb0d204ca34956cacfa592faee14627c42f Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Fri, 12 Jan 2024 00:23:18 +0000 Subject: [PATCH 4/7] Blocked corporate user edit for corporate --- src/dashboards/Agent.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/dashboards/Agent.tsx b/src/dashboards/Agent.tsx index c2dcff5d..943a5742 100644 --- a/src/dashboards/Agent.tsx +++ b/src/dashboards/Agent.tsx @@ -40,9 +40,9 @@ export default function AgentDashboard({user}: Props) { const inactiveReferredCorporateFilter = (x: User) => referredCorporateFilter(x) && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)); - const UserDisplay = (displayUser: User) => ( + const UserDisplay = ({ displayUser, allowClick = true }: {displayUser: User, allowClick?: boolean}) => (
setSelectedUser(displayUser)} + onClick={() => allowClick && 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"> {displayUser.name}
@@ -146,7 +146,7 @@ export default function AgentDashboard({user}: Props) { .filter(referredCorporateFilter) .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) .map((x) => ( - + ))}
@@ -157,7 +157,7 @@ export default function AgentDashboard({user}: Props) { .filter(corporateFilter) .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) .map((x) => ( - + ))} @@ -172,7 +172,7 @@ export default function AgentDashboard({user}: Props) { moment().isBefore(moment(x.subscriptionExpirationDate)), ) .map((x) => ( - + ))} From 7714854338ccfbac7c62348629a1d6c256e83f19 Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Fri, 12 Jan 2024 00:25:14 +0000 Subject: [PATCH 5/7] Changed all corporate icons --- src/dashboards/Admin.tsx | 2 +- src/dashboards/Agent.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dashboards/Admin.tsx b/src/dashboards/Admin.tsx index b91291d7..c72550b0 100644 --- a/src/dashboards/Admin.tsx +++ b/src/dashboards/Admin.tsx @@ -260,7 +260,7 @@ export default function AdminDashboard({user}: Props) { /> setPage("inactiveCorporate")} - Icon={BsPerson} + Icon={BsBank} label="Inactive Corporate" value={ users.filter((x) => x.type === "corporate" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate))) diff --git a/src/dashboards/Agent.tsx b/src/dashboards/Agent.tsx index 943a5742..3affaffe 100644 --- a/src/dashboards/Agent.tsx +++ b/src/dashboards/Agent.tsx @@ -117,14 +117,14 @@ export default function AgentDashboard({user}: Props) {
setPage("referredCorporate")} - Icon={BsPersonFill} + Icon={BsBank} label="Referred Corporate" value={users.filter(referredCorporateFilter).length} color="purple" /> setPage("inactiveReferredCorporate")} - Icon={BsPersonFill} + Icon={BsBank} label="Inactive Referred Corporate" value={users.filter(inactiveReferredCorporateFilter).length} color="rose" From cb91acdded9a98655a17adf2a0013a1b941c5601 Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Fri, 12 Jan 2024 00:32:02 +0000 Subject: [PATCH 6/7] Removed some horizontal margins on PDFs --- src/exams/pdf/group.test.report.tsx | 10 ++++------ src/exams/pdf/styles.ts | 4 ++-- src/exams/pdf/test.report.footer.tsx | 25 +++++++++++++++---------- src/exams/pdf/test.report.tsx | 16 +++++++--------- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/exams/pdf/group.test.report.tsx b/src/exams/pdf/group.test.report.tsx index 9b0d0405..4b865494 100644 --- a/src/exams/pdf/group.test.report.tsx +++ b/src/exams/pdf/group.test.report.tsx @@ -103,13 +103,13 @@ const GroupTestReport = ({ {title} - + Date of Test: {date} Candidate Information: - + Name: {name} ID: {id} Email: {email} @@ -193,10 +193,8 @@ const GroupTestReport = ({ ]} key={label} > - - {label} - - + {label} + ( - - + + Validity @@ -52,4 +57,4 @@ const TestReportFooter = () => ( ); -export default TestReportFooter; \ No newline at end of file +export default TestReportFooter; diff --git a/src/exams/pdf/test.report.tsx b/src/exams/pdf/test.report.tsx index 34ceddc7..acd14481 100644 --- a/src/exams/pdf/test.report.tsx +++ b/src/exams/pdf/test.report.tsx @@ -68,19 +68,19 @@ const TestReport = ({ {title} - + Date of Test: {date} Candidate Information: - + Name: {name} ID: {id} Email: {email} Gender: {gender} - + {testDetails - .filter(({ suggestions, evaluation }) => suggestions || evaluation) + .filter( + ({ suggestions, evaluation }) => suggestions || evaluation + ) .map(({ module, suggestions, evaluation }) => ( @@ -139,15 +141,11 @@ const TestReport = ({ {evaluation} {suggestions} - ))} - + From 27a4014f635f99ae6ba7f3557e7a97c4d08d1de9 Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Fri, 12 Jan 2024 01:38:34 +0000 Subject: [PATCH 7/7] Added payment done and pending --- src/dashboards/Agent.tsx | 47 ++++++++++++++--- src/hooks/usePaymentStatusUsers.tsx | 20 +++++++ src/interfaces/user.payments.ts | 5 ++ src/pages/api/payments/assigned.ts | 81 +++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+), 7 deletions(-) create mode 100644 src/hooks/usePaymentStatusUsers.tsx create mode 100644 src/interfaces/user.payments.ts create mode 100644 src/pages/api/payments/assigned.ts diff --git a/src/dashboards/Agent.tsx b/src/dashboards/Agent.tsx index dbfb56cc..bf925114 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)], + }); +}