diff --git a/.env.example b/.env.example index 8be044e..596e3c9 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,11 @@ STRAPI_URL=http://localhost:1337 NEXTAUTH_SECRET= NEXTAUTH_URL=http://localhost:3000 + +# NODE MAILER +NODEMAILER_REQUEST_SERVER= +NODEMAILER_TRANSPORTER_SERVICE= +NODEMAILER_TRANSPORTER_USER= +NODEMAILER_TRANSPORTER_PASS= +NODEMAILER_OPTIONS_FROM= +NODEMAILER_OPTIONS_TO= diff --git a/README.md b/README.md index 49b51db..c0a1de9 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ And that's it! Your `SkateHub Frontend` should now be up and running locally on ### 2024 +- 2024-04-08 - Create the `confirmation` page of the SkateHub project [#15](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/15) _(v0.1.12)_ - 2024-04-06 - Update the `signin` page of the SkateHub project [#14](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/14) _(v0.1.11)_ - 2024-04-03 - Create the `signup` page of the SkateHub project [#12](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/12) _(v0.1.10)_ - 2024-03-31 - Update `authentication` and `session` management [#11](https://github.com/jpcmf/Frontend-GraduateProgram-FullStack-2024/pull/11) _(v0.1.9)_ diff --git a/package-lock.json b/package-lock.json index c2030ce..40edddd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "frontend", - "version": "0.1.9", + "version": "0.1.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "frontend", - "version": "0.1.9", + "version": "0.1.11", "dependencies": { "@chakra-ui/next-js": "^2.2.0", "@chakra-ui/react": "^2.8.2", @@ -17,6 +17,7 @@ "framer-motion": "^11.0.20", "next": "latest", "next-auth": "^4.24.7", + "nodemailer": "^6.9.13", "nookies": "^2.5.2", "react": "latest", "react-dom": "latest", @@ -28,6 +29,7 @@ "devDependencies": { "@types/cookie": "^0.6.0", "@types/node": "latest", + "@types/nodemailer": "^6.4.14", "@types/react": "latest", "@types/react-dom": "latest", "eslint": "latest", @@ -1892,6 +1894,15 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/nodemailer": { + "version": "6.4.14", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.14.tgz", + "integrity": "sha512-fUWthHO9k9DSdPCSPRqcu6TWhYyxTBg382vlNIttSe9M7XfsT06y0f24KHXtbnijPGGRIcVvdKHTNikOI6qiHA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", @@ -4738,6 +4749,14 @@ } } }, + "node_modules/nodemailer": { + "version": "6.9.13", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.13.tgz", + "integrity": "sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/nookies": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/nookies/-/nookies-2.5.2.tgz", diff --git a/package.json b/package.json index ef653a4..3c62f81 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "frontend", - "version": "0.1.11", + "version": "0.1.12", "private": true, "scripts": { "dev": "next dev", @@ -18,6 +18,7 @@ "framer-motion": "^11.0.20", "next": "latest", "next-auth": "^4.24.7", + "nodemailer": "^6.9.13", "nookies": "^2.5.2", "react": "latest", "react-dom": "latest", @@ -29,6 +30,7 @@ "devDependencies": { "@types/cookie": "^0.6.0", "@types/node": "latest", + "@types/nodemailer": "^6.4.14", "@types/react": "latest", "@types/react-dom": "latest", "eslint": "latest", diff --git a/public/loader.svg b/public/loader.svg new file mode 100644 index 0000000..b1a15f1 --- /dev/null +++ b/public/loader.svg @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/src/pages/api/sendConfirmationEmail.ts b/src/pages/api/sendConfirmationEmail.ts new file mode 100644 index 0000000..361cfc9 --- /dev/null +++ b/src/pages/api/sendConfirmationEmail.ts @@ -0,0 +1,53 @@ +import nodemailer from "nodemailer"; +import { NextApiRequest, NextApiResponse } from "next"; + +import { + NODEMAILER_REQUEST_SERVER, + NODEMAILER_TRANSPORTER_SERVICE, + NODEMAILER_TRANSPORTER_USER, + NODEMAILER_TRANSPORTER_PASS, + NODEMAILER_OPTIONS_FROM, + NODEMAILER_OPTIONS_TO +} from "@/utils/constant"; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + if (req.method === "POST") { + // Check if request is coming from the server + if (!req.headers || !req.headers.host || !req.headers.host.startsWith(`${NODEMAILER_REQUEST_SERVER}`)) { + res.status(403).json({ message: "Forbidden" }); + return; + } + + // Extract user information from the request body + const { userEmail } = req.body; + + // Create a Nodemailer transporter + const transporter = nodemailer.createTransport({ + // Configure your email service here + service: `${NODEMAILER_TRANSPORTER_SERVICE}`, + auth: { + user: `${NODEMAILER_TRANSPORTER_USER}`, + pass: `${NODEMAILER_TRANSPORTER_PASS}` + } + }); + + // Compose email message + const mailOptions = { + from: `${NODEMAILER_OPTIONS_FROM}`, + to: `${NODEMAILER_OPTIONS_TO}`, + subject: "Confirmação de e-mail do usuário", + text: `Usuário com e-mail ${userEmail} confirmou seu endereço de e-mail.` + }; + + try { + // Send email + await transporter.sendMail(mailOptions); + res.status(200).json({ message: "Email sent to admin successfully" }); + } catch (error) { + console.error("Error sending email:", error); + res.status(500).json({ message: "Error sending email to admin" }); + } + } else { + res.status(405).json({ message: "Method Not Allowed" }); + } +} diff --git a/src/pages/auth/confirmation.tsx b/src/pages/auth/confirmation.tsx new file mode 100644 index 0000000..f046642 --- /dev/null +++ b/src/pages/auth/confirmation.tsx @@ -0,0 +1,90 @@ +import Image from "next/image"; +import { useEffect } from "react"; +import { useRouter } from "next/router"; +import { Flex, Text } from "@chakra-ui/react"; + +import { Toast } from "@/components/Toast"; + +export default function Confirmation() { + const route = useRouter(); + const { addToast } = Toast(); + + useEffect(() => { + function getQueryParam(name: string) { + const params = new URLSearchParams(window.location.search); + return params.get(name); + } + + async function sendConfirmationEmail() { + try { + const userEmail = getQueryParam("email"); + + if (!userEmail) { + addToast({ + title: "Erro ao confirmar e-mail.", + message: "Parâmetro de e-mail não encontrado na URL.", + type: "error" + }); + return; + } + + const response = await fetch("/api/sendConfirmationEmail", { + method: "POST", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ userEmail }) + }); + + if (response.ok) { + addToast({ + title: "E-mail confirmado com sucesso.", + message: + "Nossa equipe avaliará suas informações e assim que aprovado seu cadastro, você receberá um e-mail de confirmação.", + type: "success" + }); + + route.push("/"); + } else { + addToast({ + title: "Erro ao confirmar e-mail.", + message: "Erro ao enviar e-mail de confirmação: " + response.statusText, + type: "error" + }); + } + } catch (error: any) { + addToast({ + title: "Erro ao confirmar e-mail.", + message: "Erro ao enviar e-mail de confirmação: " + error.message, + type: "error" + }); + } + } + sendConfirmationEmail(); + }, []); + + return ( + + Loading + + Seu e-mail está sendo confirmado... + + + Por favor, aguarde alguns instantes. + + + ); +} diff --git a/src/utils/constant.ts b/src/utils/constant.ts index 1cd9731..abd8329 100644 --- a/src/utils/constant.ts +++ b/src/utils/constant.ts @@ -2,3 +2,10 @@ export const AVATAR_API = "https://ui-avatars.com/api"; export const API = process.env.NEXT_PUBLIC_STRAPI_URL; export const AUTH_TOKEN = "authToken"; export const BEARER = "Bearer"; + +export const NODEMAILER_REQUEST_SERVER = process.env.NODEMAILER_REQUEST_SERVER; +export const NODEMAILER_TRANSPORTER_SERVICE = process.env.NODEMAILER_TRANSPORTER_SERVICE; +export const NODEMAILER_TRANSPORTER_USER = process.env.NODEMAILER_TRANSPORTER_USER; +export const NODEMAILER_TRANSPORTER_PASS = process.env.NODEMAILER_TRANSPORTER_PASS; +export const NODEMAILER_OPTIONS_FROM = process.env.NODEMAILER_OPTIONS_FROM; +export const NODEMAILER_OPTIONS_TO = process.env.NODEMAILER_OPTIONS_TO;