281 lines
10 KiB
TypeScript
281 lines
10 KiB
TypeScript
"use client";
|
||
|
||
import React, { useState, useEffect } from "react";
|
||
import ReCAPTCHA from "react-google-recaptcha";
|
||
import axios from "axios";
|
||
import Link from 'next/link';
|
||
|
||
export default function Hero() {
|
||
const [formData, setFormData] = useState({
|
||
company: "",
|
||
name: "",
|
||
phone: "",
|
||
email: "",
|
||
product: "",
|
||
city: "",
|
||
quantity: ""
|
||
});
|
||
|
||
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 | HTMLSelectElement>) => {
|
||
const { name, value } = e.target;
|
||
setFormData((prev) => ({ ...prev, [name]: value }));
|
||
};
|
||
|
||
const handleCaptchaChange = (token: string | null) => {
|
||
setCaptchaToken(token);
|
||
};
|
||
|
||
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.product.trim()) errors.product = "Please select a product.";
|
||
if (!captchaToken) errors.captcha = "Please verify the CAPTCHA.";
|
||
|
||
setFormErrors(errors);
|
||
if (Object.keys(errors).length > 0) return;
|
||
|
||
const emailData = {
|
||
name: formData.name,
|
||
email: formData.email,
|
||
phone: formData.phone,
|
||
message: `
|
||
<b>Company:</b> ${formData.company}<br />
|
||
<b>Product:</b> ${formData.product}<br />
|
||
<b>Job Site City:</b> ${formData.city}<br />
|
||
<b>Quantity:</b> ${formData.quantity}
|
||
`,
|
||
to: "info@vgfenceproducts.com",
|
||
senderName: "VG Fence Hero Form",
|
||
recaptchaToken: captchaToken,
|
||
};
|
||
|
||
setAlert({ show: true, type: "info", message: "Sending your request..." });
|
||
|
||
try {
|
||
await axios.post("https://mailserver.metatronnest.com/send", emailData, {
|
||
headers: { "Content-Type": "application/json" },
|
||
});
|
||
|
||
setAlert({
|
||
show: true,
|
||
type: "success",
|
||
message: "Thank you! Your quote request has been sent successfully.",
|
||
});
|
||
|
||
setFormData({
|
||
company: "",
|
||
name: "",
|
||
phone: "",
|
||
email: "",
|
||
product: "",
|
||
city: "",
|
||
quantity: ""
|
||
});
|
||
setCaptchaToken(null);
|
||
setFormErrors({});
|
||
} catch (error) {
|
||
console.error("❌ Error sending email:", error);
|
||
setAlert({
|
||
show: true,
|
||
type: "danger",
|
||
message: "Failed to send request. Please try again later.",
|
||
});
|
||
}
|
||
};
|
||
|
||
useEffect(() => {
|
||
if (alert.show && alert.type !== "info") {
|
||
const timer = setTimeout(() => {
|
||
setAlert((prev) => ({ ...prev, show: false }));
|
||
}, 5000);
|
||
return () => clearTimeout(timer);
|
||
}
|
||
}, [alert.show, alert.type]);
|
||
|
||
return (
|
||
<section className="hero">
|
||
<div className="hero-pattern"></div>
|
||
<div className="hero-accent"></div>
|
||
<div className="hero-accent2"></div>
|
||
|
||
<div className="hero-left">
|
||
<div className="hero-eyebrow">Kitchener–Waterloo Region · Ontario</div>
|
||
<h1 className="hero-h1">
|
||
Ontario's B2B<br />
|
||
<em>Fence Supply</em><br />
|
||
Partner
|
||
</h1>
|
||
<p className="hero-sub">
|
||
Supplying contractors, builders, and property managers across Ontario with{' '}
|
||
<strong>chain link, ornamental, composite, glass railing, and stain products</strong> —
|
||
with same-day job site delivery across a 250km radius from KWC.
|
||
</p>
|
||
<div className="hero-btns">
|
||
<Link href="#quote" className="btn-primary">Request contractor pricing</Link>
|
||
<Link href="/products" className="btn-secondary">View all products</Link>
|
||
</div>
|
||
<div className="hero-stats">
|
||
<div>
|
||
<div className="stat-val">3+</div>
|
||
<div className="stat-label">Years serving KWC</div>
|
||
</div>
|
||
<div>
|
||
<div className="stat-val">250km</div>
|
||
<div className="stat-label">Delivery radius</div>
|
||
</div>
|
||
<div>
|
||
<div className="stat-val">9+</div>
|
||
<div className="stat-label">Product lines</div>
|
||
</div>
|
||
<div>
|
||
<div className="stat-val">B2B</div>
|
||
<div className="stat-label">Contractor focus</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="hero-right" id="quote">
|
||
<div className="quote-card">
|
||
<div className="quote-card-title">Request a quote</div>
|
||
<div className="quote-card-sub">Response within 2 business hours · Contractor pricing available</div>
|
||
|
||
{alert.show && (
|
||
<div className={`alert alert-${alert.type === 'danger' ? 'danger' : (alert.type === 'info' ? 'info' : 'success')} mb-4`} style={{
|
||
padding: '12px 16px',
|
||
borderRadius: '8px',
|
||
fontSize: '14px',
|
||
marginBottom: '20px',
|
||
background: alert.type === 'danger' ? '#fee2e2' : (alert.type === 'info' ? '#e0f2fe' : '#f0fdf4'),
|
||
color: alert.type === 'danger' ? '#991b1b' : (alert.type === 'info' ? '#075985' : '#166534'),
|
||
border: `1px solid ${alert.type === 'danger' ? '#fecaca' : (alert.type === 'info' ? '#bae6fd' : '#bbf7d0')}`
|
||
}}>
|
||
{alert.message}
|
||
</div>
|
||
)}
|
||
|
||
<form className="quote-form" onSubmit={handleSubmit}>
|
||
<div className="form-row">
|
||
<div className="form-group">
|
||
<label className="form-label">Company name</label>
|
||
<input
|
||
className="form-input"
|
||
type="text"
|
||
name="company"
|
||
placeholder="ABC Fence Co."
|
||
value={formData.company}
|
||
onChange={handleChange}
|
||
/>
|
||
</div>
|
||
<div className="form-group">
|
||
<label className="form-label">Your name</label>
|
||
<input
|
||
className="form-input"
|
||
type="text"
|
||
name="name"
|
||
placeholder="John Smith"
|
||
value={formData.name}
|
||
onChange={handleChange}
|
||
style={{ borderColor: formErrors.name ? '#ef4444' : '' }}
|
||
/>
|
||
</div>
|
||
</div>
|
||
<div className="form-row">
|
||
<div className="form-group">
|
||
<label className="form-label">Phone</label>
|
||
<input
|
||
className="form-input"
|
||
type="tel"
|
||
name="phone"
|
||
placeholder="519-xxx-xxxx"
|
||
value={formData.phone}
|
||
onChange={handleChange}
|
||
style={{ borderColor: formErrors.phone ? '#ef4444' : '' }}
|
||
/>
|
||
</div>
|
||
<div className="form-group">
|
||
<label className="form-label">Email</label>
|
||
<input
|
||
className="form-input"
|
||
type="email"
|
||
name="email"
|
||
placeholder="you@company.com"
|
||
value={formData.email}
|
||
onChange={handleChange}
|
||
style={{ borderColor: formErrors.email ? '#ef4444' : '' }}
|
||
/>
|
||
</div>
|
||
</div>
|
||
<div className="form-group">
|
||
<label className="form-label">Product needed</label>
|
||
<select
|
||
className="form-select"
|
||
name="product"
|
||
value={formData.product}
|
||
onChange={handleChange}
|
||
style={{ borderColor: formErrors.product ? '#ef4444' : '' }}
|
||
>
|
||
<option value="">Select a product...</option>
|
||
<option>Aluminum railing</option>
|
||
<option>Chain link fence — commercial</option>
|
||
<option>Chain link fence — residential</option>
|
||
<option>Composite fence</option>
|
||
<option>Expert Stain & Seal products</option>
|
||
<option>Fence armor (post caps / guards)</option>
|
||
<option>Glass railing</option>
|
||
<option>Ornamental / iron fence</option>
|
||
<option>Temporary fence rental</option>
|
||
<option>Multiple products</option>
|
||
</select>
|
||
</div>
|
||
<div className="form-row">
|
||
<div className="form-group">
|
||
<label className="form-label">Job site city</label>
|
||
<input
|
||
className="form-input"
|
||
type="text"
|
||
name="city"
|
||
placeholder="Kitchener, Guelph..."
|
||
value={formData.city}
|
||
onChange={handleChange}
|
||
/>
|
||
</div>
|
||
<div className="form-group">
|
||
<label className="form-label">Approximate quantity</label>
|
||
<input
|
||
className="form-input"
|
||
type="text"
|
||
name="quantity"
|
||
placeholder="e.g. 200 linear ft"
|
||
value={formData.quantity}
|
||
onChange={handleChange}
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="form-group">
|
||
<ReCAPTCHA
|
||
sitekey="6LekfpwrAAAAAOTwuP1d2gg-Fv9UEsAjE2gjOQJl"
|
||
onChange={handleCaptchaChange}
|
||
/>
|
||
{formErrors.captcha && <small style={{ color: '#ef4444', fontSize: '11px', marginTop: '4px', display: 'block' }}>{formErrors.captcha}</small>}
|
||
</div>
|
||
|
||
<button type="submit" className="form-submit" disabled={alert.type === "info"}>
|
||
{alert.type === "info" ? "Sending..." : "Send quote request →"}
|
||
</button>
|
||
<div className="form-note">Or call us directly · info@vgfenceproducts.com</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|