From 4f6a0d83bf25153734a97b9601a427abf521450b Mon Sep 17 00:00:00 2001 From: mukesh13 Date: Thu, 14 Aug 2025 11:53:40 +0530 Subject: [PATCH] Logo update --- app/api/contact/route.js | 268 ++++++++++++++++++ components/common/Careerform.jsx | 129 +++++---- components/common/Contact.jsx | 128 ++++++--- components/footers/Footer3.jsx | 97 +++---- components/headers/Header4.jsx | 35 +-- components/modals/Mobilemenu.jsx | 35 +-- components/otherPages/Contact.jsx | 117 ++++++-- package-lock.json | 10 + package.json | 1 + public/images/logo/keystonesolution.png | Bin 0 -> 103788 bytes public/images/logo/keystonesolution_white.png | Bin 0 -> 142803 bytes 11 files changed, 621 insertions(+), 199 deletions(-) create mode 100644 app/api/contact/route.js create mode 100644 public/images/logo/keystonesolution.png create mode 100644 public/images/logo/keystonesolution_white.png diff --git a/app/api/contact/route.js b/app/api/contact/route.js new file mode 100644 index 0000000..07c5ecc --- /dev/null +++ b/app/api/contact/route.js @@ -0,0 +1,268 @@ +// app/api/contact/route.js +// āŒ REMOVE "use client" from here - API routes must NOT have this directive + +import { NextResponse } from 'next/server'; +import nodemailer from 'nodemailer'; + +// Create transporter with Zoho configuration +const createTransport = () => { + return nodemailer.createTransport({ + host: 'smtp.zoho.com', + port: 587, + secure: false, + auth: { + user: process.env.ZOHO_EMAIL, + pass: process.env.ZOHO_PASSWORD, + }, + debug: true, + logger: true, + }); +}; + +// Handle Newsletter Subscription +async function handleNewsletter(data) { + console.log('Processing newsletter subscription for:', data.email); + + const transporter = createTransport(); + + const mailOptions = { + from: process.env.ZOHO_EMAIL, + to: process.env.RECIPIENT_EMAIL, + subject: 'New Newsletter Subscription - Keystone Solutions', + html: ` +
+

New Newsletter Subscription

+
+

Email: ${data.email}

+

Subscribed at: ${new Date().toLocaleString()}

+
+
+

+ This email was sent from your website's newsletter subscription form. +

+
+ `, + }; + + const result = await transporter.sendMail(mailOptions); + console.log('Newsletter email sent successfully:', result.messageId); + return result; +} + +// Handle Contact Form +async function handleContact(data) { + console.log('Processing contact form for:', data.fullName, data.email); + + const transporter = createTransport(); + + const mailOptions = { + from: process.env.ZOHO_EMAIL, + to: process.env.RECIPIENT_EMAIL, + subject: 'New Contact Form Submission - Keystone Solutions', + html: ` +
+

New Contact Form Submission

+
+

Full Name: ${data.fullName}

+

Email: ${data.email}

+

Phone: ${data.phone || 'Not provided'}

+

Message:

+
+ ${data.message || 'No message provided'} +
+

Submitted at: ${new Date().toLocaleString()}

+
+
+

+ This email was sent from your website's contact form. +

+
+ `, + }; + + const result = await transporter.sendMail(mailOptions); + console.log('Contact email sent successfully:', result.messageId); + return result; +} + +// Handle Career Form +async function handleCareer(data) { + console.log('Processing career form for:', data.fullName, data.email); + + const transporter = createTransport(); + + const attachments = []; + + // Handle file attachment if present + if (data.resume) { + console.log('Resume file attached:', data.resume.name); + attachments.push({ + filename: data.resume.name, + content: Buffer.from(data.resume.data, 'base64'), + contentType: data.resume.type, + }); + } + + const mailOptions = { + from: process.env.ZOHO_EMAIL, + to: process.env.RECIPIENT_EMAIL, + subject: 'New Career Application - Keystone Solutions', + html: ` +
+

