sky-and-soil/src/components/ContactCTA.tsx

250 lines
13 KiB
TypeScript

"use client";
import { User, Phone, Mail, MapPin, Send } from "lucide-react";
import Image from "next/image";
import { useState, ChangeEvent, FormEvent, useEffect } from "react";
import ReCAPTCHA from "react-google-recaptcha";
import axios from "axios";
interface FormData {
name: string;
phone: string;
email: string;
location: string;
}
interface FormErrors {
name?: string;
phone?: string;
email?: string;
location?: string;
captcha?: string;
}
export default function ContactCTA() {
const [formData, setFormData] = useState<FormData>({
name: "",
phone: "",
email: "",
location: "",
});
const [captchaToken, setCaptchaToken] = useState<string | null>(null);
const [formErrors, setFormErrors] = useState<FormErrors>({});
const [alert, setAlert] = useState<{ show: boolean; type: string; message: string }>({
show: false,
type: "",
message: "",
});
const [isSubmitting, setIsSubmitting] = useState(false);
const handleChange = (e: ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
const { name, value } = e.target;
setFormData((prev) => ({ ...prev, [name]: value }));
// Clear error when user types
if (formErrors[name as keyof FormErrors]) {
setFormErrors(prev => ({ ...prev, [name]: undefined }));
}
};
const handleCaptchaChange = (token: string | null) => {
setCaptchaToken(token);
if (token && formErrors.captcha) {
setFormErrors(prev => ({ ...prev, captcha: undefined }));
}
};
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
const errors: FormErrors = {};
if (!formData.name.trim()) errors.name = "Name is required.";
if (!formData.phone.trim()) errors.phone = "Phone number is required.";
if (!formData.email.trim()) errors.email = "Email is required.";
if (!formData.location) errors.location = "Please select a location.";
if (!captchaToken) errors.captcha = "Please verify the CAPTCHA.";
setFormErrors(errors);
if (Object.keys(errors).length > 0) return;
setIsSubmitting(true);
const emailData = {
name: formData.name,
phone: formData.phone,
email: formData.email,
subject: `New Inquiry from ${formData.name} - ${formData.location}`,
message: `Name: ${formData.name}<br />Phone: ${formData.phone}<br />Email: ${formData.email}<br />Location Interest: ${formData.location}`,
to: "hello@skyandsoil.com",
senderName: "Sky and Soil Contact Form",
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! We will contact you soon.",
});
setFormData({ name: "", phone: "", email: "", location: "" });
setCaptchaToken(null);
setFormErrors({});
} catch (error) {
setAlert({
show: true,
type: "danger",
message: "Failed to send message. Please try again later.",
});
} finally {
setIsSubmitting(false);
}
};
useEffect(() => {
if (alert.show) {
const timer = setTimeout(() => {
setAlert(prev => ({ ...prev, show: false }));
}, 5000);
return () => clearTimeout(timer);
}
}, [alert.show]);
return (
<section id="contact" className="relative py-24 bg-[#f3f1e6] dark:bg-gray-900">
<div className="relative z-10 max-w-6xl mx-auto px-6">
<div className="bg-white dark:bg-gray-800 rounded-3xl shadow-2xl overflow-hidden border border-gray-100 dark:border-gray-700 flex flex-col md:flex-row">
{/* Left Side - Form */}
<div className="w-full md:w-1/2 p-8 md:p-12">
<div className="text-left mb-8">
<h2 className="text-3xl md:text-4xl font-bold tracking-tight text-foreground mb-4">
Ready to Visit Aurora Springs?
</h2>
<p className="text-gray-600 dark:text-gray-400">
Schedule a private tour or request a call back from our relationship manager.
</p>
</div>
<form onSubmit={handleSubmit} className="space-y-5">
{alert.show && (
<div className={`p-4 rounded-xl text-sm font-medium ${alert.type === 'success' ? 'bg-green-50 text-green-700 border border-green-200' : 'bg-red-50 text-red-700 border border-red-200'}`}>
{alert.message}
</div>
)}
<div className="relative group">
<div className="absolute left-4 top-1/2 -translate-y-1/2 text-gray-400 group-focus-within:text-primary transition-colors">
<User size={20} />
</div>
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
placeholder="Your Name"
className={`w-full pl-12 pr-4 py-4 rounded-xl bg-gray-50 dark:bg-gray-700/50 border ${formErrors.name ? 'border-red-500' : 'border-gray-200 dark:border-gray-600'} text-foreground placeholder-gray-400 dark:placeholder-gray-500 focus:border-primary focus:ring-4 focus:ring-primary/10 outline-none transition-all duration-300`}
/>
{formErrors.name && <small className="text-red-500 text-xs ml-1">{formErrors.name}</small>}
</div>
<div className="relative group">
<div className="absolute left-4 top-1/2 -translate-y-1/2 text-gray-400 group-focus-within:text-primary transition-colors">
<Phone size={20} />
</div>
<input
type="tel"
name="phone"
value={formData.phone}
onChange={handleChange}
placeholder="Phone Number"
className={`w-full pl-12 pr-4 py-4 rounded-xl bg-gray-50 dark:bg-gray-700/50 border ${formErrors.phone ? 'border-red-500' : 'border-gray-200 dark:border-gray-600'} text-foreground placeholder-gray-400 dark:placeholder-gray-500 focus:border-primary focus:ring-4 focus:ring-primary/10 outline-none transition-all duration-300`}
/>
{formErrors.phone && <small className="text-red-500 text-xs ml-1">{formErrors.phone}</small>}
</div>
<div className="relative group">
<div className="absolute left-4 top-1/2 -translate-y-1/2 text-gray-400 group-focus-within:text-primary transition-colors">
<Mail size={20} />
</div>
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
placeholder="Email Address"
className={`w-full pl-12 pr-4 py-4 rounded-xl bg-gray-50 dark:bg-gray-700/50 border ${formErrors.email ? 'border-red-500' : 'border-gray-200 dark:border-gray-600'} text-foreground placeholder-gray-400 dark:placeholder-gray-500 focus:border-primary focus:ring-4 focus:ring-primary/10 outline-none transition-all duration-300`}
/>
{formErrors.email && <small className="text-red-500 text-xs ml-1">{formErrors.email}</small>}
</div>
<div className="relative group">
<div className="absolute left-4 top-1/2 -translate-y-1/2 text-gray-400 group-focus-within:text-primary transition-colors">
<MapPin size={20} />
</div>
<select
name="location"
value={formData.location}
onChange={handleChange}
className={`w-full pl-12 pr-4 py-4 rounded-xl bg-gray-50 dark:bg-gray-700/50 border ${formErrors.location ? 'border-red-500' : 'border-gray-200 dark:border-gray-600'} text-gray-600 dark:text-gray-300 focus:border-primary focus:ring-4 focus:ring-primary/10 outline-none transition-all duration-300 appearance-none`}
>
<option value="">Select Preferred Location</option>
<option value="North Bengaluru">North Bengaluru</option>
<option value="Whitefield">Whitefield</option>
<option value="Sarjapur">Sarjapur</option>
</select>
<div className="absolute right-4 top-1/2 -translate-y-1/2 pointer-events-none">
<svg className="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 9l-7 7-7-7" />
</svg>
</div>
{formErrors.location && <small className="text-red-500 text-xs ml-1">{formErrors.location}</small>}
</div>
<div className="mt-2">
<ReCAPTCHA
sitekey="6Lea8ZYrAAAAAHaghaLjDx_K084IFATZby7Rzqhl"
onChange={handleCaptchaChange}
/>
{formErrors.captcha && <small className="text-red-500 text-xs ml-1">{formErrors.captcha}</small>}
</div>
<button
type="submit"
disabled={isSubmitting}
className={`w-full py-4 text-base font-semibold text-white bg-primary rounded-xl hover:bg-blue-600 transition-all shadow-lg hover:shadow-primary/30 active:scale-[0.98] flex items-center justify-center gap-2 group ${isSubmitting ? 'opacity-70 cursor-not-allowed' : ''}`}
>
<span>{isSubmitting ? 'Sending...' : 'Request a Call Back'}</span>
{!isSubmitting && <Send size={18} className="group-hover:translate-x-1 transition-transform" />}
</button>
</form>
<p className="mt-6 text-xs text-gray-400 dark:text-gray-500 flex items-center gap-2">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
</svg>
We respect your privacy. No spam, ever.
</p>
</div>
{/* Right Side - Image */}
<div className="w-full md:w-1/2 relative min-h-[400px] md:min-h-full">
<Image
src="/assets/images/home/ready.webp"
alt="Luxury Interior"
fill
className="object-cover"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent md:bg-gradient-to-l" />
</div>
</div>
</div>
</section>
);
}