foamking/app/page.tsx
mikl0s 7d2bbae1c6 Initial implementation of Foam King Gulve price calculator
Features:
- Complete Next.js 16 app with TypeScript and Tailwind CSS
- Customer-facing price calculator form with validation
- Admin mode showing detailed price breakdowns
- Accurate price calculations matching business requirements
- Responsive design with custom shadcn/ui theme
- API endpoint for quote requests
- Danish postal code distance calculations
- Complete test coverage against documentation examples

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-10 14:27:28 +00:00

149 lines
No EOL
4.9 KiB
TypeScript

"use client"
import { useState } from "react"
import Image from "next/image"
import { CalculatorForm } from "@/components/calculator/calculator-form"
import { CalculationDetailsView } from "@/components/calculator/calculation-details"
import { Button } from "@/components/ui/button"
import type { CalculationDetails } from "@/lib/calculations"
import { formatEstimate } from "@/lib/calculations"
import { Send, Eye, EyeOff } from "lucide-react"
export default function Home() {
const [calculationResult, setCalculationResult] = useState<CalculationDetails | null>(null)
const [showAdminMode, setShowAdminMode] = useState(false)
const [isRequestingQuote, setIsRequestingQuote] = useState(false)
const [customerInfo, setCustomerInfo] = useState<any>(null)
const handleCalculation = (result: CalculationDetails, formData?: any) => {
setCalculationResult(result)
if (formData) {
setCustomerInfo(formData)
}
}
const handleQuoteRequest = async () => {
if (!calculationResult || !customerInfo) return
setIsRequestingQuote(true)
try {
const response = await fetch("/api/quote-request", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
customerInfo,
calculationDetails: calculationResult,
}),
})
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 {
setIsRequestingQuote(false)
}
}
return (
<main className="min-h-screen bg-gradient-to-b from-background to-muted/20">
<div className="container mx-auto px-4 py-8">
{/* Header */}
<div className="mb-8 text-center">
<div className="mb-4 flex justify-center">
<Image
src="/foam-king-logo.png"
alt="Foam King Gulve"
width={200}
height={80}
priority
className="h-20 w-auto"
/>
</div>
<h1 className="text-3xl font-bold">Foam King Gulve</h1>
<p className="mt-2 text-lg text-muted-foreground">
Professionelle gulvløsninger med isolering, gulvvarme og støbning
</p>
</div>
{/* Admin Mode Toggle */}
<div className="mb-4 flex justify-center">
<Button
variant="ghost"
size="sm"
onClick={() => setShowAdminMode(!showAdminMode)}
className="gap-2"
>
{showAdminMode ? (
<>
<EyeOff className="h-4 w-4" />
Skjul detaljer
</>
) : (
<>
<Eye className="h-4 w-4" />
Vis detaljer
</>
)}
</Button>
</div>
{/* Calculator */}
<div className="mx-auto max-w-6xl">
<div className="grid gap-8 lg:grid-cols-2">
<div className="flex justify-center">
<CalculatorForm
onCalculation={handleCalculation}
showDetails={showAdminMode}
/>
</div>
{/* Results */}
{calculationResult && (
<div className="space-y-6">
{!showAdminMode ? (
<div className="rounded-xl bg-card p-8 text-center shadow">
<h2 className="mb-4 text-xl font-semibold">Dit prisoverslag</h2>
<p className="text-4xl font-bold text-primary">
{formatEstimate(calculationResult.totalInclVat)}
</p>
<p className="mt-2 text-sm text-muted-foreground">inkl. moms</p>
<p className="mt-4 text-sm text-muted-foreground">
*Prisen er vejledende og kan variere med ±10.000 kr afhængigt af konkrete forhold
</p>
<Button
onClick={handleQuoteRequest}
size="lg"
className="mt-6 gap-2"
disabled={isRequestingQuote}
>
<Send className="h-4 w-4" />
Anmod om bindende tilbud
</Button>
</div>
) : (
<CalculationDetailsView details={calculationResult} />
)}
</div>
)}
</div>
</div>
{/* Footer */}
<footer className="mt-16 border-t pt-8 text-center text-sm text-muted-foreground">
<p>Foam King Gulve · Asnæs · CVR: 12345678</p>
<p className="mt-1">
Vi dækker Sjælland, Lolland-Falster og Fyn
</p>
</footer>
</div>
</main>
)
}