From 29deee3b8f3dbc9f18e48fcc0cd35983b7d90d5a Mon Sep 17 00:00:00 2001 From: John Puka Date: Fri, 6 Dec 2024 19:27:44 -0500 Subject: [PATCH 1/2] completed contact page translation and admin email connection --- backend/server.js | 49 ++++++++++++++++++++++++++++++++++---- package-lock.json | 10 ++++++++ package.json | 1 + src/api/contact-wrapper.js | 16 +++++++++---- src/pages/Contact.jsx | 43 +++++++++++++++++++-------------- 5 files changed, 92 insertions(+), 27 deletions(-) diff --git a/backend/server.js b/backend/server.js index f9e8312..7cd8d0d 100644 --- a/backend/server.js +++ b/backend/server.js @@ -4,6 +4,7 @@ const cors = require('cors'); const mongo = require('mongodb'); const mongoose = require('mongoose'); const mongoSanitize = require('express-mongo-sanitize'); +const nodemailer = require('nodemailer'); const app = express() app.use(cors()) @@ -196,22 +197,60 @@ app.get('/api/users', async (req, res) => { // Contact app.post('/api/contact', async (req, res) => { const { name, email, subject, message } = req.body + + if (!name || !email || !subject || !message) { + return res.status(400).json({ message: 'All fields are required' }); + } + try { const newContact = new Contact({ name, email, subject, message - }) - await newContact.save() + }); + await newContact.save(); + + // Nodemailer setup + const transporter = nodemailer.createTransport({ + service: 'gmail', + auth: { + user: process.env.ADMIN_EMAIL, + pass: process.env.ADMIN_PASSWORD, + }, + }); - res.status(201).json({ message: 'Inquiry submitted successfully' }) + transporter.verify((error, success) => { + if (error) { + console.error('Error initializing transporter:', error); + } else { + console.log('Transporter is ready to send emails', success); + } + }); + + + const mailOptions = { + from: email, + to: process.env.ADMIN_EMAIL, + subject: `Contact Form: ${subject}`, + html: ` +

From: ${name} (${email})

+

Subject: ${subject}

+

Message:

+

${message}

+ ` + }; + + // Send email + await transporter.sendMail(mailOptions); + + res.status(201).json({ message: 'Inquiry and email submitted successfully' }); } catch (err) { console.error('Error submitting inquiry:', err); - res.status(500).json({ message: 'Error submitting inquiry' }) + res.status(500).json({ message: 'Error submitting inquiry', error: err.message }); } -}) +}); // Classes // TODO (Donatello, Claire, Yi): Modify the endpoint to take in query params and filter classes with them diff --git a/package-lock.json b/package-lock.json index f03c3bc..5ca6b78 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "i18next": "^23.16.4", "i18next-browser-languagedetector": "^8.0.0", "i18next-http-backend": "^2.6.2", + "nodemailer": "^6.9.16", "react": "^18.3.1", "react-dom": "^18.3.1", "react-i18next": "^15.1.0", @@ -4374,6 +4375,15 @@ "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true }, + "node_modules/nodemailer": { + "version": "6.9.16", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.16.tgz", + "integrity": "sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/nodemon": { "version": "3.1.7", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz", diff --git a/package.json b/package.json index 3359f2d..09ad4e4 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "i18next": "^23.16.4", "i18next-browser-languagedetector": "^8.0.0", "i18next-http-backend": "^2.6.2", + "nodemailer": "^6.9.16", "react": "^18.3.1", "react-dom": "^18.3.1", "react-i18next": "^15.1.0", diff --git a/src/api/contact-wrapper.js b/src/api/contact-wrapper.js index afc8add..731f24f 100644 --- a/src/api/contact-wrapper.js +++ b/src/api/contact-wrapper.js @@ -7,14 +7,22 @@ const postContact = async (body) => { headers: { "Content-Type": "application/json", }, - body: JSON.stringify(body) - }) + body: JSON.stringify(body), + }); - return response + if (!response.ok) { + const errorResponse = await response.json(); + console.error('Error response from /api/contact:', errorResponse); + throw new Error(errorResponse.message || 'Failed to submit contact form'); + } + + return response; } catch (error) { console.error('Contact endpoint post error:', error); + throw error; // Propagate the error to the caller } -} +}; + export { postContact diff --git a/src/pages/Contact.jsx b/src/pages/Contact.jsx index d37ff7a..0c3740a 100644 --- a/src/pages/Contact.jsx +++ b/src/pages/Contact.jsx @@ -4,8 +4,10 @@ import { postContact } from '@/api/contact-wrapper'; import Form from "@/components/Form/Form" import FormInput from '@/components/Form/FormInput'; import FormSubmit from '@/components/Form/FormSubmit'; +import { useTranslation } from 'react-i18next'; export default function Contact() { + const { t } = useTranslation(); const [formData, setFormData] = useState({ name: '', @@ -20,19 +22,24 @@ export default function Contact() { const handleSubmit = async (e) => { e.preventDefault(); + const contactData = { + name: e.target.name.value, + email: e.target.email.value, + subject: e.target.subject.value, + message: e.target.message.value + }; try { - const response = await postContact(formData) + const response = await postContact(contactData); - if (!response.ok) { - throw new Error(`Response status: ${response.status}`); + if (response.ok) { + alert("Message submitted successfully!"); + } else { + const errorResponse = await response.json(); + alert(`Failed to send message: ${errorResponse.message}`); } - const json = await response.json() - console.log(json) - alert("Inquiry submitted successfully!") - } catch (err) { - console.error(error.message) - alert("There was an error submitting the inquiry.") + console.error('Error in handleSubmit:', err); + alert("There was an error submitting the inquiry."); } }; @@ -40,9 +47,9 @@ export default function Contact() { return (
-

CONTACT US

+

{t("contact_heading")}

- Email: + {t("email_field")}: dillarenglish@gmail.com @@ -58,9 +65,9 @@ export default function Contact() {

{/* form box */}
-

Get in Touch

+

{t("form_heading")}

- Let us know if you have questions or concerns. + {t("form_description")}

- +
From 526be29ec647d4827b3bf9b2c475abc93947b761 Mon Sep 17 00:00:00 2001 From: John Puka Date: Sat, 7 Dec 2024 15:40:10 -0500 Subject: [PATCH 2/2] removed error redundancy in server.js contact section --- backend/server.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/backend/server.js b/backend/server.js index 7cd8d0d..18c3c30 100644 --- a/backend/server.js +++ b/backend/server.js @@ -198,10 +198,6 @@ app.get('/api/users', async (req, res) => { app.post('/api/contact', async (req, res) => { const { name, email, subject, message } = req.body - if (!name || !email || !subject || !message) { - return res.status(400).json({ message: 'All fields are required' }); - } - try { const newContact = new Contact({ name,