diff --git a/src/email/templates/assignment.handlebars b/src/email/templates/assignment.handlebars index d4a0752e..4774de28 100644 --- a/src/email/templates/assignment.handlebars +++ b/src/email/templates/assignment.handlebars @@ -19,7 +19,7 @@


Don't forget to do it before its end date!

-

Click here to open the EnCoach Platform!

+

Click here to open the EnCoach Platform!


Thanks,

Your EnCoach team

diff --git a/src/email/templates/main.handlebars b/src/email/templates/main.handlebars index c7ac02a1..77a0f501 100644 --- a/src/email/templates/main.handlebars +++ b/src/email/templates/main.handlebars @@ -11,7 +11,8 @@
Hello future {{type}} of EnCoach,
- You have been invited to register at EnCoach + You have been invited to register at EnCoach to become a {{type}}!
@@ -19,7 +20,7 @@


- + {{code}} diff --git a/src/email/templates/verification.handlebars b/src/email/templates/verification.handlebars index ebf387db..03a35498 100644 --- a/src/email/templates/verification.handlebars +++ b/src/email/templates/verification.handlebars @@ -10,7 +10,8 @@

Hello {{name}},


Follow this link to verify your email address.

- Verify account + Verify + account

If you didn’t ask to verify this address, you can ignore this email.

