Compare commits

..

No commits in common. "4656df7fca448364078a6a43097e978c5403fed4" and "5c139e83f5e2f14163f86287990f12386e42a176" have entirely different histories.

4 changed files with 80 additions and 77 deletions

View File

@ -1,80 +1,4 @@
"use server";
import { createTransport } from "nodemailer";
export async function getReCaptchaSiteKey() {
return process.env.RECAPTCHA_SITE_KEY;
}
const RECAPTCHA_SERVER_KEY = process.env.RECAPTCHA_SERVER_KEY;
export type SubmitContactReturn = { error: string } | { success: true };
export default async function SubmitContact(
prevState: unknown,
data: FormData
): Promise<SubmitContactReturn> {
if (!RECAPTCHA_SERVER_KEY) {
console.error(
"RECAPTCHA_SERVER_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_SERVER_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 };
}

View File

@ -1,8 +1,9 @@
"use client";
import SubmitContact from "@/components/contact";
import { useActionState, useEffect, useState } from "react";
import ReCAPTCHA from "react-google-recaptcha";
import SubmitContact, { getReCaptchaSiteKey } from "./action";
import { getReCaptchaSiteKey } from "./action";
export default function ContactPage() {
const [recaptchaSiteKey, setRecaptchaSiteKey] = useState<string | undefined>(

View File

@ -1,3 +1,5 @@
/* eslint-disable react/no-unescaped-entities */
"use client";
import React from "react";

76
src/components/contact.ts Normal file
View File

@ -0,0 +1,76 @@
"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<SubmitContactReturn> {
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 };
}