/* global React, TREATMENTS, CATEGORIES, CLINIC, IconClose, IconArrow, IconArrowLeft, IconCheck, IconSparkle, IconAligner, IconImplant, IconLeaf, IconTooth, IconCalendar */
const TX_GROUPS = [
{ id: "Cosmetic", icon: IconSparkle, label: "Cosmetic", desc: "Veneers, whitening, smile makeover" },
{ id: "Orthodontics", icon: IconAligner, label: "Orthodontics", desc: "Invisalign, braces, retainers" },
{ id: "Implants", icon: IconImplant, label: "Implants & Restoration", desc: "Implants, crowns, dentures" },
{ id: "General", icon: IconLeaf, label: "General & Preventive", desc: "Check-up, cleaning, root canal" }
];
// generate a synthetic next-7-days set, excluding Friday (likely closed)
function nextDays(n = 7) {
const out = [];
const today = new Date(2026, 4, 22); // anchored to keep prototype deterministic
let cursor = new Date(today);
while (out.length < n) {
cursor.setDate(cursor.getDate() + 1);
if (cursor.getDay() === 5) continue; // skip Friday
out.push(new Date(cursor));
}
return out;
}
const DAYS = nextDays(5);
const WEEKDAY = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
const MONTH = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
const TIME_SLOTS = ["10:00","10:30","11:00","11:30","12:00","12:30","14:30","15:00","15:30","16:00","16:30","17:00","17:30","18:00"];
// pretend some are taken
const TAKEN = new Set(["11:00","12:30","15:30","18:00"]);
function BookingModal({ open, onClose, prefillTreatment }) {
const [step, setStep] = React.useState(0);
const [form, setForm] = React.useState({
category: "Cosmetic", treatment: null, day: 1, time: "15:00",
name: "", phone: "", email: "", message: "", consent: false
});
// Sync the category when a treatment is prefilled
React.useEffect(() => {
if (open && prefillTreatment) {
const tx = TREATMENTS.find(t => t.id === prefillTreatment);
if (tx) setForm(f => ({ ...f, category: tx.cat, treatment: tx.id }));
}
}, [open, prefillTreatment]);
React.useEffect(() => {
if (!open) {
// tiny delay so the close animation finishes before resetting
const t = setTimeout(() => { setStep(0); }, 240);
return () => clearTimeout(t);
}
document.body.style.overflow = "hidden";
return () => { document.body.style.overflow = ""; };
}, [open]);
const set = (patch) => setForm(f => ({ ...f, ...patch }));
const steps = [
{ id: 0, t: "What brings you in?", sub: "Pick a category — we'll match it to the right dentist." },
{ id: 1, t: "Choose a date & time", sub: "Provisional slots; the clinic will confirm by phone." },
{ id: 2, t: "Your details", sub: "We only need a phone number to confirm — the rest is optional." },
{ id: 3, t: "Confirm your booking", sub: "Last look. We’ll text and call to confirm." }
];
const filteredTx = TREATMENTS.filter(t => t.cat === form.category);
const canAdvance = (() => {
if (step === 0) return !!form.category;
if (step === 1) return form.day !== null && form.time;
if (step === 2) return form.name.trim().length > 1 && /^[+\d\s()-]{7,}$/.test(form.phone) && form.consent;
return true;
})();
const submit = () => setStep(4);
return (
e.stopPropagation()} role="dialog" aria-modal="true">
Book a Consultation
From AED 200 — confirmed in under a minute.
{steps.map((s, i) => (
{i < step ? : i + 1}
{s.t}
))}
One of the best dental clinics in Dubai. Especially Dr Ammar — makes you feel as if you know him for a long time.
— Verified patient, Doctify
Step {Math.min(step, 3) + 1} of 4
{step <= 3 && (
{steps[step].t}
{steps[step].sub}
)}
{/* STEP 0 — category & treatment */}
{step === 0 && (
{TX_GROUPS.map(g => {
const Icon = g.icon;
return (
set({ category: g.id, treatment: null })}
>
{g.label}
{g.desc}
);
})}
Specific treatment · optional
set({ treatment: e.target.value || null })}
>
Not sure yet — recommend for me
{filteredTx.map(t => (
{t.title}
))}
)}
{/* STEP 1 — calendar */}
{step === 1 && (
{DAYS.map((d, i) => (
set({ day: i })}
>
{WEEKDAY[d.getDay()]}
{d.getDate()}
{MONTH[d.getMonth()]}
))}
Available times — {WEEKDAY[DAYS[form.day].getDay()]} {DAYS[form.day].getDate()} {MONTH[DAYS[form.day].getMonth()]}
{TIME_SLOTS.map(t => {
const taken = TAKEN.has(t);
return (
!taken && set({ time: t })}
>{t}
);
})}
Heads up: these are placeholder slots until the clinic confirms its working calendar — the team will phone you within 1 working day to lock the time.
)}
{/* STEP 2 — details */}
{step === 2 && (
)}
{/* STEP 3 — confirm */}
{step === 3 && (
Treatment
{form.category}{form.treatment ? ` · ${TREATMENTS.find(t => t.id === form.treatment)?.title}` : " · open consultation"}
When
{WEEKDAY[DAYS[form.day].getDay()]} {DAYS[form.day].getDate()} {MONTH[DAYS[form.day].getMonth()]} · {form.time}
Patient
{form.name || "—"} · {form.phone || "—"}
{form.email &&
}
Clinic
Empire Heights, Tower B, Office 901 · Business Bay
Consultation
From AED 200 · pay at the clinic
)}
{/* STEP 4 — booked */}
{step === 4 && (
You’re on the list.
A member of the Empire team will call {form.phone} within one working day to confirm your {WEEKDAY[DAYS[form.day].getDay()]} {DAYS[form.day].getDate()} {MONTH[DAYS[form.day].getMonth()]} · {form.time} consultation.
Reference
EMP-{Date.now().toString().slice(-6)}
Map
Tower B, 9th floor · Empire Heights, Marasi Dr
Close
)}
{step <= 3 && (
{step > 0 ? (
setStep(s => s - 1)}>
Back
) : (
No payment now · pay at the clinic
)}
{step < 3 ? (
setStep(s => s + 1)} style={{ opacity: canAdvance ? 1 : .45 }}>
Continue
) : (
Confirm booking
)}
)}
);
}
window.BookingModal = BookingModal;