import React, { useMemo, useState } from “react”;
import { motion } from “framer-motion”;
import { Plus, Trash2, RotateCcw, Ruler, Euro, Download, Home } from “lucide-react”;
import { Button } from “@/components/ui/button”;
import { Card, CardContent } from “@/components/ui/card”;
const MODULES = [
{ id: “base60”, name: “Onderkast 60”, width: 60, depth: 60, price: 240, type: “Onderkast” },
{ id: “base80”, name: “Onderkast 80”, width: 80, depth: 60, price: 310, type: “Onderkast” },
{ id: “sink80”, name: “Spoelkast 80”, width: 80, depth: 60, price: 390, type: “Spoelzone” },
{ id: “hob60”, name: “Kookplaatkast 60”, width: 60, depth: 60, price: 430, type: “Kookzone” },
{ id: “drawer90”, name: “Ladekast 90”, width: 90, depth: 60, price: 520, type: “Opbergen” },
{ id: “tall60”, name: “Hoge kast 60”, width: 60, depth: 60, price: 690, type: “Hoge kast” },
{ id: “fridge60”, name: “Koelkastkast 60”, width: 60, depth: 60, price: 850, type: “Apparatuur” },
{ id: “oven60”, name: “Ovenkast 60”, width: 60, depth: 60, price: 760, type: “Apparatuur” },
];
const LAYOUTS = [
{ id: “straight”, label: “Rechte keuken”, description: “Alle modules langs één wand.” },
{ id: “lshape”, label: “L-keuken”, description: “Modules verdeeld over twee wanden.” },
{ id: “island”, label: “Keuken met eiland”, description: “Wandopstelling plus los eiland.” },
];
function currency(value) {
return new Intl.NumberFormat(“nl-NL”, { style: “currency”, currency: “EUR”, maximumFractionDigits: 0 }).format(value);
}
function fitStatus(totalWidth, roomWidth) {
if (totalWidth <= roomWidth) return { label: "Past", tone: "bg-emerald-100 text-emerald-800" };
return { label: "Te breed", tone: "bg-red-100 text-red-800" };
}
export default function KitchenDesigner() {
const [roomWidth, setRoomWidth] = useState(360);
const [roomDepth, setRoomDepth] = useState(260);
const [layout, setLayout] = useState("straight");
const [selectedType, setSelectedType] = useState("Alles");
const [items, setItems] = useState([
{ uid: crypto.randomUUID(), ...MODULES[1], zone: "wand" },
{ uid: crypto.randomUUID(), ...MODULES[2], zone: "wand" },
{ uid: crypto.randomUUID(), ...MODULES[3], zone: "wand" },
]);
const filteredModules = useMemo(() => {
if (selectedType === “Alles”) return MODULES;
return MODULES.filter((m) => m.type === selectedType);
}, [selectedType]);
const totalWidth = items.filter((i) => i.zone === “wand”).reduce((sum, i) => sum + i.width, 0);
const islandWidth = items.filter((i) => i.zone === “eiland”).reduce((sum, i) => sum + i.width, 0);
const cabinetsPrice = items.reduce((sum, i) => sum + i.price, 0);
const worktopPrice = Math.ceil((totalWidth + islandWidth) / 100) * 180;
const installPrice = Math.max(850, Math.ceil(items.length * 115));
const totalPrice = cabinetsPrice + worktopPrice + installPrice;
const status = fitStatus(totalWidth, roomWidth);
const addModule = (module) => {
const zone = layout === “island” && [“drawer90”, “base80”, “base60”].includes(module.id) && islandWidth < 180 ? "eiland" : "wand";
setItems((prev) => […prev, { uid: crypto.randomUUID(), …module, zone }]);
};
const removeModule = (uid) => setItems((prev) => prev.filter((item) => item.uid !== uid));
const reset = () => {
setLayout(“straight”);
setRoomWidth(360);
setRoomDepth(260);
setItems([
{ uid: crypto.randomUUID(), …MODULES[1], zone: “wand” },
{ uid: crypto.randomUUID(), …MODULES[2], zone: “wand” },
{ uid: crypto.randomUUID(), …MODULES[3], zone: “wand” },
]);
};
const exportDesign = () => {
const data = {
ruimte: { breedte_cm: roomWidth, diepte_cm: roomDepth },
layout,
modules: items.map(({ uid, name, width, depth, price, zone }) => ({ uid, name, width, depth, price, zone })),
prijsindicatie: { kasten: cabinetsPrice, werkblad: worktopPrice, montage: installPrice, totaal: totalPrice },
};
const blob = new Blob([JSON.stringify(data, null, 2)], { type: “application/json” });
const url = URL.createObjectURL(blob);
const a = document.createElement(“a”);
a.href = url;
a.download = “keukenontwerp.json”;
a.click();
URL.revokeObjectURL(url);
};
const scale = 1.35;
const roomSvgWidth = Math.max(420, roomWidth * scale);
const roomSvgHeight = Math.max(260, roomDepth * scale);
return (
Online configurator
Keukenontwerp systeem
Stel een keuken samen, controleer of de indeling past en exporteer het ontwerp als JSON.
Live plattegrond
Schaal is indicatief. Grijze vlakken zijn keukenmodules.
{status.label}
Geselecteerde modules
))}
Prijsopbouw
Deze prijs is een indicatie. Koppel dit systeem aan je eigen productdatabase voor actuele voorraad, materialen en marges.
);
}
function Metric({ icon, label, value, badge }) {
return (
{badge && {badge.label}}
);
}
function KitchenBlock({ x, y, w, h, label }) {
return (
);
}
function PriceRow({ label, value, strong = false }) {
return (
{currency(value)}
);
}