fix update email
This commit is contained in:
21
package-lock.json
generated
21
package-lock.json
generated
@@ -18,6 +18,7 @@
|
||||
"lenis": "^1.3.23",
|
||||
"maath": "^0.10.8",
|
||||
"next": "16.2.6",
|
||||
"nodemailer": "^9.0.0",
|
||||
"react": "19.2.4",
|
||||
"react-dom": "19.2.4",
|
||||
"react-leaflet": "^5.0.0",
|
||||
@@ -31,6 +32,7 @@
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/leaflet": "^1.9.21",
|
||||
"@types/node": "^20",
|
||||
"@types/nodemailer": "^8.0.1",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"@types/three": "^0.184.0",
|
||||
@@ -3045,6 +3047,16 @@
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/nodemailer": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-8.0.1.tgz",
|
||||
"integrity": "sha512-PxpaInm8V1JQDd4j0ds5HfvWQk8JupS1C0Picb96QJsrrRDjBH+DlK7L4ZdNSqNULhiZRQHc40nLVShaGxXAMw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/offscreencanvas": {
|
||||
"version": "2019.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz",
|
||||
@@ -9018,6 +9030,15 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemailer": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-9.0.0.tgz",
|
||||
"integrity": "sha512-tbPTid7d/p9jAA8CRZ3iomvrMaST0o6NYuY7v6JQZHpPRZ61mLFSPKYd7342NtOFuej9/+L48SOIxwfu2uDvtw==",
|
||||
"license": "MIT-0",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"lenis": "^1.3.23",
|
||||
"maath": "^0.10.8",
|
||||
"next": "16.2.6",
|
||||
"nodemailer": "^9.0.0",
|
||||
"react": "19.2.4",
|
||||
"react-dom": "19.2.4",
|
||||
"react-leaflet": "^5.0.0",
|
||||
@@ -36,6 +37,7 @@
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/leaflet": "^1.9.21",
|
||||
"@types/node": "^20",
|
||||
"@types/nodemailer": "^8.0.1",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"@types/three": "^0.184.0",
|
||||
|
||||
53
src/actions/sendEmail.ts
Normal file
53
src/actions/sendEmail.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
"use server";
|
||||
|
||||
import nodemailer from "nodemailer";
|
||||
|
||||
export async function sendContactEmail(data: {
|
||||
fullName: string;
|
||||
email: string;
|
||||
subject: string;
|
||||
message: string;
|
||||
}) {
|
||||
const { fullName, email, subject, message } = data;
|
||||
|
||||
if (!fullName || !email || !subject || !message) {
|
||||
return { success: false, error: "All fields are required." };
|
||||
}
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: process.env.SMTP_HOST,
|
||||
port: Number(process.env.SMTP_PORT) || 465,
|
||||
secure: true,
|
||||
auth: {
|
||||
user: process.env.SMTP_USER,
|
||||
pass: process.env.SMTP_PASSWORD,
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
await transporter.sendMail({
|
||||
from: `"${fullName}" <${process.env.SMTP_USER}>`,
|
||||
to: process.env.CONTACT_RECEIVER,
|
||||
replyTo: email,
|
||||
subject: `New Contact Form Submission: ${subject}`,
|
||||
html: `
|
||||
<div style="font-family: sans-serif; color: #333; max-width: 600px; margin: 0 auto; border: 1px solid #eee; padding: 20px; border-radius: 8px;">
|
||||
<h2 style="color: #c01227; border-bottom: 2px solid #c01227; padding-bottom: 10px; margin-top: 0;">New Contact Form Submission</h2>
|
||||
<p><strong>Name:</strong> ${fullName}</p>
|
||||
<p><strong>Email:</strong> ${email}</p>
|
||||
<p><strong>Subject:</strong> ${subject}</p>
|
||||
<p><strong>Message:</strong></p>
|
||||
<blockquote style="background: #f9f9f9; padding: 15px; border-left: 4px solid #c01227; margin: 0; font-style: italic;">
|
||||
${message.replace(/\n/g, "<br />")}
|
||||
</blockquote>
|
||||
</div>
|
||||
`,
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error("Email send error:", error);
|
||||
const errorMessage = error instanceof Error ? error.message : "Failed to send the email. Please try again later.";
|
||||
return { success: false, error: errorMessage };
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import emailjs from "@emailjs/browser";
|
||||
import { sendContactEmail } from "@/actions/sendEmail";
|
||||
import { ScrollReveal } from "@/animations/Reveal";
|
||||
|
||||
export default function Footer() {
|
||||
@@ -53,34 +53,24 @@ export default function Footer() {
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
// EmailJS is fully client-side — only the public-safe credentials are used
|
||||
// (Service ID, Template ID, Public Key). No private/secret key, no backend route.
|
||||
const serviceId = process.env.NEXT_PUBLIC_EMAILJS_SERVICE_ID;
|
||||
const templateId = process.env.NEXT_PUBLIC_EMAILJS_TEMPLATE_ID;
|
||||
const publicKey = process.env.NEXT_PUBLIC_EMAILJS_PUBLIC_KEY;
|
||||
if (!serviceId || !templateId || !publicKey) {
|
||||
console.error("EmailJS env vars are missing — set NEXT_PUBLIC_EMAILJS_* in .env.local");
|
||||
setFormStatus("error");
|
||||
return;
|
||||
}
|
||||
|
||||
setFormStatus("submitting");
|
||||
try {
|
||||
await emailjs.send(
|
||||
serviceId,
|
||||
templateId,
|
||||
{
|
||||
name: formData.fullName,
|
||||
email: formData.email,
|
||||
subject: formData.subject,
|
||||
message: formData.message,
|
||||
},
|
||||
publicKey,
|
||||
);
|
||||
setFormStatus("success");
|
||||
setFormData({ fullName: "", email: "", subject: "", message: "" });
|
||||
const res = await sendContactEmail({
|
||||
fullName: formData.fullName,
|
||||
email: formData.email,
|
||||
subject: formData.subject,
|
||||
message: formData.message,
|
||||
});
|
||||
|
||||
if (res.success) {
|
||||
setFormStatus("success");
|
||||
setFormData({ fullName: "", email: "", subject: "", message: "" });
|
||||
} else {
|
||||
console.error("Failed to send contact email:", res.error);
|
||||
setFormStatus("error");
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
console.error("Error submitting contact form:", err);
|
||||
setFormStatus("error");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -827,7 +827,11 @@ function SceneReadySignal({ onReady }: { onReady?: () => void }) {
|
||||
};
|
||||
|
||||
try {
|
||||
const compile = renderer.compileAsync
|
||||
const hasParallelExtension =
|
||||
typeof renderer.getContext === "function" &&
|
||||
!!renderer.getContext()?.getExtension?.("KHR_parallel_shader_compile");
|
||||
|
||||
const compile = (typeof renderer.compileAsync === "function" && hasParallelExtension)
|
||||
? renderer.compileAsync(scene, camera)
|
||||
: Promise.resolve().then(() => renderer.compile(scene, camera));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user