diff --git a/src/email/templates/verification.handlebars.json b/src/email/templates/verification.handlebars.json index 2fbb1fad..c415aa8f 100644 --- a/src/email/templates/verification.handlebars.json +++ b/src/email/templates/verification.handlebars.json @@ -1,5 +1,6 @@ { "name": "Tiago Ribeiro", "email": "tiago.ribeiro@ecrop.dev", - "code": "123" + "code": "123", + "environment": "platform" } \ No newline at end of file diff --git a/src/pages/action.tsx b/src/pages/action.tsx index f7564cd5..bee4552a 100644 --- a/src/pages/action.tsx +++ b/src/pages/action.tsx @@ -1,227 +1,170 @@ /* eslint-disable @next/next/no-img-element */ -import { toast, ToastContainer } from "react-toastify"; +import {toast, ToastContainer} from "react-toastify"; import axios from "axios"; -import { FormEvent, useEffect, useState } from "react"; +import {FormEvent, useEffect, useState} from "react"; import Head from "next/head"; import useUser from "@/hooks/useUser"; -import { Divider } from "primereact/divider"; +import {Divider} from "primereact/divider"; import Button from "@/components/Low/Button"; -import { BsArrowRepeat } from "react-icons/bs"; +import {BsArrowRepeat} from "react-icons/bs"; import Link from "next/link"; import Input from "@/components/Low/Input"; -import { useRouter } from "next/router"; +import {useRouter} from "next/router"; export function getServerSideProps({ - query, - res, + query, + res, }: { - query: { - oobCode: string; - mode: string; - continueUrl?: string; - }; - res: any; + query: { + oobCode: string; + mode: string; + continueUrl?: string; + }; + res: any; }) { - if (!query || !query.oobCode || !query.mode) { - res.setHeader("location", "/login"); - res.statusCode = 302; - res.end(); - return { - props: {}, - }; - } + if (!query || !query.oobCode || !query.mode) { + res.setHeader("location", "/login"); + res.statusCode = 302; + res.end(); + return { + props: {}, + }; + } - return { - props: { - code: query.oobCode, - mode: query.mode, - ...(query.continueUrl ? { continueUrl: query.continueUrl } : {}), - }, - }; + return { + props: { + code: query.oobCode, + mode: query.mode, + ...(query.continueUrl ? {continueUrl: query.continueUrl} : {}), + }, + }; } -export default function Reset({ - code, - mode, - continueUrl, -}: { - code: string; - mode: string; - continueUrl?: string; -}) { - const [password, setPassword] = useState(""); - const [isLoading, setIsLoading] = useState(false); +export default function Reset({code, mode, continueUrl}: {code: string; mode: string; continueUrl?: string}) { + const [password, setPassword] = useState(""); + const [isLoading, setIsLoading] = useState(false); - const router = useRouter(); + const router = useRouter(); - useUser({ - redirectTo: "/", - redirectIfFound: true, - }); + useUser({ + redirectTo: "/", + redirectIfFound: true, + }); - useEffect(() => { - if (mode === "signIn") { - axios - .post<{ ok: boolean }>("/api/reset/verify", { - email: continueUrl?.replace("https://platform.encoach.com/", ""), - }) - .then((response) => { - if (response.data.ok) { - toast.success("Your account has been verified!", { - toastId: "verify-successful", - }); - setTimeout(() => { - router.push("/"); - }, 1000); - return; - } + useEffect(() => { + if (mode === "signIn") { + axios + .post<{ok: boolean}>("/api/reset/verify", { + email: continueUrl?.replace("https://platform.encoach.com/", "").replace("https://staging.encoach.com/", ""), + }) + .then((response) => { + if (response.data.ok) { + toast.success("Your account has been verified!", { + toastId: "verify-successful", + }); + setTimeout(() => { + router.push("/"); + }, 1000); + return; + } - toast.error( - "Something went wrong! Please make sure to click the link in your e-mail again and input the correct e-mail!", - { - toastId: "verify-error", - }, - ); - }) - .catch(() => { - toast.error( - "Something went wrong! Please make sure to click the link in your e-mail again and input the correct e-mail!", - { - toastId: "verify-error", - }, - ); - setIsLoading(false); - }); - } - }); + toast.error("Something went wrong! Please make sure to click the link in your e-mail again and input the correct e-mail!", { + toastId: "verify-error", + }); + }) + .catch(() => { + toast.error("Something went wrong! Please make sure to click the link in your e-mail again and input the correct e-mail!", { + toastId: "verify-error", + }); + setIsLoading(false); + }); + } + }); - const login = (e: FormEvent) => { - e.preventDefault(); + const login = (e: FormEvent) => { + e.preventDefault(); - setIsLoading(true); - axios - .post<{ ok: boolean }>("/api/reset/confirm", { code, password }) - .then((response) => { - if (response.data.ok) { - toast.success("Your password has been reset!", { - toastId: "reset-successful", - }); - setTimeout(() => { - router.push("/login"); - }, 1000); - return; - } + setIsLoading(true); + axios + .post<{ok: boolean}>("/api/reset/confirm", {code, password}) + .then((response) => { + if (response.data.ok) { + toast.success("Your password has been reset!", { + toastId: "reset-successful", + }); + setTimeout(() => { + router.push("/login"); + }, 1000); + return; + } - toast.error( - "Something went wrong! Please make sure to click the link in your e-mail again!", - { toastId: "reset-error" }, - ); - }) - .catch(() => { - toast.error( - "Something went wrong! Please make sure to click the link in your e-mail again!", - { toastId: "reset-error" }, - ); - }) - .finally(() => setIsLoading(false)); - }; + toast.error("Something went wrong! Please make sure to click the link in your e-mail again!", {toastId: "reset-error"}); + }) + .catch(() => { + toast.error("Something went wrong! Please make sure to click the link in your e-mail again!", {toastId: "reset-error"}); + }) + .finally(() => setIsLoading(false)); + }; - return ( - <> - - Reset | EnCoach - - - - -
- -
-
- People smiling looking at a tablet -
- {mode === "resetPassword" && ( -
-
- EnCoach's Logo -

- Reset your password -

-

- to your registered Email Address -

-
- -
- setPassword(e)} - placeholder="Password" - /> + return ( + <> + + Reset | EnCoach + + + + +
+ +
+
+ People smiling looking at a tablet +
+ {mode === "resetPassword" && ( +
+
+ EnCoach's Logo +

Reset your password

+

to your registered Email Address

+
+ + + setPassword(e)} placeholder="Password" /> - - - - Don't have an account?{" "} - - Sign up - - -
- )} - {mode === "signIn" && ( -
-
- EnCoach's Logo -

- Confirm your account -

-

- to your registered Email Address -

-
- -
- - Your e-mail is currently being verified, please wait a second.{" "} -

- Once it has been verified, you will be redirected to the home - page. -
-
-
- )} -
- - ); + + + + Don't have an account?{" "} + + Sign up + + +
+ )} + {mode === "signIn" && ( +
+
+ EnCoach's Logo +

Confirm your account

+

to your registered Email Address

+
+ +
+ + Your e-mail is currently being verified, please wait a second.

+ Once it has been verified, you will be redirected to the home page. +
+
+
+ )} +
+ + ); } diff --git a/src/pages/api/assignments/index.ts b/src/pages/api/assignments/index.ts index 471b8376..4d0cc11a 100644 --- a/src/pages/api/assignments/index.ts +++ b/src/pages/api/assignments/index.ts @@ -163,6 +163,7 @@ async function POST(req: NextApiRequest, res: NextApiResponse) { modules: examModulesLabel, assigner: teacher.name, }, + environment: process.env.ENVIRONMENT, }, [assignee.email], "EnCoach - New Assignment!", diff --git a/src/pages/api/invites/accept/[id].ts b/src/pages/api/invites/accept/[id].ts index b12db506..20e8445e 100644 --- a/src/pages/api/invites/accept/[id].ts +++ b/src/pages/api/invites/accept/[id].ts @@ -113,6 +113,7 @@ async function get(req: NextApiRequest, res: NextApiResponse) { corporateName: invitedBy.name, name: req.session.user.name, decision: "accept", + environment: process.env.ENVIRONMENT, }, [invitedBy.email], `${req.session.user.name} has accepted your invite!`, diff --git a/src/pages/api/invites/decline/[id].ts b/src/pages/api/invites/decline/[id].ts index e8ab55a9..4110e70b 100644 --- a/src/pages/api/invites/decline/[id].ts +++ b/src/pages/api/invites/decline/[id].ts @@ -1,72 +1,62 @@ // Next.js API route support: https://nextjs.org/docs/api-routes/introduction -import type { NextApiRequest, NextApiResponse } from "next"; -import { app } from "@/firebase"; -import { - getFirestore, - getDoc, - doc, - deleteDoc, - setDoc, - getDocs, - collection, - where, - query, -} from "firebase/firestore"; -import { withIronSessionApiRoute } from "iron-session/next"; -import { sessionOptions } from "@/lib/session"; -import { Ticket } from "@/interfaces/ticket"; -import { Invite } from "@/interfaces/invite"; -import { Group, User } from "@/interfaces/user"; -import { v4 } from "uuid"; -import { sendEmail } from "@/email"; +import type {NextApiRequest, NextApiResponse} from "next"; +import {app} from "@/firebase"; +import {getFirestore, getDoc, doc, deleteDoc, setDoc, getDocs, collection, where, query} from "firebase/firestore"; +import {withIronSessionApiRoute} from "iron-session/next"; +import {sessionOptions} from "@/lib/session"; +import {Ticket} from "@/interfaces/ticket"; +import {Invite} from "@/interfaces/invite"; +import {Group, User} from "@/interfaces/user"; +import {v4} from "uuid"; +import {sendEmail} from "@/email"; 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); + if (req.method === "GET") return await get(req, res); - res.status(404).json(undefined); + res.status(404).json(undefined); } async function get(req: NextApiRequest, res: NextApiResponse) { - if (!req.session.user) { - res.status(401).json({ ok: false }); - return; - } + if (!req.session.user) { + res.status(401).json({ok: false}); + return; + } - const { id } = req.query as { id: string }; - const snapshot = await getDoc(doc(db, "invites", id)); + const {id} = req.query as {id: string}; + const snapshot = await getDoc(doc(db, "invites", id)); - if (snapshot.exists()) { - const invite = { ...snapshot.data(), id: snapshot.id } as Invite; - if (invite.to !== req.session.user.id) - return res.status(403).json({ ok: false }); + if (snapshot.exists()) { + const invite = {...snapshot.data(), id: snapshot.id} as Invite; + if (invite.to !== req.session.user.id) return res.status(403).json({ok: false}); - await deleteDoc(snapshot.ref); - const invitedByRef = await getDoc(doc(db, "users", invite.from)); - if (!invitedByRef.exists()) return res.status(404).json({ ok: false }); + await deleteDoc(snapshot.ref); + const invitedByRef = await getDoc(doc(db, "users", invite.from)); + if (!invitedByRef.exists()) return res.status(404).json({ok: false}); - const invitedBy = { ...invitedByRef.data(), id: invitedByRef.id } as User; + const invitedBy = {...invitedByRef.data(), id: invitedByRef.id} as User; - try { - await sendEmail( - "respondedInvite", - { - corporateName: invitedBy.name, - name: req.session.user.name, - decision: "decline", - }, - [invitedBy.email], - `${req.session.user.name} has declined your invite!`, - ); - } catch (e) { - console.log(e); - } + try { + await sendEmail( + "respondedInvite", + { + corporateName: invitedBy.name, + name: req.session.user.name, + decision: "decline", + environment: process.env.ENVIRONMENT, + }, + [invitedBy.email], + `${req.session.user.name} has declined your invite!`, + ); + } catch (e) { + console.log(e); + } - res.status(200).json({ ok: true }); - } else { - res.status(404).json(undefined); - } + res.status(200).json({ok: true}); + } else { + res.status(404).json(undefined); + } } diff --git a/src/pages/api/invites/index.ts b/src/pages/api/invites/index.ts index 023e6e2d..efc88d72 100644 --- a/src/pages/api/invites/index.ts +++ b/src/pages/api/invites/index.ts @@ -1,20 +1,13 @@ // Next.js API route support: https://nextjs.org/docs/api-routes/introduction -import { sendEmail } from "@/email"; -import { app } from "@/firebase"; -import { Invite } from "@/interfaces/invite"; -import { Ticket } from "@/interfaces/ticket"; -import { User } from "@/interfaces/user"; -import { sessionOptions } from "@/lib/session"; -import { - collection, - doc, - getDoc, - getDocs, - getFirestore, - setDoc, -} from "firebase/firestore"; -import { withIronSessionApiRoute } from "iron-session/next"; -import type { NextApiRequest, NextApiResponse } from "next"; +import {sendEmail} from "@/email"; +import {app} from "@/firebase"; +import {Invite} from "@/interfaces/invite"; +import {Ticket} from "@/interfaces/ticket"; +import {User} from "@/interfaces/user"; +import {sessionOptions} from "@/lib/session"; +import {collection, doc, getDoc, getDocs, getFirestore, setDoc} from "firebase/firestore"; +import {withIronSessionApiRoute} from "iron-session/next"; +import type {NextApiRequest, NextApiResponse} from "next"; import ShortUniqueId from "short-unique-id"; const db = getFirestore(app); @@ -22,67 +15,60 @@ const db = getFirestore(app); export default withIronSessionApiRoute(handler, sessionOptions); async function handler(req: NextApiRequest, res: NextApiResponse) { - if (!req.session.user) { - res.status(401).json({ ok: false }); - return; - } + if (!req.session.user) { + res.status(401).json({ok: false}); + return; + } - if (req.method === "GET") await get(req, res); - if (req.method === "POST") await post(req, res); + if (req.method === "GET") await get(req, res); + if (req.method === "POST") await post(req, res); } async function get(req: NextApiRequest, res: NextApiResponse) { - const snapshot = await getDocs(collection(db, "invites")); + const snapshot = await getDocs(collection(db, "invites")); - res.status(200).json( - snapshot.docs.map((doc) => ({ - id: doc.id, - ...doc.data(), - })), - ); + res.status(200).json( + snapshot.docs.map((doc) => ({ + id: doc.id, + ...doc.data(), + })), + ); } async function post(req: NextApiRequest, res: NextApiResponse) { - const body = req.body as Invite; + const body = req.body as Invite; - const existingInvites = (await getDocs(collection(db, "invites"))).docs.map( - (x) => ({ ...x.data(), id: x.id }), - ) as Invite[]; + const existingInvites = (await getDocs(collection(db, "invites"))).docs.map((x) => ({...x.data(), id: x.id})) as Invite[]; - const invitedRef = await getDoc(doc(db, "users", body.to)); - if (!invitedRef.exists()) return res.status(404).json({ ok: false }); + const invitedRef = await getDoc(doc(db, "users", body.to)); + if (!invitedRef.exists()) return res.status(404).json({ok: false}); - const invitedByRef = await getDoc(doc(db, "users", body.from)); - if (!invitedByRef.exists()) return res.status(404).json({ ok: false }); + const invitedByRef = await getDoc(doc(db, "users", body.from)); + if (!invitedByRef.exists()) return res.status(404).json({ok: false}); - const invited = { ...invitedRef.data(), id: invitedRef.id } as User; - const invitedBy = { ...invitedByRef.data(), id: invitedByRef.id } as User; + const invited = {...invitedRef.data(), id: invitedRef.id} as User; + const invitedBy = {...invitedByRef.data(), id: invitedByRef.id} as User; - try { - await sendEmail( - "receivedInvite", - { - name: invited.name, - corporateName: - invitedBy.type === "corporate" - ? invitedBy.corporateInformation?.companyInformation?.name || - invitedBy.name - : invitedBy.name, - }, - [invited.email], - "You have been invited to a group!", - ); - } catch (e) { - console.log(e); - } + try { + await sendEmail( + "receivedInvite", + { + name: invited.name, + corporateName: + invitedBy.type === "corporate" ? invitedBy.corporateInformation?.companyInformation?.name || invitedBy.name : invitedBy.name, + environment: process.env.ENVIRONMENT, + }, + [invited.email], + "You have been invited to a group!", + ); + } catch (e) { + console.log(e); + } - if ( - existingInvites.filter((i) => i.to === body.to && i.from === body.from) - .length == 0 - ) { - const shortUID = new ShortUniqueId(); - await setDoc(doc(db, "invites", body.id || shortUID.randomUUID(8)), body); - } + if (existingInvites.filter((i) => i.to === body.to && i.from === body.from).length == 0) { + const shortUID = new ShortUniqueId(); + await setDoc(doc(db, "invites", body.id || shortUID.randomUUID(8)), body); + } - res.status(200).json({ ok: true }); + res.status(200).json({ok: true}); } diff --git a/src/pages/api/reset/sendVerification.ts b/src/pages/api/reset/sendVerification.ts index cb582cb1..1116cc2d 100644 --- a/src/pages/api/reset/sendVerification.ts +++ b/src/pages/api/reset/sendVerification.ts @@ -19,6 +19,7 @@ async function sendVerification(req: NextApiRequest, res: NextApiResponse) { name: req.session.user.name, code: short.randomUUID(6), email: req.session.user.email, + environment: process.env.ENVIRONMENT, }, [req.session.user.email], "EnCoach Verification", diff --git a/src/pages/api/tickets/[id].ts b/src/pages/api/tickets/[id].ts index 29e35e45..f55ca518 100644 --- a/src/pages/api/tickets/[id].ts +++ b/src/pages/api/tickets/[id].ts @@ -1,109 +1,104 @@ // Next.js API route support: https://nextjs.org/docs/api-routes/introduction -import type { NextApiRequest, NextApiResponse } from "next"; -import { app } from "@/firebase"; -import { - getFirestore, - getDoc, - doc, - deleteDoc, - setDoc, -} from "firebase/firestore"; -import { withIronSessionApiRoute } from "iron-session/next"; -import { sessionOptions } from "@/lib/session"; -import { Ticket, TicketTypeLabel, TicketStatusLabel } from "@/interfaces/ticket"; +import type {NextApiRequest, NextApiResponse} from "next"; +import {app} from "@/firebase"; +import {getFirestore, getDoc, doc, deleteDoc, setDoc} from "firebase/firestore"; +import {withIronSessionApiRoute} from "iron-session/next"; +import {sessionOptions} from "@/lib/session"; +import {Ticket, TicketTypeLabel, TicketStatusLabel} from "@/interfaces/ticket"; import moment from "moment"; -import { sendEmail } from "@/email"; +import {sendEmail} from "@/email"; 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); - if (req.method === "DELETE") return await del(req, res); - if (req.method === "PATCH") return await patch(req, res); + if (req.method === "GET") return await get(req, res); + if (req.method === "DELETE") return await del(req, res); + if (req.method === "PATCH") return await patch(req, res); - res.status(404).json(undefined); + res.status(404).json(undefined); } async function get(req: NextApiRequest, res: NextApiResponse) { - if (!req.session.user) { - res.status(401).json({ ok: false }); - return; - } + if (!req.session.user) { + res.status(401).json({ok: false}); + return; + } - const { id } = req.query as { id: string }; + const {id} = req.query as {id: string}; - const snapshot = await getDoc(doc(db, "tickets", id)); + const snapshot = await getDoc(doc(db, "tickets", id)); - if (snapshot.exists()) { - res.status(200).json({ ...snapshot.data(), id: snapshot.id }); - } else { - res.status(404).json(undefined); - } + if (snapshot.exists()) { + res.status(200).json({...snapshot.data(), id: snapshot.id}); + } else { + res.status(404).json(undefined); + } } async function del(req: NextApiRequest, res: NextApiResponse) { - if (!req.session.user) { - res.status(401).json({ ok: false }); - return; - } + if (!req.session.user) { + res.status(401).json({ok: false}); + return; + } - const { id } = req.query as { id: string }; + const {id} = req.query as {id: string}; - const snapshot = await getDoc(doc(db, "tickets", id)); - const data = snapshot.data() as Ticket; + const snapshot = await getDoc(doc(db, "tickets", id)); + const data = snapshot.data() as Ticket; - const user = req.session.user; - if (user.type === "admin" || user.type === "developer") { - await deleteDoc(snapshot.ref); - res.status(200).json({ ok: true }); - return; - } + const user = req.session.user; + if (user.type === "admin" || user.type === "developer") { + await deleteDoc(snapshot.ref); + res.status(200).json({ok: true}); + return; + } - res.status(403).json({ ok: false }); + res.status(403).json({ok: false}); } async function patch(req: NextApiRequest, res: NextApiResponse) { - if (!req.session.user) { - res.status(401).json({ ok: false }); - return; - } + if (!req.session.user) { + res.status(401).json({ok: false}); + return; + } - const { id } = req.query as { id: string }; - const body = req.body as Ticket; + const {id} = req.query as {id: string}; + const body = req.body as Ticket; - const snapshot = await getDoc(doc(db, "tickets", id)); + const snapshot = await getDoc(doc(db, "tickets", id)); - const user = req.session.user; - if (user.type === "admin" || user.type === "developer") { - const data = snapshot.data() as Ticket; - await setDoc(snapshot.ref, body, { merge: true }); - try { - // send email if the status actually changed to completed - if(data.status !== req.body.status && req.body.status === 'completed') { - await sendEmail( - "ticketStatusCompleted", - { - id, - subject: body.subject, - reporter: body.reporter, - date: moment(body.date).format("DD/MM/YYYY - HH:mm"), - type: TicketTypeLabel[body.type], - reportedFrom: body.reportedFrom, - description: body.description, - }, - [data.reporter.email], - `Ticket ${id}: ${data.subject}`, - ); - } - } catch(err) { - console.error(err); - // doesnt matter if the email fails - } - res.status(200).json({ ok: true }); - return; - } + const user = req.session.user; + if (user.type === "admin" || user.type === "developer") { + const data = snapshot.data() as Ticket; + await setDoc(snapshot.ref, body, {merge: true}); + try { + // send email if the status actually changed to completed + if (data.status !== req.body.status && req.body.status === "completed") { + await sendEmail( + "ticketStatusCompleted", + { + id, + subject: body.subject, + reporter: body.reporter, + date: moment(body.date).format("DD/MM/YYYY - HH:mm"), + type: TicketTypeLabel[body.type], + reportedFrom: body.reportedFrom, + description: body.description, + environment: process.env.ENVIRONMENT, + }, + [data.reporter.email], + `Ticket ${id}: ${data.subject}`, + ); + } + } catch (err) { + console.error(err); + // doesnt matter if the email fails + } + res.status(200).json({ok: true}); + return; + } - res.status(403).json({ ok: false }); + res.status(403).json({ok: false}); } diff --git a/src/pages/api/tickets/index.ts b/src/pages/api/tickets/index.ts index d7daa365..d99b9fee 100644 --- a/src/pages/api/tickets/index.ts +++ b/src/pages/api/tickets/index.ts @@ -1,110 +1,103 @@ // Next.js API route support: https://nextjs.org/docs/api-routes/introduction -import { sendEmail } from "@/email"; -import { app } from "@/firebase"; -import { Ticket, TicketTypeLabel, TicketWithCorporate } from "@/interfaces/ticket"; -import { sessionOptions } from "@/lib/session"; -import { - collection, - doc, - getDocs, - getFirestore, - setDoc, - where, - query, -} from "firebase/firestore"; -import { withIronSessionApiRoute } from "iron-session/next"; +import {sendEmail} from "@/email"; +import {app} from "@/firebase"; +import {Ticket, TicketTypeLabel, TicketWithCorporate} from "@/interfaces/ticket"; +import {sessionOptions} from "@/lib/session"; +import {collection, doc, getDocs, getFirestore, setDoc, where, query} from "firebase/firestore"; +import {withIronSessionApiRoute} from "iron-session/next"; import moment from "moment"; -import type { NextApiRequest, NextApiResponse } from "next"; +import type {NextApiRequest, NextApiResponse} from "next"; import ShortUniqueId from "short-unique-id"; -import { Group, CorporateUser } from "@/interfaces/user"; +import {Group, CorporateUser} from "@/interfaces/user"; const db = getFirestore(app); export default withIronSessionApiRoute(handler, sessionOptions); async function handler(req: NextApiRequest, res: NextApiResponse) { - // due to integration with the homepage the POST request should be public - if (req.method === "POST") { - await post(req, res); - return; - } + // due to integration with the homepage the POST request should be public + if (req.method === "POST") { + await post(req, res); + return; + } - // specific logic for the preflight request - if (req.method === "OPTIONS") { - res.status(200).end(); - return; - } - if (!req.session.user) { - res.status(401).json({ ok: false }); - return; - } + // specific logic for the preflight request + if (req.method === "OPTIONS") { + res.status(200).end(); + return; + } + if (!req.session.user) { + res.status(401).json({ok: false}); + return; + } - if (req.method === "GET") { - await get(req, res); - } + if (req.method === "GET") { + await get(req, res); + } } async function get(req: NextApiRequest, res: NextApiResponse) { - const snapshot = await getDocs(collection(db, "tickets")); + const snapshot = await getDocs(collection(db, "tickets")); - const docs = snapshot.docs.map((doc) => ({ - id: doc.id, - ...doc.data(), - })) as Ticket[]; + const docs = snapshot.docs.map((doc) => ({ + id: doc.id, + ...doc.data(), + })) as Ticket[]; - // fetch all groups for these users + // fetch all groups for these users - const reporters = [...new Set(docs.map((d) => d.reporter.id).filter((id) => id))]; + const reporters = [...new Set(docs.map((d) => d.reporter.id).filter((id) => id))]; - const groupsSnapshot = await getDocs(query(collection(db, "groups"), where("participants", "array-contains-any", reporters))); - const groups = groupsSnapshot.docs.map((doc) => doc.data()) as Group[]; + const groupsSnapshot = await getDocs(query(collection(db, "groups"), where("participants", "array-contains-any", reporters))); + const groups = groupsSnapshot.docs.map((doc) => doc.data()) as Group[]; - // based on the admin of each group, verify if it exists and it's of type corporate - const groupsAdmins = [...new Set(groups.map((g) => g.admin).filter((id) => id))]; - const adminsSnapshot = await getDocs(query(collection(db, "users"), where("id", "in", groupsAdmins), where("type", "==", "corporate"))); - const admins = adminsSnapshot.docs.map((doc) => doc.data()); + // based on the admin of each group, verify if it exists and it's of type corporate + const groupsAdmins = [...new Set(groups.map((g) => g.admin).filter((id) => id))]; + const adminsSnapshot = await getDocs(query(collection(db, "users"), where("id", "in", groupsAdmins), where("type", "==", "corporate"))); + const admins = adminsSnapshot.docs.map((doc) => doc.data()); - const docsWithAdmins = docs.map((d) => { - const group = groups.find((g) => g.participants.includes(d.reporter.id)); - const admin = admins.find((a) => a.id === group?.admin) as CorporateUser; + const docsWithAdmins = docs.map((d) => { + const group = groups.find((g) => g.participants.includes(d.reporter.id)); + const admin = admins.find((a) => a.id === group?.admin) as CorporateUser; - if(admin) { - return { - ...d, - corporate: admin.corporateInformation?.companyInformation?.name, - }; - } + if (admin) { + return { + ...d, + corporate: admin.corporateInformation?.companyInformation?.name, + }; + } - return d; - }) as TicketWithCorporate[]; + return d; + }) as TicketWithCorporate[]; - res.status(200).json(docsWithAdmins); + res.status(200).json(docsWithAdmins); } async function post(req: NextApiRequest, res: NextApiResponse) { - const body = req.body as Ticket; + const body = req.body as Ticket; - const shortUID = new ShortUniqueId(); - const id = body.id || shortUID.randomUUID(8); - await setDoc(doc(db, "tickets", id), body); - res.status(200).json({ ok: true }); + const shortUID = new ShortUniqueId(); + const id = body.id || shortUID.randomUUID(8); + await setDoc(doc(db, "tickets", id), body); + res.status(200).json({ok: true}); - try { - await sendEmail( - "submittedFeedback", - { - id, - subject: body.subject, - reporter: body.reporter, - date: moment(body.date).format("DD/MM/YYYY - HH:mm"), - type: TicketTypeLabel[body.type], - reportedFrom: body.reportedFrom, - description: body.description, - }, - [body.reporter.email], - `Ticket ${id}: ${body.subject}` - ); - } catch (e) { - console.log(e); - } + try { + await sendEmail( + "submittedFeedback", + { + id, + subject: body.subject, + reporter: body.reporter, + date: moment(body.date).format("DD/MM/YYYY - HH:mm"), + type: TicketTypeLabel[body.type], + reportedFrom: body.reportedFrom, + description: body.description, + environment: process.env.ENVIRONMENT, + }, + [body.reporter.email], + `Ticket ${id}: ${body.subject}`, + ); + } catch (e) { + console.log(e); + } }