New Career Application

+
+

Full Name: ${data.fullName}

+

Email: ${data.email}

+

Phone: ${data.phone}

+

Roles of Interest: ${data.roles}

+

Resume: ${data.resume ? 'Attached' : 'Not provided'}

+

Applied at: ${new Date().toLocaleString()}

+
+
+

+ This email was sent from your website's career application form. +

+
+ `, + attachments: attachments, + }; + + const result = await transporter.sendMail(mailOptions); + console.log('Career email sent successfully:', result.messageId); + return result; +} + +// POST handler for all form submissions +export async function POST(request) { + console.log('\nšŸš€ === EMAIL API ROUTE STARTED ==='); + + try { + // Check environment variables first + const requiredEnvVars = { + ZOHO_EMAIL: process.env.ZOHO_EMAIL, + ZOHO_PASSWORD: process.env.ZOHO_PASSWORD, + RECIPIENT_EMAIL: process.env.RECIPIENT_EMAIL, + }; + + console.log('Environment variables check:'); + Object.entries(requiredEnvVars).forEach(([key, value]) => { + console.log(`${key}: ${value ? 'āœ… Set' : 'āŒ Missing'}`); + }); + console.log( + 'Loaded password (first 3 chars):', + process.env.ZOHO_PASSWORD?.slice(0, 3) + ); + + if (!requiredEnvVars.ZOHO_EMAIL || !requiredEnvVars.ZOHO_PASSWORD || !requiredEnvVars.RECIPIENT_EMAIL) { + console.error('āŒ Missing required environment variables'); + return NextResponse.json( + { error: 'Email configuration missing' }, + { status: 500 } + ); + } + + // Parse request body + let body; + try { + body = await request.json(); + console.log('āœ… Request body parsed successfully'); + } catch (parseError) { + console.error('āŒ Failed to parse request body:', parseError); + return NextResponse.json( + { error: 'Invalid JSON in request body' }, + { status: 400 } + ); + } + + const { type, ...data } = body; + console.log(`šŸ“ Form type: ${type}`); + console.log(`šŸ“‹ Form data keys: ${Object.keys(data).join(', ')}`); + + if (!type) { + console.error('āŒ No form type specified'); + return NextResponse.json( + { error: 'Form type is required' }, + { status: 400 } + ); + } + + // Route to appropriate handler based on form type + let result; + switch (type) { + case 'newsletter': + if (!data.email) { + console.error('āŒ Newsletter: Email is required'); + return NextResponse.json({ error: 'Email is required' }, { status: 400 }); + } + result = await handleNewsletter(data); + break; + + case 'contact': + if (!data.fullName || !data.email) { + console.error('āŒ Contact: Full name and email are required'); + return NextResponse.json({ error: 'Full name and email are required' }, { status: 400 }); + } + result = await handleContact(data); + break; + + case 'career': + if (!data.fullName || !data.email || !data.phone) { + console.error('āŒ Career: Full name, email, and phone are required'); + return NextResponse.json({ error: 'Full name, email, and phone are required' }, { status: 400 }); + } + result = await handleCareer(data); + break; + + default: + console.error('āŒ Invalid form type:', type); + return NextResponse.json({ error: 'Invalid form type' }, { status: 400 }); + } + + console.log('āœ… Email sent successfully!'); + console.log('šŸ“§ Message ID:', result.messageId); + console.log('šŸŽ‰ === EMAIL API ROUTE SUCCESS ===\n'); + + return NextResponse.json( + { + message: 'Email sent successfully', + messageId: result.messageId, + type: type + }, + { status: 200 } + ); + + } catch (error) { + console.error('\nšŸ’„ === EMAIL API ROUTE ERROR ==='); + console.error('Error name:', error.name); + console.error('Error message:', error.message); + console.error('Error code:', error.code); + console.error('Error stack:', error.stack); + + // Provide more specific error messages + let errorMessage = 'Failed to send email'; + let statusCode = 500; + + if (error.code === 'EAUTH') { + errorMessage = 'Authentication failed. Please check your Zoho email and app password.'; + console.error('šŸ” Authentication issue - check ZOHO_EMAIL and ZOHO_PASSWORD'); + } else if (error.code === 'ECONNECTION' || error.code === 'ETIMEDOUT') { + errorMessage = 'Connection to email server failed. Please try again.'; + console.error('🌐 Network connection issue'); + } else if (error.code === 'EMESSAGE') { + errorMessage = 'Invalid email message format.'; + statusCode = 400; + console.error('šŸ“§ Email format issue'); + } + + console.error('šŸ’„ === END ERROR DETAILS ===\n'); + + return NextResponse.json( + { + error: errorMessage, + details: error.message, + code: error.code + }, + { status: statusCode } + ); + } +} \ No newline at end of file diff --git a/components/common/Careerform.jsx b/components/common/Careerform.jsx index 82fded4..90e2ba4 100644 --- a/components/common/Careerform.jsx +++ b/components/common/Careerform.jsx @@ -12,6 +12,8 @@ export default function Careerform() { resume: null }); const [uploadStatus, setUploadStatus] = useState(''); + const [isSubmitting, setIsSubmitting] = useState(false); + const [submitStatus, setSubmitStatus] = useState(null); const handleInputChange = (e) => { const { id, value } = e.target; @@ -39,15 +41,25 @@ export default function Careerform() { return; } - setFormData(prev => ({ - ...prev, - resume: file - })); - setUploadStatus(`${file.name} uploaded successfully`); + // Convert file to base64 + const reader = new FileReader(); + reader.onload = () => { + const base64 = reader.result.split(',')[1]; // Remove data:mime;base64, prefix + setFormData(prev => ({ + ...prev, + resume: { + name: file.name, + data: base64, + type: file.type + } + })); + setUploadStatus(`${file.name} uploaded successfully`); + }; + reader.readAsDataURL(file); } }; - const handleSubmit = (e) => { + const handleSubmit = async (e) => { e.preventDefault(); // Basic form validation @@ -61,40 +73,47 @@ export default function Careerform() { return; } - // Here you would typically send the form data to your backend - console.log('Form submitted:', formData); - - // Example of how you might handle the form submission - const submitData = new FormData(); - submitData.append('fullName', formData.fullName); - submitData.append('email', formData.email); - submitData.append('phone', formData.phone); - submitData.append('roles', formData.roles); - submitData.append('resume', formData.resume); + setIsSubmitting(true); + setSubmitStatus(null); - // Replace with your actual API endpoint - // fetch('/api/submit-application', { - // method: 'POST', - // body: submitData - // }).then(response => { - // // Handle response - // }); + try { + const response = await fetch('/api/contact', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + type: 'career', + ...formData, + }), + }); - alert('Application submitted successfully!'); - - // Reset form - setFormData({ - fullName: '', - email: '', - phone: '', - roles: '', - resume: null - }); - setUploadStatus(''); - - // Reset file input - const fileInput = document.getElementById('resume-upload'); - if (fileInput) fileInput.value = ''; + if (response.ok) { + setSubmitStatus('success'); + + // Reset form + setFormData({ + fullName: '', + email: '', + phone: '', + roles: '', + resume: null + }); + setUploadStatus(''); + + // Reset file input + const fileInput = document.getElementById('resume-upload'); + if (fileInput) fileInput.value = ''; + } else { + setSubmitStatus('error'); + } + } catch (error) { + console.error('Error:', error); + setSubmitStatus('error'); + } finally { + setIsSubmitting(false); + setTimeout(() => setSubmitStatus(null), 5000); + } }; return ( @@ -120,6 +139,20 @@ export default function Careerform() {
+ {submitStatus && ( +
+ {submitStatus === 'success' + ? 'Application submitted successfully! We will review your application and get back to you soon.' + : 'Failed to submit application. Please try again.'} +
+ )}
- - {/*
- item -
*/} ); diff --git a/components/common/Contact.jsx b/components/common/Contact.jsx index f33780b..d50fac2 100644 --- a/components/common/Contact.jsx +++ b/components/common/Contact.jsx @@ -1,9 +1,63 @@ "use client"; -import React from "react"; +import React, { useState } from "react"; import Link from "next/link"; import Image from "next/image"; export default function Contact() { + const [formData, setFormData] = useState({ + fullName: '', + email: '', + phone: '', + message: '' + }); + const [isSubmitting, setIsSubmitting] = useState(false); + const [submitStatus, setSubmitStatus] = useState(null); + + const handleInputChange = (e) => { + const { id, value } = e.target; + setFormData(prev => ({ + ...prev, + [id]: value + })); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + setIsSubmitting(true); + setSubmitStatus(null); + + try { + const response = await fetch('/api/contact', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + type: 'contact', + ...formData, + }), + }); + + if (response.ok) { + setSubmitStatus('success'); + setFormData({ + fullName: '', + email: '', + phone: '', + message: '' + }); + } else { + setSubmitStatus('error'); + } + } catch (error) { + console.error('Error:', error); + setSubmitStatus('error'); + } finally { + setIsSubmitting(false); + setTimeout(() => setSubmitStatus(null), 5000); + } + }; + return (
@@ -22,30 +76,37 @@ export default function Contact() { Call us for urgent Inquiry

- {/* - Get Direction - - */}
-
e.preventDefault()} className="form-contact" style={{ gap: "10px !important" }}> + {submitStatus && ( +
+ {submitStatus === 'success' + ? 'Message sent successfully! We will get back to you soon.' + : 'Failed to send message. Please try again.'} +
+ )} +
-
@@ -56,6 +117,8 @@ export default function Contact() { type="email" placeholder="Your email address*" id="email" + value={formData.email} + onChange={handleInputChange} required />
@@ -68,6 +131,8 @@ export default function Contact() { type="text" placeholder="Your phone number" id="phone" + value={formData.phone} + onChange={handleInputChange} />
@@ -79,29 +144,26 @@ export default function Contact() { className="message" placeholder="Write your message here..." id="message" - defaultValue={""} + value={formData.message} + onChange={handleInputChange} /> - - - Add an attachment - -
- {/*
- item -
*/} ); } \ No newline at end of file diff --git a/components/footers/Footer3.jsx b/components/footers/Footer3.jsx index e55f19e..655b87a 100644 --- a/components/footers/Footer3.jsx +++ b/components/footers/Footer3.jsx @@ -1,6 +1,5 @@ "use client"; import React, { useEffect, useState } from "react"; -import axios from "axios"; import Link from "next/link"; import Image from "next/image"; @@ -16,30 +15,34 @@ export default function Footer3() { }; const sendEmail = async (e) => { - e.preventDefault(); // Prevent default form submission behavior + e.preventDefault(); const email = e.target.email.value; try { - const response = await axios.post( - "https://express-brevomail.vercel.app/api/contacts", - { + const response = await fetch('/api/contact', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + type: 'newsletter', email, - } - ); + }), + }); - if ([200, 201].includes(response.status)) { - e.target.reset(); // Reset the form - setSuccess(true); // Set success state + if (response.ok) { + e.target.reset(); + setSuccess(true); handleShowMessage(); } else { - setSuccess(false); // Handle unexpected responses + setSuccess(false); handleShowMessage(); } } catch (error) { - console.error("Error:", error.response?.data || "An error occurred"); - setSuccess(false); // Set error state + console.error('Error:', error); + setSuccess(false); handleShowMessage(); - e.target.reset(); // Reset the form + e.target.reset(); } }; @@ -63,13 +66,12 @@ export default function Footer3() { heading.addEventListener("click", toggleOpen); }); - // Clean up event listeners when the component unmounts return () => { headings.forEach((heading) => { heading.removeEventListener("click", toggleOpen); }); }; - }, []); // Empty dependency array means this will run only once on mount + }, []); return (