/* ============================================================ QuoteModal — multi-field form, validation, mock submit ============================================================ */ const QuoteModal = ({ open, onClose }) => { const empty = { name: "", phone: "", email: "", service: "", region: "", date: "", notes: "" }; const [form, setForm] = useState(empty); const [errors, setErrors] = useState({}); const [stage, setStage] = useState("form"); // form | sending | done useEffect(() => { if (open) { setStage("form"); setErrors({}); setForm(empty); } document.body.style.overflow = open ? "hidden" : ""; return () => { document.body.style.overflow = ""; }; }, [open]); useEffect(() => { const onKey = (e) => { if (e.key === "Escape") onClose(); }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [onClose]); const set = (k, v) => { setForm((f) => ({ ...f, [k]: v })); setErrors((e) => ({ ...e, [k]: undefined })); }; const validate = () => { const e = {}; if (!form.name.trim()) e.name = "Please enter your name"; if (!/^[+0-9 ()-]{7,}$/.test(form.phone.trim())) e.phone = "Enter a valid phone number"; if (form.email && !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(form.email.trim())) e.email = "Enter a valid email"; if (!form.service) e.service = "Select a service"; setErrors(e); return Object.keys(e).length === 0; }; const submit = (ev) => { ev.preventDefault(); if (!validate()) return; setStage("sending"); fetch("submit.php", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ ...form, form_source: "quote_modal" }), }) .then((r) => r.json()) .then((res) => { if (res.ok) setStage("done"); else { setStage("form"); setErrors({ name: res.message || "Submission failed. Please try again." }); } }) .catch(() => { setStage("form"); setErrors({ name: "Network error. Please call us at +65 935 7444 7." }); }); }; const services = ["Residential", "Commercial", "F&B", "Deep Clean", "Not sure yet"]; const regions = ["Central", "East", "West", "North", "North-East"]; return (
Thank you, {form.name.split(" ")[0] || "there"}. Our team will get back to you with a free, no-obligation quote within one business day.
Tell us a little about your space and we'll get back within one business day.