From 1ef3614660c11d9b8e8c1315e64e57a522c5a0ce Mon Sep 17 00:00:00 2001 From: Prosper Date: Thu, 3 Oct 2024 16:51:27 -0300 Subject: [PATCH] addded email functionality --- .gitignore | 1 + app/_components/Contact/Form.tsx | 52 +++++++++++++++++++----------- app/globals.css | 8 ----- lib/action.ts | 54 ++++++++++++++++++++++++++++++++ package-lock.json | 21 +++++++++++++ package.json | 2 ++ service/email.ts | 0 7 files changed, 111 insertions(+), 27 deletions(-) create mode 100644 lib/action.ts delete mode 100644 service/email.ts diff --git a/.gitignore b/.gitignore index fd3dbb5..ba1a0b6 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts +.env \ No newline at end of file diff --git a/app/_components/Contact/Form.tsx b/app/_components/Contact/Form.tsx index a9dd3a5..2156144 100644 --- a/app/_components/Contact/Form.tsx +++ b/app/_components/Contact/Form.tsx @@ -1,5 +1,6 @@ "use client"; import { Button } from "@/components/ui/button"; +import { sendMail } from "@/lib/action"; import { Loader2 } from "lucide-react"; import React from "react"; @@ -14,10 +15,12 @@ const Form = () => { const [message, setMessage] = React.useState(""); const [loading, setLoading] = React.useState(false); const [error, setError] = React.useState(null); + const [success, setSuccess] = React.useState(null); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setLoading(true); + setSuccess(null); setError(null); if (!validateName(name)) { @@ -39,18 +42,9 @@ const Form = () => { } try { - const res = await fetch("/api/contact", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ name, email, message }), - }); - - if (!res.ok) { - throw new Error("Something went wrong"); - } - + const res = await sendMail({ name, email, message }); + if (!res.success) throw new Error(res.message); + setSuccess(res.message); setName(""); setEmail(""); setMessage(""); @@ -65,6 +59,15 @@ const Form = () => { } }; + React.useEffect(() => { + const timeout = setTimeout(() => { + setError(null); + setSuccess(null); + }, 5000); + + return () => clearTimeout(timeout); + }, [error, success]); + return (
{ Get In Touch {loading && } -

- {error} -

+ {error && ( +

+ {error} +

+ )} + {success && ( +

+ {success} +

+ )} ); }; diff --git a/app/globals.css b/app/globals.css index 2575a6b..3087055 100644 --- a/app/globals.css +++ b/app/globals.css @@ -48,14 +48,6 @@ body { font-family: var(--font-sora), sans-serif; } -.backface-hidden { - backface-visibility: hidden; -} - -.preserve-3d { - transform-style: preserve-3d; -} - ::selection { background: light-dark(var(--dark), var(--light)); color: light-dark(var(--light), var(--dark)); diff --git a/lib/action.ts b/lib/action.ts new file mode 100644 index 0000000..7c9ab80 --- /dev/null +++ b/lib/action.ts @@ -0,0 +1,54 @@ +"use server"; +import nodemailer from "nodemailer"; + +export const sendMail = async ({ + name, + email, + message, +}: { + name: string; + email: string; + message: string; +}): Promise<{ + message: string; + success: boolean; + error: Error | null; +}> => { + const transporter = nodemailer.createTransport({ + service: "gmail", + host: "smtp.gmail.com", + secure: true, + port: 465, + auth: { + user: process.env.NODE_EMAIL, + pass: process.env.NODE_APP_PASSWORD, + }, + }); + + const mailOptions = { + to: "piinoya@gmail.com", + subject: `New message from ${name}`, + replyTo: "noreply@pnoya.com", + text: `Hey Prosper, ${name} sent you a message: \n${message}.\n Thier Email: ${email}\n Date: ${new Date()}`, + }; + + return new Promise((resolve, reject) => { + transporter.sendMail(mailOptions, function (err, data) { + console.log("err", err); + console.log("data", data); + if (err) { + reject({ + message: "Unable to send email, please try again later", + error: err, + success: false, + }); + } else { + resolve({ + message: "Email sent, thank you!", + success: true, + error: null, + }); + } + }); + }); +}; diff --git a/package-lock.json b/package-lock.json index 13630c5..433c4e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "lucide-react": "^0.446.0", "next": "14.2.13", "next-themes": "^0.3.0", + "nodemailer": "^6.9.15", "react": "^18", "react-dom": "^18", "react-leaflet": "^4.2.1", @@ -27,6 +28,7 @@ "devDependencies": { "@types/leaflet": "^1.9.12", "@types/node": "^20", + "@types/nodemailer": "^6.4.16", "@types/react": "^18", "@types/react-dom": "^18", "eslint": "^8", @@ -932,6 +934,16 @@ "undici-types": "~6.19.2" } }, + "node_modules/@types/nodemailer": { + "version": "6.4.16", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.16.tgz", + "integrity": "sha512-uz6hN6Pp0upXMcilM61CoKyjT7sskBoOWpptkjjJp8jIMlTdc3xG01U7proKkXzruMS4hS0zqtHNkNPFB20rKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/prop-types": { "version": "15.7.13", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", @@ -4061,6 +4073,15 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/nodemailer": { + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.15.tgz", + "integrity": "sha512-AHf04ySLC6CIfuRtRiEYtGEXgRfa6INgWGluDhnxTZhHSKvrBu7lc1VVchQ0d8nPc4cFaZoPq8vkyNoZr0TpGQ==", + "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 7ec0acf..03d83b0 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "lucide-react": "^0.446.0", "next": "14.2.13", "next-themes": "^0.3.0", + "nodemailer": "^6.9.15", "react": "^18", "react-dom": "^18", "react-leaflet": "^4.2.1", @@ -28,6 +29,7 @@ "devDependencies": { "@types/leaflet": "^1.9.12", "@types/node": "^20", + "@types/nodemailer": "^6.4.16", "@types/react": "^18", "@types/react-dom": "^18", "eslint": "^8", diff --git a/service/email.ts b/service/email.ts deleted file mode 100644 index e69de29..0000000