diff --git a/src/app/contact/action.ts b/src/app/contact/action.ts index a89f8bf..801800a 100644 --- a/src/app/contact/action.ts +++ b/src/app/contact/action.ts @@ -1,4 +1,80 @@ "use server"; + +import { createTransport } from "nodemailer"; + export async function getReCaptchaSiteKey() { return process.env.RECAPTCHA_SITE_KEY; } + +const RECAPTCHA_SECRET_KEY = process.env.RECAPTCHA_SECRET_KEY; + +export type SubmitContactReturn = { error: string } | { success: true }; + +export default async function SubmitContact( + prevState: unknown, + data: FormData +): Promise { + if (!RECAPTCHA_SECRET_KEY) { + console.error( + "RECAPTCHA_SECRET_KEY is not set. Please check your environment variables." + ); + throw new Error("Server error: RECAPTCHA not configure correctly."); + } + + const name = data.get("name"); + const email = data.get("email"); + const message = data.get("message"); + const recaptcha = data.get("g-recaptcha-response"); + + if (!name || !email || !message) { + return { error: "All fields are required." }; + } + + if (!recaptcha) { + return { error: "Please complete the reCAPTCHA." }; + } + + try { + const recaptchaResponse = await fetch( + `https://www.google.com/recaptcha/api/siteverify`, + { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + body: `secret=${RECAPTCHA_SECRET_KEY}&response=${recaptcha}`, + } + ); + const recaptchaData = await recaptchaResponse.json(); + if (!recaptchaData.success) { + return { error: "reCAPTCHA verification failed." }; + } + } catch (e) { + console.error(e); + return { error: "Could not reach reCAPTCHA for verification." }; + } + + try { + const transporter = createTransport({ + host: process.env.MAIL_HOST ?? "localhost", + port: process.env.MAIL_PORT ? parseInt(process.env.MAIL_PORT) : undefined, + secure: true, + auth: { + user: process.env.MAIL_USER, + pass: process.env.MAIL_PASS, + }, + }); + await transporter.sendMail({ + from: process.env.MAIL_FROM, + to: process.env.MAIL_TO, + subject: `From ${name}`, + replyTo: email.toString(), + text: `Name:${name}\nEmail: ${email}\nMessage:\n ${message}`, + }); + } catch (e) { + console.error(e); + return { error: "Failed to send email." }; + } + + return { success: true }; +} diff --git a/src/app/contact/page.tsx b/src/app/contact/page.tsx index 810219b..69727b4 100644 --- a/src/app/contact/page.tsx +++ b/src/app/contact/page.tsx @@ -1,9 +1,8 @@ "use client"; -import SubmitContact from "@/components/contact"; import { useActionState, useEffect, useState } from "react"; import ReCAPTCHA from "react-google-recaptcha"; -import { getReCaptchaSiteKey } from "./action"; +import SubmitContact, { getReCaptchaSiteKey } from "./action"; export default function ContactPage() { const [recaptchaSiteKey, setRecaptchaSiteKey] = useState( diff --git a/src/components/contact.ts b/src/components/contact.ts deleted file mode 100644 index 322c339..0000000 --- a/src/components/contact.ts +++ /dev/null @@ -1,76 +0,0 @@ -"use server"; - -import { createTransport } from "nodemailer"; - -const RECAPTCHA_SECRET_KEY = process.env.RECAPTCHA_SECRET_KEY; - -export type SubmitContactReturn = { error: string } | { success: true }; - -export default async function SubmitContact( - prevState: unknown, - data: FormData -): Promise { - if (!RECAPTCHA_SECRET_KEY) { - console.error( - "RECAPTCHA_SECRET_KEY is not set. Please check your environment variables." - ); - throw new Error("Server error: RECAPTCHA not configure correctly."); - } - - const name = data.get("name"); - const email = data.get("email"); - const message = data.get("message"); - const recaptcha = data.get("g-recaptcha-response"); - - if (!name || !email || !message) { - return { error: "All fields are required." }; - } - - if (!recaptcha) { - return { error: "Please complete the reCAPTCHA." }; - } - - try { - const recaptchaResponse = await fetch( - `https://www.google.com/recaptcha/api/siteverify`, - { - method: "POST", - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, - body: `secret=${RECAPTCHA_SECRET_KEY}&response=${recaptcha}`, - } - ); - const recaptchaData = await recaptchaResponse.json(); - if (!recaptchaData.success) { - return { error: "reCAPTCHA verification failed." }; - } - } catch (e) { - console.error(e); - return { error: "Could not reach reCAPTCHA for verification." }; - } - - try { - const transporter = createTransport({ - host: process.env.MAIL_HOST ?? "localhost", - port: process.env.MAIL_PORT ? parseInt(process.env.MAIL_PORT) : undefined, - secure: true, - auth: { - user: process.env.MAIL_USER, - pass: process.env.MAIL_PASS, - }, - }); - await transporter.sendMail({ - from: process.env.MAIL_FROM, - to: process.env.MAIL_TO, - subject: `From ${name}`, - replyTo: email.toString(), - text: `Name:${name}\nEmail: ${email}\nMessage:\n ${message}`, - }); - } catch (e) { - console.error(e); - return { error: "Failed to send email." }; - } - - return { success: true }; -}