From ddbf352b33f357be725982b65a1190bf002397af Mon Sep 17 00:00:00 2001 From: Aravind Date: Mon, 15 Jun 2026 22:08:23 +0530 Subject: [PATCH] fix update email --- package-lock.json | 21 +++++++++ package.json | 2 + src/actions/sendEmail.ts | 53 ++++++++++++++++++++++ src/components/layout/Footer.tsx | 42 +++++++---------- src/components/strategy/StrategyCanvas.tsx | 6 ++- 5 files changed, 97 insertions(+), 27 deletions(-) create mode 100644 src/actions/sendEmail.ts diff --git a/package-lock.json b/package-lock.json index e32526e..9798239 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index 44a5c91..d31b392 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/actions/sendEmail.ts b/src/actions/sendEmail.ts new file mode 100644 index 0000000..7dd8c78 --- /dev/null +++ b/src/actions/sendEmail.ts @@ -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: ` +
+

New Contact Form Submission

+

Name: ${fullName}

+

Email: ${email}

+

Subject: ${subject}

+

Message:

+
+ ${message.replace(/\n/g, "
")} +
+
+ `, + }); + + 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 }; + } +} diff --git a/src/components/layout/Footer.tsx b/src/components/layout/Footer.tsx index 2988a3c..7c6cb44 100644 --- a/src/components/layout/Footer.tsx +++ b/src/components/layout/Footer.tsx @@ -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"); } }; diff --git a/src/components/strategy/StrategyCanvas.tsx b/src/components/strategy/StrategyCanvas.tsx index 4554524..2ace625 100644 --- a/src/components/strategy/StrategyCanvas.tsx +++ b/src/components/strategy/StrategyCanvas.tsx @@ -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));