Files
ignum/components/pages/contact/main.tsx
nabijonovdavronbek619@gmail.com dca26dbca1 contact page
2026-01-23 09:54:44 +05:00

320 lines
10 KiB
TypeScript

"use client";
import React from "react";
import { useState } from "react";
import Image from "next/image";
import { Mail, MapPin, Phone, Check } from "lucide-react";
import ContactHeader from "./contactHeader";
interface FormData {
firstName: string;
lastName: string;
email: string;
subject: string;
message: string;
agreeToPolicy: boolean;
}
interface FormErrors {
firstName?: string;
lastName?: string;
email?: string;
subject?: string;
message?: string;
agreeToPolicy?: string;
}
export function Contact() {
const [formData, setFormData] = useState<FormData>({
firstName: "",
lastName: "",
email: "",
subject: "",
message: "",
agreeToPolicy: false,
});
const [errors, setErrors] = useState<FormErrors>({});
const [isSubmitting, setIsSubmitting] = useState(false);
const [submitStatus, setSubmitStatus] = useState<
"idle" | "success" | "error"
>("idle");
const validateForm = (): boolean => {
const newErrors: FormErrors = {};
if (!formData.firstName.trim()) {
newErrors.firstName = "First name is required";
}
if (!formData.lastName.trim()) {
newErrors.lastName = "Last name is required";
}
if (!formData.email.trim()) {
newErrors.email = "Email is required";
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
newErrors.email = "Please enter a valid email";
}
if (!formData.subject.trim()) {
newErrors.subject = "Subject is required";
}
if (!formData.message.trim()) {
newErrors.message = "Message is required";
}
if (!formData.agreeToPolicy) {
newErrors.agreeToPolicy = "You must agree to the privacy policy";
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
const { name, value } = e.target;
setFormData((prev) => ({ ...prev, [name]: value }));
if (errors[name as keyof FormErrors]) {
setErrors((prev) => ({ ...prev, [name]: undefined }));
}
};
const handleCheckboxChange = () => {
setFormData((prev) => ({ ...prev, agreeToPolicy: !prev.agreeToPolicy }));
if (errors.agreeToPolicy) {
setErrors((prev) => ({ ...prev, agreeToPolicy: undefined }));
}
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!validateForm()) return;
setIsSubmitting(true);
setSubmitStatus("idle");
try {
const response = await fetch("/api/contact", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(formData),
});
if (response.ok) {
setSubmitStatus("success");
setFormData({
firstName: "",
lastName: "",
email: "",
subject: "",
message: "",
agreeToPolicy: false,
});
} else {
setSubmitStatus("error");
}
} catch {
setSubmitStatus("error");
} finally {
setIsSubmitting(false);
}
};
const contactInfo = [
{
icon: Mail,
title: "EMAIL",
detail: "support@fireforce",
},
{
icon: MapPin,
title: "OUR LOCATION",
detail: "Jl. Dr. Ir. Soekarno No. 99x Tabanan - Bali",
},
{
icon: Phone,
title: "PHONE",
detail: "+123-456-7890",
},
];
return (
<section className="relative min-h-175 w-full py-16 md:py-40">
{/* Background Image */}
<div className="absolute inset-0 z-0">
<Image
src="/images/contactBanner.jpg"
alt="Contact background"
fill
className="object-cover"
priority
/>
{/* Radial Gradient Overlay */}
<div
className="absolute inset-0"
style={{
background:
"radial-gradient(ellipse at bottom center, #d2610ab0 0%, #1e1d1ce3 70%)",
}}
/>
</div>
{/* Content */}
<div className="relative z-10 mx-auto max-w-4xl px-4 sm:px-6 lg:px-8">
<ContactHeader />
{/* Form */}
<form onSubmit={handleSubmit} className="space-y-4">
{/* First Row - Names */}
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<input
type="text"
name="firstName"
placeholder="First Name"
value={formData.firstName}
onChange={handleChange}
className={`w-full rounded-md border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
errors.firstName ? "border-red-500" : "border-transparent"
}`}
/>
{errors.firstName && (
<p className="mt-1 text-xs text-red-500">{errors.firstName}</p>
)}
</div>
<div>
<input
type="text"
name="lastName"
placeholder="Last Name"
value={formData.lastName}
onChange={handleChange}
className={`w-full rounded-md border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
errors.lastName ? "border-red-500" : "border-transparent"
}`}
/>
{errors.lastName && (
<p className="mt-1 text-xs text-red-500">{errors.lastName}</p>
)}
</div>
</div>
{/* Second Row - Email & Subject */}
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<div>
<input
type="email"
name="email"
placeholder="Your Email Address"
value={formData.email}
onChange={handleChange}
className={`w-full rounded-md border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
errors.email ? "border-red-500" : "border-transparent"
}`}
/>
{errors.email && (
<p className="mt-1 text-xs text-red-500">{errors.email}</p>
)}
</div>
<div>
<input
type="text"
name="subject"
placeholder="Subject"
value={formData.subject}
onChange={handleChange}
className={`w-full rounded-md border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
errors.subject ? "border-red-500" : "border-transparent"
}`}
/>
{errors.subject && (
<p className="mt-1 text-xs text-red-500">{errors.subject}</p>
)}
</div>
</div>
{/* Message Textarea */}
<div>
<textarea
name="message"
placeholder="Leave us a message"
rows={5}
value={formData.message}
onChange={handleChange}
className={`w-full resize-none rounded-md border bg-white px-4 py-3 text-sm text-gray-700 placeholder-gray-400 outline-none transition focus:ring-2 focus:ring-red-500 ${
errors.message ? "border-red-500" : "border-transparent"
}`}
/>
{errors.message && (
<p className="mt-1 text-xs text-red-500">{errors.message}</p>
)}
</div>
{/* Checkbox and Submit */}
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
<div className="flex items-center gap-3">
<button
type="button"
onClick={handleCheckboxChange}
className={`flex h-5 w-5 items-center justify-center rounded border-2 transition ${
formData.agreeToPolicy
? "border-red-600 bg-red-600"
: "border-gray-400 bg-transparent"
}`}
aria-label="Agree to privacy policy"
>
{formData.agreeToPolicy && (
<Check className="h-3 w-3 text-white" strokeWidth={3} />
)}
</button>
<span className="text-sm text-gray-300">
You agree to our friendly privacy policy
</span>
</div>
<button
type="submit"
disabled={isSubmitting}
className="rounded-full bg-red-600 px-8 py-3 text-sm font-semibold uppercase tracking-wider text-white transition hover:bg-red-700 disabled:cursor-not-allowed disabled:opacity-50"
>
{isSubmitting ? "Sending..." : "Send Message"}
</button>
</div>
{errors.agreeToPolicy && (
<p className="text-xs text-red-500">{errors.agreeToPolicy}</p>
)}
{/* Status Messages */}
{submitStatus === "success" && (
<p className="text-center text-sm text-green-400">
Message sent successfully!
</p>
)}
{submitStatus === "error" && (
<p className="text-center text-sm text-red-400">
Failed to send message. Please try again.
</p>
)}
</form>
{/* Contact Info */}
<div className="mt-12 grid grid-cols-1 gap-8 md:grid-cols-3">
{contactInfo.map((info) => (
<div
key={info.title}
className="flex flex-col items-center text-center"
>
<div className="mb-3 flex h-14 w-14 items-center justify-center rounded-full border-2 border-red-600">
<info.icon className="h-6 w-6 text-red-600" />
</div>
<h3 className="text-sm font-bold tracking-wider text-white">
{info.title}
</h3>
<p className="mt-1 text-sm text-gray-400">{info.detail}</p>
</div>
))}
</div>
</div>
</section>
);
}