Expand the calculator with a multi-step wizard flow, admin dashboard with quote tracking, login/auth system, distance API integration, and history page. Add new UI components (dialog, progress, select, slider, switch), update pricing logic, and improve the overall design with new assets. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
335 lines
12 KiB
TypeScript
335 lines
12 KiB
TypeScript
"use client"
|
|
|
|
import { useState } from "react"
|
|
import Image from "next/image"
|
|
import { StepWizard } from "@/components/calculator/step-wizard"
|
|
import { Button } from "@/components/ui/button"
|
|
import { formatEstimate, type CalculationDetails } from "@/lib/calculations"
|
|
import {
|
|
Phone,
|
|
Mail,
|
|
MapPin,
|
|
CheckCircle2,
|
|
ArrowRight,
|
|
RotateCcw,
|
|
Loader2,
|
|
} from "lucide-react"
|
|
|
|
export default function Home() {
|
|
const [result, setResult] = useState<CalculationDetails | null>(null)
|
|
const [customerData, setCustomerData] = useState<any>(null)
|
|
const [showResult, setShowResult] = useState(false)
|
|
|
|
const handleComplete = (calculationResult: CalculationDetails, formData: any) => {
|
|
setResult(calculationResult)
|
|
setCustomerData(formData)
|
|
setShowResult(true)
|
|
}
|
|
|
|
const handleReset = () => {
|
|
setResult(null)
|
|
setCustomerData(null)
|
|
setShowResult(false)
|
|
}
|
|
|
|
const [isRequesting, setIsRequesting] = useState(false)
|
|
|
|
const handleRequestQuote = async () => {
|
|
if (!result || !customerData) return
|
|
|
|
setIsRequesting(true)
|
|
try {
|
|
const response = await fetch("/api/quote-request", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
customerInfo: {
|
|
name: customerData.name,
|
|
email: customerData.email,
|
|
phone: customerData.phone,
|
|
postalCode: customerData.postalCode,
|
|
address: customerData.address,
|
|
remarks: customerData.remarks,
|
|
},
|
|
calculationDetails: result,
|
|
}),
|
|
})
|
|
|
|
const data = await response.json()
|
|
|
|
if (response.ok) {
|
|
alert(data.message)
|
|
} else {
|
|
alert(data.error || "Der opstod en fejl. Prøv igen senere.")
|
|
}
|
|
} catch (error) {
|
|
alert("Der opstod en fejl. Prøv igen senere.")
|
|
} finally {
|
|
setIsRequesting(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<main className="min-h-screen bg-background">
|
|
{/* Hero Section */}
|
|
<section className="relative flex min-h-[70vh] items-center justify-center overflow-hidden">
|
|
{/* Background Image */}
|
|
<div className="absolute inset-0 z-0">
|
|
<Image
|
|
src="/gulv.jpeg"
|
|
alt="Smukt gulv i moderne hjem"
|
|
fill
|
|
className="object-cover"
|
|
priority
|
|
/>
|
|
<div className="absolute inset-0 bg-gradient-to-b from-black/60 via-black/40 to-black/70" />
|
|
</div>
|
|
|
|
{/* Hero Content */}
|
|
<div className="container relative z-10 mx-auto px-4 text-center text-white">
|
|
<div className="mb-6">
|
|
<Image
|
|
src="/foam-king-logo.png"
|
|
alt="Foam King"
|
|
width={180}
|
|
height={72}
|
|
className="mx-auto h-16 w-auto brightness-0 invert"
|
|
priority
|
|
/>
|
|
</div>
|
|
<h1 className="mb-4 text-4xl font-bold tracking-tight sm:text-5xl md:text-6xl">
|
|
Gulvarbejde i<br />
|
|
<span className="text-secondary">verdensklasse</span>
|
|
</h1>
|
|
<p className="mx-auto mb-8 max-w-2xl text-lg text-white/90 sm:text-xl">
|
|
Professionel udførelse af betongulve, gulvvarme og isolering. Vi leverer kvalitet der
|
|
holder i mange år fremover.
|
|
</p>
|
|
<div className="mb-8 flex flex-wrap justify-center gap-4">
|
|
<div className="flex items-center gap-2 rounded-full bg-white/10 px-4 py-2 backdrop-blur-sm">
|
|
<CheckCircle2 className="h-5 w-5 text-secondary" />
|
|
<span>Stor erfaring</span>
|
|
</div>
|
|
<div className="flex items-center gap-2 rounded-full bg-white/10 px-4 py-2 backdrop-blur-sm">
|
|
<CheckCircle2 className="h-5 w-5 text-secondary" />
|
|
<span>Byg Garanti</span>
|
|
</div>
|
|
<div className="flex items-center gap-2 rounded-full bg-white/10 px-4 py-2 backdrop-blur-sm">
|
|
<CheckCircle2 className="h-5 w-5 text-secondary" />
|
|
<span>Gratis tilbud</span>
|
|
</div>
|
|
</div>
|
|
<Button
|
|
size="lg"
|
|
className="h-14 bg-secondary px-8 text-lg text-secondary-foreground hover:bg-secondary/90"
|
|
onClick={() =>
|
|
document.getElementById("calculator")?.scrollIntoView({ behavior: "smooth" })
|
|
}
|
|
>
|
|
Få dit prisoverslag
|
|
<ArrowRight className="ml-2 h-5 w-5" />
|
|
</Button>
|
|
</div>
|
|
|
|
{/* Scroll Indicator */}
|
|
<div className="absolute bottom-8 left-1/2 z-10 -translate-x-1/2 animate-bounce">
|
|
<div className="flex h-12 w-8 items-start justify-center rounded-full border-2 border-white/50 pt-2">
|
|
<div className="h-3 w-1 rounded-full bg-white/70" />
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Calculator Section */}
|
|
<section
|
|
id="calculator"
|
|
className="bg-gradient-to-b from-muted/50 to-background py-16 sm:py-24"
|
|
>
|
|
<div className="container mx-auto px-4">
|
|
<div className="mb-12 text-center">
|
|
<p className="mb-2 font-semibold text-secondary">Prisberegner</p>
|
|
<h2 className="mb-4 text-3xl font-bold sm:text-4xl">Få dit personlige tilbud</h2>
|
|
<p className="mx-auto max-w-xl text-muted-foreground">
|
|
Besvar nogle få spørgsmål, så kan give dig den mest nøjagtige prisberegning.
|
|
<br />
|
|
Det tager kun 2 minutter.
|
|
</p>
|
|
</div>
|
|
|
|
{!showResult ? (
|
|
<StepWizard onComplete={handleComplete} />
|
|
) : (
|
|
/* Result Card */
|
|
<div className="mx-auto max-w-lg">
|
|
<div className="rounded-2xl bg-white p-8 text-center shadow-lg">
|
|
<div className="mx-auto mb-6 flex h-16 w-16 items-center justify-center rounded-full bg-green-100">
|
|
<CheckCircle2 className="h-8 w-8 text-green-600" />
|
|
</div>
|
|
<h3 className="mb-2 text-2xl font-bold">Dit prisoverslag</h3>
|
|
<p className="mb-6 text-muted-foreground">
|
|
Baseret på {result?.area} m² gulv i {customerData?.postalCode}
|
|
</p>
|
|
|
|
<div className="mb-6 rounded-xl bg-gradient-to-br from-primary/10 to-secondary/10 p-6">
|
|
<p className="mb-2 text-3xl font-bold text-primary sm:text-5xl">
|
|
{result && formatEstimate(result.totalInclVat)}
|
|
</p>
|
|
<p className="text-muted-foreground">inkl. moms</p>
|
|
</div>
|
|
|
|
<div className="mb-6 rounded-lg bg-muted/30 p-4 text-left text-sm">
|
|
<p className="mb-2 font-medium">Inkluderet i prisen:</p>
|
|
<ul className="space-y-1 text-muted-foreground">
|
|
{result?.includeInsulation && (
|
|
<li className="flex items-center gap-2">
|
|
<CheckCircle2 className="h-4 w-4 text-green-600" />
|
|
Isolering ({result.insulationThickness} cm)
|
|
</li>
|
|
)}
|
|
{result?.includeFloorHeating && (
|
|
<li className="flex items-center gap-2">
|
|
<CheckCircle2 className="h-4 w-4 text-green-600" />
|
|
Gulvvarme syntetisk net + Ø16 PEX (excl. tilslutning)
|
|
</li>
|
|
)}
|
|
{result?.includeCompound && (
|
|
<li className="flex items-center gap-2">
|
|
<CheckCircle2 className="h-4 w-4 text-green-600" />
|
|
Flydespartel (støbning)
|
|
</li>
|
|
)}
|
|
<li className="flex items-center gap-2">
|
|
<CheckCircle2 className="h-4 w-4 text-green-600" />
|
|
Transport til {customerData?.postalCode}
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<p className="mb-6 text-xs text-muted-foreground">
|
|
*Prisen er vejledende og kan variere med ±10.000 kr afhængigt af konkrete forhold
|
|
</p>
|
|
|
|
<div className="flex flex-col gap-3">
|
|
<Button
|
|
size="lg"
|
|
className="h-12 w-full bg-secondary text-secondary-foreground hover:bg-secondary/90"
|
|
onClick={handleRequestQuote}
|
|
disabled={isRequesting}
|
|
>
|
|
{isRequesting ? (
|
|
<>
|
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
Sender...
|
|
</>
|
|
) : (
|
|
<>
|
|
<Mail className="mr-2 h-4 w-4" />
|
|
Anmod om bindende tilbud
|
|
</>
|
|
)}
|
|
</Button>
|
|
|
|
<Button
|
|
variant="outline"
|
|
size="lg"
|
|
className="h-12 w-full"
|
|
onClick={handleReset}
|
|
>
|
|
<RotateCcw className="mr-2 h-4 w-4" />
|
|
Ny beregning
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</section>
|
|
|
|
{/* Features Section */}
|
|
<section className="bg-muted/30 py-16 sm:py-24">
|
|
<div className="container mx-auto px-4">
|
|
<div className="grid gap-6 md:grid-cols-3">
|
|
<div className="flex h-32 items-center justify-center rounded-2xl bg-white p-6 shadow-md transition-shadow hover:shadow-lg">
|
|
<Image
|
|
src="/dansk_kvalitet.png"
|
|
alt="Dansk Kvalitet"
|
|
width={75}
|
|
height={100}
|
|
className="h-20 w-auto object-contain"
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex h-32 items-center justify-center rounded-2xl bg-white p-6 shadow-md transition-shadow hover:shadow-lg">
|
|
<Image
|
|
src="/byg_trans.png"
|
|
alt="Byg Garanti"
|
|
width={360}
|
|
height={97}
|
|
className="h-20 w-auto object-contain"
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex h-32 items-center justify-center rounded-2xl bg-white p-6 shadow-md transition-shadow hover:shadow-lg">
|
|
<Image
|
|
src="/tilfredshed_service.png"
|
|
alt="Tilfredshed & Service"
|
|
width={75}
|
|
height={100}
|
|
className="h-20 w-auto object-contain"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Coverage Section */}
|
|
<section className="bg-white py-16">
|
|
<div className="container mx-auto px-4 text-center">
|
|
<h2 className="mb-4 text-2xl font-bold">Vi dækker hele Østdanmark</h2>
|
|
<p className="mb-6 text-muted-foreground">
|
|
Sjælland · København · Nordsjælland · Lolland-Falster · Fyn
|
|
</p>
|
|
<div className="flex justify-center gap-4">
|
|
<a href="tel:35901066" className="flex items-center gap-2 text-primary hover:underline">
|
|
<Phone className="h-4 w-4" />
|
|
35 90 10 66
|
|
</a>
|
|
<a
|
|
href="mailto:info@foamking.dk"
|
|
className="flex items-center gap-2 text-primary hover:underline"
|
|
>
|
|
<Mail className="h-4 w-4" />
|
|
info@foamking.dk
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Footer */}
|
|
<footer className="bg-foreground py-8 text-background">
|
|
<div className="container mx-auto px-4">
|
|
<div className="flex flex-col items-center justify-between gap-4 md:flex-row">
|
|
<div className="flex items-center gap-4">
|
|
<Image
|
|
src="/foam-king-logo.png"
|
|
alt="Foam King"
|
|
width={120}
|
|
height={48}
|
|
className="h-10 w-auto brightness-0 invert"
|
|
/>
|
|
<div className="text-sm text-background/70">
|
|
<p>Foam King ApS · CVR: 44 48 54 51</p>
|
|
<p className="flex items-center gap-1">
|
|
<MapPin className="h-3 w-3" />
|
|
Søgårdsvej 7, 4550 Asnæs
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<p className="text-sm text-background/50">
|
|
© {new Date().getFullYear()} Foam King. Alle rettigheder forbeholdes.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
</main>
|
|
)
|
|
}
|