284 lines
15 KiB
TypeScript
284 lines
15 KiB
TypeScript
"use client";
|
|
|
|
import React, { useState, useEffect, useRef } from "react";
|
|
import ReCAPTCHA from "react-google-recaptcha";
|
|
import axios from "axios";
|
|
|
|
const ContactSection = () => {
|
|
const sectionRef = useRef<HTMLDivElement>(null);
|
|
const [formData, setFormData] = useState({
|
|
name: "",
|
|
phone: "",
|
|
email: "",
|
|
service: "",
|
|
message: "",
|
|
});
|
|
|
|
const [formErrors, setFormErrors] = useState<any>({});
|
|
const [captchaToken, setCaptchaToken] = useState<string | null>(null);
|
|
const [alert, setAlert] = useState({ show: false, type: "", message: "" });
|
|
|
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
|
|
const { name, value } = e.target;
|
|
setFormData((prev) => ({ ...prev, [name]: value }));
|
|
};
|
|
|
|
const handleCaptchaChange = (token: string | null) => {
|
|
setCaptchaToken(token);
|
|
};
|
|
|
|
useEffect(() => {
|
|
const observer = new IntersectionObserver(
|
|
(entries) => {
|
|
entries.forEach((entry) => {
|
|
if (entry.isIntersecting) {
|
|
const elements = entry.target.querySelectorAll(".wow");
|
|
elements.forEach((el) => {
|
|
const htmlEl = el as HTMLElement;
|
|
const delay = htmlEl.dataset.wowDelay || "0ms";
|
|
setTimeout(() => {
|
|
htmlEl.classList.add("animated");
|
|
|
|
if (htmlEl.classList.contains("fadeInLeft")) {
|
|
htmlEl.classList.add("fadeInLeft");
|
|
} else if (htmlEl.classList.contains("fadeInRight")) {
|
|
htmlEl.classList.add("fadeInRight");
|
|
} else {
|
|
htmlEl.classList.add("fadeInUp");
|
|
}
|
|
|
|
htmlEl.style.visibility = "visible";
|
|
}, parseInt(delay));
|
|
});
|
|
observer.unobserve(entry.target);
|
|
}
|
|
});
|
|
},
|
|
{ threshold: 0.1 }
|
|
);
|
|
|
|
if (sectionRef.current) {
|
|
observer.observe(sectionRef.current);
|
|
}
|
|
|
|
return () => observer.disconnect();
|
|
}, []);
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
|
|
const errors: any = {};
|
|
if (!formData.name.trim()) errors.name = "Name is required.";
|
|
if (!formData.phone.trim()) errors.phone = "Phone is required.";
|
|
if (!formData.email.trim()) errors.email = "Email is required.";
|
|
if (!formData.service.trim()) errors.service = "Please select a service.";
|
|
if (!formData.message.trim()) errors.message = "Message is required.";
|
|
if (!captchaToken) errors.captcha = "Please verify the CAPTCHA.";
|
|
|
|
setFormErrors(errors);
|
|
if (Object.keys(errors).length > 0) return;
|
|
|
|
const emailData = {
|
|
...formData,
|
|
message: `Service: ${formData.service}<br /><br />Message: ${formData.message}`,
|
|
to: "info@metatroncubesolutions.com",
|
|
senderName: "Metatroncube Careers Contact",
|
|
recaptchaToken: captchaToken,
|
|
};
|
|
|
|
try {
|
|
const res = await axios.post("https://mailserver.metatronnest.com/send", emailData, {
|
|
headers: { "Content-Type": "application/json" },
|
|
});
|
|
|
|
setAlert({
|
|
show: true,
|
|
type: "success",
|
|
message: res?.data?.message || "Message sent successfully!",
|
|
});
|
|
|
|
setFormData({
|
|
name: "",
|
|
phone: "",
|
|
email: "",
|
|
service: "",
|
|
message: "",
|
|
});
|
|
setCaptchaToken(null);
|
|
setFormErrors({});
|
|
} catch (error) {
|
|
console.error("❌ Error sending email:", error);
|
|
setAlert({
|
|
show: true,
|
|
type: "danger",
|
|
message: "Failed to send message. Please try again later.",
|
|
});
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (alert.show) {
|
|
const timer = setTimeout(() => {
|
|
setAlert((prev) => ({ ...prev, show: false }));
|
|
}, 5000);
|
|
return () => clearTimeout(timer);
|
|
}
|
|
}, [alert.show]);
|
|
|
|
return (
|
|
<section ref={sectionRef} className="contact-one">
|
|
<div className="container">
|
|
<div className="row align-items-center">
|
|
<div className="col-lg-8">
|
|
{/* <div className="contact-one__info wow fadeInLeft" data-wow-delay="100ms" style={{ visibility: "hidden" }}>
|
|
<div className="contact-one__info__icon">
|
|
<span className="fa-solid fa-headset"></span>
|
|
</div>
|
|
<h3 className="contact-one__info__title">
|
|
Let's call together just <span>contact</span> line
|
|
</h3>
|
|
<p className="contact-one__info__text">
|
|
<a href="tel:+16476797651">+1-647-679-7651</a>
|
|
</p>
|
|
|
|
</div> */}
|
|
</div>
|
|
<div className="col-lg-4">
|
|
<div className="contact-one__image wow fadeInRight" data-wow-delay="200ms" style={{ visibility: "hidden" }}>
|
|
<img src="/assets/images/about/7/4-top-right.webp" alt="Contact Support" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="container contact-one__container wow fadeInUp" data-wow-delay="100ms" style={{ visibility: "hidden", marginTop: "-113px" }}>
|
|
<div
|
|
className="contact-one__wrapper"
|
|
style={{ backgroundImage: "url(/assets/images/about/7/element-bottom-right.webp)" }}
|
|
>
|
|
<div className="row">
|
|
<div className="col-lg-6">
|
|
<div className="contact-one__image-two">
|
|
<img src="/assets/images/about/7/4-left-img.webp" alt="Business Growth" />
|
|
</div>
|
|
</div>
|
|
<div className="col-lg-6">
|
|
<div className="contact-one__content">
|
|
<div className="sec-title text-left">
|
|
<h6 className="sec-title__tagline">
|
|
<span className="sec-title__tagline__left"></span>
|
|
Get In Contact
|
|
<span className="sec-title__tagline__right"></span>
|
|
</h6>
|
|
<h3 className="sec-title__title" style={{ color: "#fff" }}>
|
|
Get in touch for a free business consultation.
|
|
</h3>
|
|
</div>
|
|
|
|
{alert.show && (
|
|
<div className={`alert alert-${alert.type === 'danger' ? 'danger' : 'success'} mb-4`} style={{ padding: '15px', color: '#fff', backgroundColor: alert.type === 'danger' ? 'rgba(255, 107, 107, 0.2)' : 'rgba(76, 175, 80, 0.2)', border: alert.type === 'danger' ? '1px solid #ff6b6b' : '1px solid #4CAF50', borderRadius: '8px' }}>
|
|
{alert.message}
|
|
</div>
|
|
)}
|
|
|
|
<form className="contact-one__form form-one" onSubmit={handleSubmit}> <div className="form-one__group">
|
|
<div className="mb-20">
|
|
<label className="form-label-custom">Full Name</label>
|
|
<input
|
|
type="text"
|
|
name="name"
|
|
placeholder="Full Name"
|
|
value={formData.name}
|
|
onChange={handleChange}
|
|
className="form-input-custom-global"
|
|
suppressHydrationWarning={true}
|
|
/>
|
|
{formErrors.name && <small className="text-danger">{formErrors.name}</small>}
|
|
</div>
|
|
<div className="mb-20">
|
|
<label className="form-label-custom">Email Address</label>
|
|
<input
|
|
type="email"
|
|
name="email"
|
|
placeholder="Email Address"
|
|
value={formData.email}
|
|
onChange={handleChange}
|
|
className="form-input-custom-global"
|
|
suppressHydrationWarning={true}
|
|
/>
|
|
{formErrors.email && <small className="text-danger">{formErrors.email}</small>}
|
|
</div>
|
|
<div className="mb-20">
|
|
<label className="form-label-custom">Phone Number</label>
|
|
<input
|
|
type="text"
|
|
name="phone"
|
|
placeholder="Phone Number"
|
|
value={formData.phone}
|
|
onChange={handleChange}
|
|
className="form-input-custom-global"
|
|
suppressHydrationWarning={true}
|
|
/>
|
|
{formErrors.phone && <small className="text-danger">{formErrors.phone}</small>}
|
|
</div>
|
|
<div className="mb-20">
|
|
<label className="form-label-custom">Select Service</label>
|
|
<select
|
|
name="service"
|
|
value={formData.service}
|
|
onChange={handleChange}
|
|
className="form-select-custom-styled-global"
|
|
suppressHydrationWarning={true}
|
|
>
|
|
<option value="">Select Service</option>
|
|
<option value="Website Development">Website Development</option>
|
|
<option value="Mobile Application Development">Mobile Application Development</option>
|
|
<option value="Graphic Designing">Graphic Designing</option>
|
|
<option value="UI / UX Designing">UI / UX Designing</option>
|
|
<option value="SEO & Content Writing">SEO & Content Writing</option>
|
|
<option value="Digital Marketing">Digital Marketing</option>
|
|
<option value="ERP Development & Implementation">ERP Development & Implementation</option>
|
|
</select>
|
|
{formErrors.service && <small className="text-danger">{formErrors.service}</small>}
|
|
</div>
|
|
<div className="form-one__control--full mb-20">
|
|
<label className="form-label-custom">Write Message</label>
|
|
<textarea
|
|
name="message"
|
|
placeholder="Write Message"
|
|
rows={4}
|
|
value={formData.message}
|
|
onChange={handleChange}
|
|
className="form-textarea-custom-global"
|
|
suppressHydrationWarning={true}
|
|
></textarea>
|
|
{formErrors.message && <small className="text-danger">{formErrors.message}</small>}
|
|
</div>
|
|
|
|
<div className="form-one__control--full mb-3 mt-3">
|
|
<ReCAPTCHA
|
|
sitekey="6LekfpwrAAAAAOTwuP1d2gg-Fv9UEsAjE2gjOQJl"
|
|
onChange={handleCaptchaChange}
|
|
/>
|
|
{formErrors.captcha && <small className="text-danger">{formErrors.captcha}</small>}
|
|
</div>
|
|
|
|
<div className="form-one__control--full">
|
|
<button type="submit" className="submit-btn-custom-global">
|
|
<b>SEND A Message</b>
|
|
<span></span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export default ContactSection;
|