Merge version_3 into main #5

Open
bender wants to merge 1 commits from version_3 into main

View File

@@ -1,6 +1,7 @@
"use client";
import { Clock, Mail, MapPin, Phone } from "lucide-react";
import { useState, useRef } from "react";
import { Clock, Mail, MapPin, Phone, Plus, Minus } from "lucide-react";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarStyleApple from "@/components/navbar/NavbarStyleApple/NavbarStyleApple";
import HeroBillboard from "@/components/sections/hero/HeroBillboard";
@@ -12,7 +13,64 @@ import AboutMetric from "@/components/sections/about/AboutMetric";
import ContactSplit from "@/components/sections/contact/ContactSplit";
import FooterLogoEmphasis from "@/components/sections/footer/FooterLogoEmphasis";
interface PricingCalculatorState {
serviceType: string;
squareFootage: string;
priceRange: { min: number; max: number } | null;
}
export default function LandingPage() {
const [calculator, setCalculator] = useState<PricingCalculatorState>({
serviceType: "interior-painting", squareFootage: "", priceRange: null,
});
const [formData, setFormData] = useState({
name: "", phone: "", email: "", serviceType: "interior-painting", squareFootage: "", address: "", timeline: "asap", notes: ""});
const calculatorRef = useRef<HTMLDivElement>(null);
const formRef = useRef<HTMLDivElement>(null);
const servicePrices: Record<string, { min: number; max: number }> = {
"interior-painting": { min: 3.5, max: 5.5 },
"exterior-painting": { min: 4.5, max: 7.0 },
"flooring-installation": { min: 6.0, max: 12.0 },
"small-renovations": { min: 5.0, max: 15.0 },
};
const calculatePrice = () => {
const sqft = parseFloat(calculator.squareFootage);
if (!isNaN(sqft) && sqft > 0) {
const prices = servicePrices[calculator.serviceType];
if (prices) {
const minPrice = sqft * prices.min;
const maxPrice = sqft * prices.max;
setCalculator(prev => ({
...prev,
priceRange: { min: Math.round(minPrice), max: Math.round(maxPrice) },
}));
}
}
};
const scrollToSection = (ref: React.RefObject<HTMLDivElement>) => {
ref.current?.scrollIntoView({ behavior: "smooth" });
};
const handleServiceCardCTA = (section: "calculator" | "form") => {
if (section === "calculator") {
scrollToSection(calculatorRef);
} else {
scrollToSection(formRef);
}
};
const serviceCardButtons = [
{
text: "Get Instant Estimate", onClick: () => handleServiceCardCTA("calculator"),
},
{ text: "Request a Quote", onClick: () => handleServiceCardCTA("form") },
];
return (
<ThemeProvider
defaultButtonVariant="elastic-effect"
@@ -133,7 +191,278 @@ export default function LandingPage() {
/>
</div>
<div id="cta-section" data-section="cta-section">
{/* Pricing Calculator Section */}
<div
id="calculator"
ref={calculatorRef}
data-section="calculator"
className="py-20 px-4 md:px-8 bg-background/50"
>
<div className="max-w-2xl mx-auto">
<h2 className="text-3xl md:text-4xl font-bold text-foreground mb-2 text-center">
Instant Price Calculator
</h2>
<p className="text-foreground/70 text-center mb-12">
Get an estimated price range for your project
</p>
<div className="bg-card rounded-lg p-8 border border-accent/30">
<div className="space-y-6">
{/* Service Type Dropdown */}
<div>
<label className="block text-sm font-semibold text-foreground mb-3">
Service Type
</label>
<select
value={calculator.serviceType}
onChange={(e) => {
setCalculator((prev) => ({
...prev,
serviceType: e.target.value,
priceRange: null,
}));
}}
className="w-full bg-background border border-accent/50 rounded-md px-4 py-3 text-foreground focus:outline-none focus:border-primary-cta transition-colors"
>
<option value="interior-painting">Interior Painting</option>
<option value="exterior-painting">Exterior Painting</option>
<option value="flooring-installation">Flooring Installation</option>
<option value="small-renovations">Small Renovations</option>
</select>
</div>
{/* Square Footage Input */}
<div>
<label className="block text-sm font-semibold text-foreground mb-3">
Square Footage
</label>
<div className="flex gap-3">
<input
type="number"
value={calculator.squareFootage}
onChange={(e) => {
setCalculator((prev) => ({
...prev,
squareFootage: e.target.value,
priceRange: null,
}));
}}
placeholder="Enter square footage"
className="flex-1 bg-background border border-accent/50 rounded-md px-4 py-3 text-foreground placeholder-foreground/40 focus:outline-none focus:border-primary-cta transition-colors"
/>
<button
onClick={calculatePrice}
className="bg-primary-cta text-primary-cta-text px-6 py-3 rounded-md font-semibold hover:opacity-90 transition-opacity"
>
Calculate
</button>
</div>
</div>
{/* Price Display */}
{calculator.priceRange && (
<div className="bg-background/50 rounded-md p-6 border border-primary-cta/30">
<p className="text-foreground/70 text-sm mb-2">Estimated Price Range</p>
<p className="text-2xl md:text-3xl font-bold text-primary-cta">
${calculator.priceRange.min.toLocaleString()} - $
{calculator.priceRange.max.toLocaleString()}
</p>
<p className="text-foreground/60 text-sm mt-3">
*This is an estimate. Final price may vary based on project complexity and site conditions.
</p>
</div>
)}
</div>
</div>
</div>
</div>
{/* Quote Request Form Section */}
<div
id="form"
ref={formRef}
data-section="form"
className="py-20 px-4 md:px-8 bg-background"
>
<div className="max-w-2xl mx-auto">
<h2 className="text-3xl md:text-4xl font-bold text-foreground mb-2 text-center">
Request Your Free Quote
</h2>
<p className="text-foreground/70 text-center mb-12">
Fill out the form below and our team will contact you within 24 hours
</p>
<form className="bg-card rounded-lg p-8 border border-accent/30 space-y-6">
{/* Name */}
<div>
<label className="block text-sm font-semibold text-foreground mb-2">
Full Name *
</label>
<input
type="text"
value={formData.name}
onChange={(e) =>
setFormData({ ...formData, name: e.target.value })
}
placeholder="Your full name"
required
className="w-full bg-background border border-accent/50 rounded-md px-4 py-3 text-foreground placeholder-foreground/40 focus:outline-none focus:border-primary-cta transition-colors"
/>
</div>
{/* Phone */}
<div>
<label className="block text-sm font-semibold text-foreground mb-2">
Phone Number *
</label>
<input
type="tel"
value={formData.phone}
onChange={(e) =>
setFormData({ ...formData, phone: e.target.value })
}
placeholder="(555) 123-4567"
required
className="w-full bg-background border border-accent/50 rounded-md px-4 py-3 text-foreground placeholder-foreground/40 focus:outline-none focus:border-primary-cta transition-colors"
/>
</div>
{/* Email */}
<div>
<label className="block text-sm font-semibold text-foreground mb-2">
Email Address *
</label>
<input
type="email"
value={formData.email}
onChange={(e) =>
setFormData({ ...formData, email: e.target.value })
}
placeholder="your@email.com"
required
className="w-full bg-background border border-accent/50 rounded-md px-4 py-3 text-foreground placeholder-foreground/40 focus:outline-none focus:border-primary-cta transition-colors"
/>
</div>
{/* Service Type */}
<div>
<label className="block text-sm font-semibold text-foreground mb-2">
Service Type *
</label>
<select
value={formData.serviceType}
onChange={(e) =>
setFormData({ ...formData, serviceType: e.target.value })
}
required
className="w-full bg-background border border-accent/50 rounded-md px-4 py-3 text-foreground focus:outline-none focus:border-primary-cta transition-colors"
>
<option value="interior-painting">Interior Painting</option>
<option value="exterior-painting">Exterior Painting</option>
<option value="flooring-installation">Flooring Installation</option>
<option value="small-renovations">Small Renovations</option>
</select>
</div>
{/* Square Footage */}
<div>
<label className="block text-sm font-semibold text-foreground mb-2">
Square Footage *
</label>
<input
type="number"
value={formData.squareFootage}
onChange={(e) =>
setFormData({ ...formData, squareFootage: e.target.value })
}
placeholder="Enter square footage"
required
className="w-full bg-background border border-accent/50 rounded-md px-4 py-3 text-foreground placeholder-foreground/40 focus:outline-none focus:border-primary-cta transition-colors"
/>
</div>
{/* Project Address */}
<div>
<label className="block text-sm font-semibold text-foreground mb-2">
Project Address *
</label>
<input
type="text"
value={formData.address}
onChange={(e) =>
setFormData({ ...formData, address: e.target.value })
}
placeholder="123 Main St, City, Province"
required
className="w-full bg-background border border-accent/50 rounded-md px-4 py-3 text-foreground placeholder-foreground/40 focus:outline-none focus:border-primary-cta transition-colors"
/>
</div>
{/* Preferred Timeline */}
<div>
<label className="block text-sm font-semibold text-foreground mb-2">
Preferred Timeline *
</label>
<select
value={formData.timeline}
onChange={(e) =>
setFormData({ ...formData, timeline: e.target.value })
}
required
className="w-full bg-background border border-accent/50 rounded-md px-4 py-3 text-foreground focus:outline-none focus:border-primary-cta transition-colors"
>
<option value="asap">ASAP</option>
<option value="1-2-weeks">1-2 weeks</option>
<option value="1-month">1 month</option>
<option value="flexible">Flexible</option>
</select>
</div>
{/* Notes */}
<div>
<label className="block text-sm font-semibold text-foreground mb-2">
Additional Notes (Optional)
</label>
<textarea
value={formData.notes}
onChange={(e) =>
setFormData({ ...formData, notes: e.target.value })
}
placeholder="Tell us more about your project..."
rows={4}
className="w-full bg-background border border-accent/50 rounded-md px-4 py-3 text-foreground placeholder-foreground/40 focus:outline-none focus:border-primary-cta transition-colors resize-none"
/>
</div>
{/* Submit Button */}
<button
type="submit"
className="w-full bg-primary-cta text-primary-cta-text font-semibold py-4 rounded-md hover:opacity-90 transition-opacity"
>
Request Quote
</button>
</form>
</div>
</div>
{/* Sticky Mobile CTA */}
<div className="fixed bottom-0 left-0 right-0 md:hidden bg-card border-t border-accent/30 p-4 flex gap-3 z-40">
<button
onClick={() => scrollToSection(calculatorRef)}
className="flex-1 bg-primary-cta text-primary-cta-text font-semibold py-3 rounded-md hover:opacity-90 transition-opacity"
>
Estimate
</button>
<button
onClick={() => window.location.href = "tel:(555)123-4567"}
className="flex-1 bg-secondary-cta text-secondary-cta-text font-semibold py-3 rounded-md border border-primary-cta/30 hover:opacity-90 transition-opacity flex items-center justify-center gap-2"
>
<Phone size={18} />
Call
</button>
</div>
<div id="cta-section" data-section="cta-section" className="mb-20 md:mb-0">
<AboutMetric
title="Ready to Transform Your Space?"
metrics={[