/* Fluffy Friends — multi-step booking modal (pre-fills a WhatsApp message) */ const { Button, Input, Select, Checkbox, Badge } = window.FluffyFriendsDesignSystem_a09c32; const PET_OPTS = [ { key: 'dog', label: 'Dog', icon: 'dog' }, { key: 'cat', label: 'Cat', icon: 'cat' }, { key: 'bird', label: 'Bird', icon: 'bird' }, { key: 'rabbit', label: 'Rabbit', icon: 'rabbit' }, ]; /* base price by pet + groom type. Dogs are priced by size (+AED 50 per tier). */ const BASE = { dog: { small: { 'Basic groom': 200, 'Full groom': 250, 'Nail trimming': 50, 'Haircut only': 70 }, medium: { 'Basic groom': 250, 'Full groom': 300, 'Nail trimming': 50, 'Haircut only': 70 }, large: { 'Basic groom': 300, 'Full groom': 350, 'Nail trimming': 50, 'Haircut only': 70 }, }, cat: { kitten: { 'Basic groom': 180, 'Full groom': 200, 'Nail trimming': 50, 'Haircut only': 70 }, adult: { 'Basic groom': 200, 'Full groom': 250, 'Nail trimming': 50, 'Haircut only': 70 }, }, bird: { 'Small bird': 120, 'Large bird': 170 }, rabbit: { 'Full grooming': 150 }, }; const CAT_AGES = [ { key: 'kitten', label: 'Kitten · up to 8 months' }, { key: 'adult', label: 'Adult cat' }, ]; const SERVICE_OPTS = { dog: ['Basic groom', 'Full groom', 'Nail trimming', 'Haircut only'], cat: ['Basic groom', 'Full groom', 'Nail trimming', 'Haircut only'], bird: ['Small bird', 'Large bird'], rabbit: ['Full grooming'], }; // Quick add-on services have their own short durations (override the size/pet duration). const SERVICE_DURATIONS = { 'Nail trimming': 30, 'Haircut only': 60 }; const EXTRAS = [ { key: 'teeth', label: 'Teeth brushing / gland cleaning', price: 50 }, { key: 'shampoo', label: 'Anti-allergy / medical shampoo', price: 30 }, { key: 'ticks', label: 'Tick & fleas protection', price: 100 }, ]; function BookingModal({ onClose, initialPet }) { const [step, setStep] = React.useState(1); const [pet, setPet] = React.useState(initialPet || 'dog'); const [catAge, setCatAge] = React.useState('adult'); const [size, setSize] = React.useState('small'); const [service, setService] = React.useState('Full groom'); const [extras, setExtras] = React.useState({}); const [form, setForm] = React.useState({ name: '', mobile: '', petName: '', date: '', time: 'Morning (9–12)', area: '' }); // keep service valid when pet changes React.useEffect(() => { const opts = SERVICE_OPTS[pet]; if (!opts.includes(service)) setService(opts[0]); setExtras({}); }, [pet]); // eslint-disable-line const set = (k, v) => setForm(f => ({ ...f, [k]: v })); const toggle = (k) => setExtras(e => ({ ...e, [k]: !e[k] })); const priceFor = (svc) => (pet === 'cat' ? (BASE.cat[catAge] || {})[svc] : pet === 'dog' ? (BASE.dog[size] || {})[svc] : (BASE[pet] || {})[svc]) || 0; const base = priceFor(service); const catAgeLabel = (CAT_AGES.find(a => a.key === catAge) || {}).label; const sizeName = size.charAt(0).toUpperCase() + size.slice(1); const dogSizeLabel = pet === 'dog' ? `${sizeName} dog` : ''; const petDesc = pet === 'cat' ? `Cat (${catAge === 'kitten' ? 'Kitten, up to 8 months' : 'Adult'})` : pet === 'dog' ? `Dog (${sizeName})` : null; const extrasList = EXTRAS.filter(x => extras[x.key]); const extrasTotal = extrasList.reduce((s, x) => s + x.price, 0); const total = base + extrasTotal; const petLabel = PET_OPTS.find(p => p.key === pet).label; const showExtras = pet === 'dog' || pet === 'cat'; const buildMessage = () => { const lines = [ 'Hi Fluffy Friends! 🐾 I\'d like to book a groom:', `• Pet: ${petDesc || petLabel}${form.petName ? ` — ${form.petName}` : ''}`, `• Service: ${service} — AED ${base}`, ]; if (extrasList.length) lines.push(`• Add-ons: ${extrasList.map(x => `${x.label} (AED ${x.price})`).join(', ')}`); lines.push(`• Estimated total: AED ${total}`); if (form.date) lines.push(`• Preferred date: ${form.date}`); lines.push(`• Time: ${form.time}`); if (form.name) lines.push(`• Name: ${form.name}`); if (form.mobile) lines.push(`• Mobile: ${form.mobile}`); if (form.area) lines.push(`• Area: ${form.area}`); return lines.join('\n'); }; const confirm = () => { openWhatsApp(buildMessage()); setStep(3); }; return (
e.stopPropagation()}> {step < 3 && (

{step === 1 ? 'Book a groom' : 'Your details'}

)} {step === 1 && (
{PET_OPTS.map(p => ( ))}
{pet === 'cat' && (
)} {pet === 'dog' && (
)}
{showExtras && (
{EXTRAS.map(x => ( toggle(x.key)} /> ))}
)} {pet === 'rabbit' && (

A note on rabbits

We don’t shower rabbits — we use safe, water-free spot-cleaning to keep them warm and healthy.

)}
{pet === 'cat' ? `${service} · ${catAge === 'kitten' ? 'Kitten' : 'Adult cat'}` : service}AED {base}
{extrasList.map(x =>
{x.label}AED {x.price}
)}
Estimated totalAED {total}
)} {step === 2 && (
{petLabel} {pet === 'cat' && {catAgeLabel}} {pet === 'dog' && {dogSizeLabel}} {service} AED {total}
set('name', e.target.value)} /> set('petName', e.target.value)} />
set('mobile', e.target.value)} />
set('date', e.target.value)} />
set('area', e.target.value)} />

We’ll open WhatsApp with your booking ready to send.

)} {step === 3 && (

Sent to WhatsApp!

We’ve opened a chat with your {petLabel.toLowerCase()}’s {service.toLowerCase()} booking ready to send. We’ll confirm your time and bring the pink van right to your door. See you soon!

)}
); } /* Typical groom time per pet (minutes), from historical booking durations. Drives how long a slot is reserved so the groomer's schedule is blocked accurately (esp. for multi-pet bookings). Dogs use size-based durations (see DOG_SIZES); cat/bird/rabbit use these flat estimates. */ const DURATIONS = { cat: 60, bird: 45, rabbit: 45 }; /* Dog size → typical groom duration (minutes), from the size-by-duration data. */ const DOG_SIZES = [ { key: 'small', label: 'Small dog · up to 8kg', duration: 60 }, { key: 'medium', label: 'Medium dog · 8–15kg', duration: 90 }, { key: 'large', label: 'Large dog · 15kg+', duration: 120 }, ]; Object.assign(window, { BookingModal, BOOKING_DATA: { PET_OPTS, BASE, CAT_AGES, SERVICE_OPTS, EXTRAS, DURATIONS, DOG_SIZES, SERVICE_DURATIONS } });