contact integration updated

This commit is contained in:
Selvi 2026-04-23 14:28:41 +05:30
parent 3240bdaf4c
commit 4a9948c6e0
5 changed files with 376 additions and 144 deletions

View File

@ -19,6 +19,8 @@ const ContactClient = () => {
const [formStatus, setFormStatus] = useState<"idle" | "submitting" | "success" | "error">("idle"); const [formStatus, setFormStatus] = useState<"idle" | "submitting" | "success" | "error">("idle");
const [tcError, setTcError] = useState(false); const [tcError, setTcError] = useState(false);
const [nlEmail, setNlEmail] = useState("");
const [nlStatus, setNlStatus] = useState<"idle" | "submitting" | "success" | "error">("idle");
const [openFaq, setOpenFaq] = useState<number | null>(null); const [openFaq, setOpenFaq] = useState<number | null>(null);
useEffect(() => { useEffect(() => {
@ -104,6 +106,34 @@ const ContactClient = () => {
} }
}; };
const submitNewsletterForm = async (e: React.FormEvent) => {
e.preventDefault();
if (!nlEmail || !nlEmail.includes("@")) return;
setNlStatus("submitting");
const emailData = {
name: "Newsletter Subscriber",
email: nlEmail,
phone: "N/A",
service: "Newsletter Subscription",
message: `A new user has subscribed to the newsletter: <b>${nlEmail}</b>`,
to: "info@vgfenceproducts.com",
senderName: "VG Fence Contact Page Newsletter",
};
try {
await axios.post("https://mailserver.metatronnest.com/send", emailData, {
headers: { "Content-Type": "application/json" },
});
setNlStatus("success");
setNlEmail("");
} catch (error) {
console.error("❌ Error subscribing to newsletter:", error);
setNlStatus("error");
}
};
return ( return (
<div className="contact-page"> <div className="contact-page">
@ -658,18 +688,27 @@ const ContactClient = () => {
<div className="nl-eye">Stay in the loop</div> <div className="nl-eye">Stay in the loop</div>
<h2 className="nl-h2">Product updates &amp;<br /><span>contractor deals.</span></h2> <h2 className="nl-h2">Product updates &amp;<br /><span>contractor deals.</span></h2>
<p className="nl-sub">New products, seasonal promotions, and industry tips delivered to your inbox. No spam, unsubscribe anytime.</p> <p className="nl-sub">New products, seasonal promotions, and industry tips delivered to your inbox. No spam, unsubscribe anytime.</p>
<div className="nl-form"> <div className="nl-form-wrap">
<input className="nl-input" type="email" placeholder="Enter your email address" id="nl-input" /> {nlStatus === "success" ? (
<button className="nl-btn" onClick={() => { <div className="nl-success-msg" style={{ padding: '12px 20px', background: '#16A34A', color: 'white', borderRadius: '4px', fontWeight: 600, textAlign: 'center' }}>
const input = document.getElementById('nl-input') as HTMLInputElement; Thank you! You've been subscribed successfully.
if (input && input.value.includes('@')) { </div>
const btn = document.querySelector('.nl-btn') as HTMLElement; ) : (
btn.textContent = 'Subscribed ✓'; <form className="nl-form" onSubmit={submitNewsletterForm}>
btn.style.background = '#16A34A'; <input
input.value = ''; className="nl-input"
input.placeholder = 'Thank you — you\'re subscribed!'; type="email"
} placeholder={nlStatus === "error" ? "Error occurred. Try again?" : "Enter your email address"}
}}>Subscribe </button> value={nlEmail}
onChange={(e) => setNlEmail(e.target.value)}
required
disabled={nlStatus === "submitting"}
/>
<button type="submit" className="nl-btn" disabled={nlStatus === "submitting"}>
{nlStatus === "submitting" ? "..." : "Subscribe →"}
</button>
</form>
)}
</div> </div>
<p className="nl-note">Join contractors and builders across Ontario · 16 emails per month</p> <p className="nl-note">Join contractors and builders across Ontario · 16 emails per month</p>
</div> </div>

View File

@ -378,6 +378,7 @@
.model-image-col { .model-image-col {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%;
} }
.photo-area { .photo-area {
@ -428,17 +429,16 @@
display: grid; display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
gap: 48px; gap: 48px;
align-items: stretch; /* Key for matching height */ align-items: start;
margin-top: 40px; margin-top: 40px;
} }
.photo-area-large { .photo-area-large {
flex: 1; height: 500px;
min-height: 300px;
} }
.photo-area-small { .photo-area-small {
min-height: 180px; height: 340px;
} }
.photo-area img { .photo-area img {

View File

@ -1,8 +1,65 @@
"use client"; "use client";
import React from 'react'; import React, { useState } from 'react';
import axios from 'axios';
const ChainLinkQuote = () => { const ChainLinkQuote = () => {
const [formData, setFormData] = useState({
company: '',
name: '',
phone: '',
email: '',
material: '',
city: '',
footage: ''
});
const [status, setStatus] = useState<"idle" | "submitting" | "success" | "error">("idle");
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setStatus("submitting");
const emailData = {
name: formData.name,
email: formData.email,
phone: formData.phone,
service: formData.material || "Chain Link Quote",
message: `
<b>Company:</b> ${formData.company}<br />
<b>Material Needed:</b> ${formData.material}<br />
<b>Job Site City:</b> ${formData.city}<br />
<b>Linear Footage:</b> ${formData.footage}
`,
to: "info@vgfenceproducts.com",
senderName: "VG Fence Chain Link Page",
};
try {
await axios.post("https://mailserver.metatronnest.com/send", emailData, {
headers: { "Content-Type": "application/json" },
});
setStatus("success");
setFormData({
company: '',
name: '',
phone: '',
email: '',
material: '',
city: '',
footage: ''
});
} catch (error) {
console.error("❌ Error sending chain link quote request:", error);
setStatus("error");
}
};
return ( return (
<section className="quote-cta"> <section className="quote-cta">
<div className="quote-inner"> <div className="quote-inner">
@ -11,56 +68,71 @@ const ChainLinkQuote = () => {
<p>Fill in the quick form and we'll come back to you with contractor pricing within 2 business hours. Bulk orders welcome we supply fence contractors, builders, and property managers across Ontario.</p> <p>Fill in the quick form and we'll come back to you with contractor pricing within 2 business hours. Bulk orders welcome we supply fence contractors, builders, and property managers across Ontario.</p>
</div> </div>
<div className="quote-form-card"> <div className="quote-form-card">
<div className="q-form-title">Request a quote</div> {status === "success" ? (
<div className="q-form-sub">Response within 2 business hours</div> <div className="q-success-msg" style={{ padding: '40px 20px', textAlign: 'center' }}>
<div className="qrow"> <div style={{ fontSize: '48px', marginBottom: '20px' }}></div>
<div> <h3 style={{ color: '#fff', marginBottom: '10px' }}>Quote Request Sent!</h3>
<label className="ql">Company name</label> <p style={{ color: '#fff' }}>Thank you. We'll respond within 2 business hours.</p>
<input className="qi" type="text" placeholder="ABC Fence Co." /> <button className="qbtn" style={{ marginTop: '20px' }} onClick={() => setStatus("idle")}>Send another request</button>
</div> </div>
<div> ) : (
<label className="ql">Your name</label> <form onSubmit={handleSubmit}>
<input className="qi" type="text" placeholder="John Smith" /> <div className="q-form-title">Request a quote</div>
</div> <div className="q-form-sub">Response within 2 business hours</div>
</div> <div className="qrow">
<div className="qrow"> <div>
<div> <label className="ql">Company name</label>
<label className="ql">Phone</label> <input className="qi" type="text" name="company" placeholder="ABC Fence Co." value={formData.company} onChange={handleChange} />
<input className="qi" type="tel" placeholder="519-xxx-xxxx" /> </div>
</div> <div>
<div> <label className="ql">Your name</label>
<label className="ql">Email</label> <input className="qi" type="text" name="name" placeholder="John Smith" value={formData.name} onChange={handleChange} required />
<input className="qi" type="email" placeholder="you@company.com" /> </div>
</div> </div>
</div> <div className="qrow">
<label className="ql">Material needed</label> <div>
<select className="qi"> <label className="ql">Phone</label>
<option value="">Select material type...</option> <input className="qi" type="tel" name="phone" placeholder="519-xxx-xxxx" value={formData.phone} onChange={handleChange} required />
<option>Chain link mesh galvanized</option> </div>
<option>Chain link mesh vinyl coated black</option> <div>
<option>Posts (terminal &amp; line)</option> <label className="ql">Email</label>
<option>Top rail</option> <input className="qi" type="email" name="email" placeholder="you@company.com" value={formData.email} onChange={handleChange} required />
<option>Gates &amp; gate hardware</option> </div>
<option>Hardware &amp; fittings pack</option> </div>
<option>Privacy slats</option> <label className="ql">Material needed</label>
<option>Barbed wire</option> <select className="qi" name="material" value={formData.material} onChange={handleChange} required>
<option>Complete material package</option> <option value="">Select material type...</option>
</select> <option>Chain link mesh galvanized</option>
<div className="qrow"> <option>Chain link mesh vinyl coated black</option>
<div> <option>Posts (terminal &amp; line)</option>
<label className="ql">Job site city</label> <option>Top rail</option>
<input className="qi" type="text" placeholder="Kitchener, Guelph..." /> <option>Gates &amp; gate hardware</option>
</div> <option>Hardware &amp; fittings pack</option>
<div> <option>Privacy slats</option>
<label className="ql">Linear footage</label> <option>Barbed wire</option>
<input className="qi" type="text" placeholder="e.g. 300 linear ft" /> <option>Complete material package</option>
</div> </select>
</div> <div className="qrow">
<button className="qbtn">Send quote request </button> <div>
<label className="ql">Job site city</label>
<input className="qi" type="text" name="city" placeholder="Kitchener, Guelph..." value={formData.city} onChange={handleChange} />
</div>
<div>
<label className="ql">Linear footage</label>
<input className="qi" type="text" name="footage" placeholder="e.g. 300 linear ft" value={formData.footage} onChange={handleChange} />
</div>
</div>
{status === "error" && <p style={{ color: 'red', fontSize: '14px', marginBottom: '10px' }}> Error sending request. Please try again.</p>}
<button className="qbtn" disabled={status === "submitting"}>
{status === "submitting" ? "Sending..." : "Send quote request →"}
</button>
</form>
)}
</div> </div>
</div> </div>
</section> </section>
); );
}; };
export default ChainLinkQuote; export default ChainLinkQuote;

View File

@ -1,4 +1,40 @@
"use client";
import React, { useState } from "react";
import axios from "axios";
export default function Newsletter() { export default function Newsletter() {
const [email, setEmail] = useState("");
const [status, setStatus] = useState<"idle" | "submitting" | "success" | "error">("idle");
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!email || !email.includes("@")) return;
setStatus("submitting");
const emailData = {
name: "Newsletter Subscriber",
email: email,
phone: "N/A",
service: "Newsletter Subscription",
message: `A new user has subscribed to the newsletter: <b>${email}</b>`,
to: "info@vgfenceproducts.com",
senderName: "VG Fence Newsletter",
};
try {
await axios.post("https://mailserver.metatronnest.com/send", emailData, {
headers: { "Content-Type": "application/json" },
});
setStatus("success");
setEmail("");
} catch (error) {
console.error("❌ Error subscribing to newsletter:", error);
setStatus("error");
}
};
return ( return (
<section className="newsletter-section"> <section className="newsletter-section">
<div className="newsletter-inner reveal"> <div className="newsletter-inner reveal">
@ -8,12 +44,37 @@ export default function Newsletter() {
New product arrivals, seasonal promotions, and industry tips delivered to your inbox.<br /> New product arrivals, seasonal promotions, and industry tips delivered to your inbox.<br />
No spam, unsubscribe anytime. No spam, unsubscribe anytime.
</p> </p>
<form className="newsletter-form" action="#" method="POST">
<input type="email" className="newsletter-input" placeholder="Enter your email address" required /> {status === "success" ? (
<button type="submit" className="newsletter-btn">Subscribe </button> <div className="newsletter-success" style={{ textAlign: 'center', padding: '20px', background: 'rgba(22, 163, 74, 0.1)', borderRadius: '8px', border: '1px solid #16A34A', color: '#16A34A', fontWeight: 600 }}>
</form> Thank you! You've been subscribed successfully.
</div>
) : (
<form className="newsletter-form" onSubmit={handleSubmit}>
<input
type="email"
className="newsletter-input"
placeholder="Enter your email address"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
disabled={status === "submitting"}
/>
<button type="submit" className="newsletter-btn" disabled={status === "submitting"}>
{status === "submitting" ? "Subscribing..." : "Subscribe →"}
</button>
</form>
)}
{status === "error" && (
<p style={{ color: '#ef4444', fontSize: '14px', marginTop: '10px', textAlign: 'center' }}>
Failed to subscribe. Please try again later.
</p>
)}
<div className="newsletter-note">Join contractors and builders across Ontario · 16 emails per month</div> <div className="newsletter-note">Join contractors and builders across Ontario · 16 emails per month</div>
</div> </div>
</section> </section>
); );
} }

View File

@ -1,6 +1,7 @@
"use client"; "use client";
import { useState } from 'react'; import { useState } from 'react';
import axios from 'axios';
export default function StainingQuote() { export default function StainingQuote() {
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
@ -8,19 +9,58 @@ export default function StainingQuote() {
email: '', email: '',
phone: '', phone: '',
projectType: 'fence', projectType: 'fence',
location: '',
size: '',
message: '' message: ''
}); });
const [status, setStatus] = useState<"idle" | "submitting" | "success" | "error">("idle");
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => { const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {
setFormData({ ...formData, [e.target.name]: e.target.value }); setFormData({ ...formData, [e.target.name]: e.target.value });
}; };
const handleSubmit = (e: React.FormEvent) => { const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
console.log('Form submitted:', formData);
alert('Thank you for your request! We will contact you shortly.'); setStatus("submitting");
const emailData = {
name: formData.name,
email: formData.email,
phone: formData.phone,
service: formData.projectType || "Wood Staining",
message: `
<b>Service:</b> ${formData.projectType}<br />
<b>Location:</b> ${formData.location}<br />
<b>Approx Size:</b> ${formData.size}<br /><br />
<b>Additional Notes:</b> ${formData.message || "N/A"}
`,
to: "info@vgfenceproducts.com",
senderName: "VG Fence Staining Page",
};
try {
await axios.post("https://mailserver.metatronnest.com/send", emailData, {
headers: { "Content-Type": "application/json" },
});
setStatus("success");
setFormData({
name: '',
email: '',
phone: '',
projectType: 'fence',
location: '',
size: '',
message: ''
});
} catch (error) {
console.error("❌ Error sending staining quote request:", error);
setStatus("error");
}
}; };
return ( return (
<section className="quote-cta quote-cta-orange" id="quote-section"> <section className="quote-cta quote-cta-orange" id="quote-section">
<div className="quote-inner"> <div className="quote-inner">
@ -31,92 +71,112 @@ export default function StainingQuote() {
</p> </p>
</div> </div>
<div className="quote-form-card"> <div className="quote-form-card">
<form onSubmit={handleSubmit}> {status === "success" ? (
<div className="q-form-title">REQUEST A STAINING QUOTE</div> <div className="q-form-success" style={{ padding: '30px', background: 'rgba(255,255,255,0.1)', borderRadius: '8px', border: '1px solid white', color: 'white', textAlign: 'center' }}>
<div className="q-form-sub text-white-70">Response within 2 business hours</div> <div style={{ fontSize: '40px', marginBottom: '15px' }}></div>
<h3 style={{ margin: '0 0 10px 0' }}>Request Sent!</h3>
<p style={{ margin: 0, opacity: 0.9 }}>Thank you. We'll be in touch within 2 business hours.</p>
<button type="button" className="qbtn btn-white-orange" style={{ marginTop: '20px' }} onClick={() => setStatus("idle")}>Send another request</button>
</div>
) : (
<form onSubmit={handleSubmit}>
<div className="q-form-title">REQUEST A STAINING QUOTE</div>
<div className="q-form-sub text-white-70">Response within 2 business hours</div>
<div className="qrow"> <div className="qrow">
<div> <div>
<label className="ql text-white">YOUR NAME</label> <label className="ql text-white">YOUR NAME</label>
<input
type="text"
name="name"
className="qi"
placeholder="John Smith"
required
value={formData.name}
onChange={handleChange}
/>
</div>
<div>
<label className="ql text-white">PHONE</label>
<input
type="tel"
name="phone"
className="qi"
placeholder="519-xxx-xxxx"
required
value={formData.phone}
onChange={handleChange}
/>
</div>
</div>
<label className="ql text-white">EMAIL</label>
<input <input
type="text" type="email"
name="name" name="email"
className="qi" className="qi"
placeholder="John Smith" placeholder="you@email.com"
required required
value={formData.name} value={formData.email}
onChange={handleChange} onChange={handleChange}
/> />
</div>
<div> <label className="ql text-white">SERVICE NEEDED</label>
<label className="ql text-white">PHONE</label> <select
<input name="projectType"
type="tel"
name="phone"
className="qi" className="qi"
placeholder="519-xxx-xxxx" value={formData.projectType}
required
value={formData.phone}
onChange={handleChange} onChange={handleChange}
/> >
</div> <option value="">Select service...</option>
</div> <option>Fence staining new wood</option>
<option>Fence staining existing / restoration</option>
<option>Deck staining new wood</option>
<option>Deck staining restoration</option>
<option>Pergola / structure staining</option>
<option>Log cabin / cedar siding</option>
<option>Pre-staining fence boards before install</option>
<option>Expert Stain &amp; Seal product only contractor purchase</option>
<option>Multiple services describe below</option>
</select>
<label className="ql text-white">EMAIL</label> <div className="qrow">
<input <div>
type="email" <label className="ql text-white">CITY / LOCATION</label>
name="email" <input
className="qi" type="text"
placeholder="you@email.com" name="location"
required className="qi"
value={formData.email} placeholder="Kitchener, Guelph..."
onChange={handleChange} value={formData.location}
/> onChange={handleChange}
/>
</div>
<div>
<label className="ql text-white">APPROXIMATE SIZE</label>
<input
type="text"
name="size"
className="qi"
placeholder="e.g. 150 ft fence / 400 sq ft deck"
value={formData.size}
onChange={handleChange}
/>
</div>
</div>
<label className="ql text-white">SERVICE NEEDED</label> {status === "error" && (
<select <p style={{ color: '#fee2e2', fontSize: '14px', marginBottom: '15px' }}>
name="projectType" Failed to send request. Please try again or email us directly.
className="qi" </p>
value={formData.projectType} )}
onChange={handleChange}
>
<option value="">Select service...</option>
<option>Fence staining new wood</option>
<option>Fence staining existing / restoration</option>
<option>Deck staining new wood</option>
<option>Deck staining restoration</option>
<option>Pergola / structure staining</option>
<option>Log cabin / cedar siding</option>
<option>Pre-staining fence boards before install</option>
<option>Expert Stain &amp; Seal product only contractor purchase</option>
<option>Multiple services describe below</option>
</select>
<div className="qrow"> <button type="submit" className="qbtn btn-white-orange" disabled={status === "submitting"}>
<div> {status === "submitting" ? "SENDING..." : "SEND QUOTE REQUEST →"}
<label className="ql text-white">CITY / LOCATION</label> </button>
<input </form>
type="text" )}
name="location"
className="qi"
placeholder="Kitchener, Guelph..."
onChange={handleChange}
/>
</div>
<div>
<label className="ql text-white">APPROXIMATE SIZE</label>
<input
type="text"
name="size"
className="qi"
placeholder="e.g. 150 ft fence / 400 sq ft deck"
onChange={handleChange}
/>
</div>
</div>
<button type="submit" className="qbtn btn-white-orange">SEND QUOTE REQUEST </button>
</form>
</div> </div>
</div> </div>
</section> </section>