/* global React */
/* Multi-step booking form */
const DB = window.BVH_DATA;
const { useState: useStateB, useEffect: useEffectB } = React;
function BookPage({ setRoute, location, setLocation, prefillService }) {
const [step, setStep] = useStateB(0);
const [form, setForm] = useStateB({
urgency: '',
petType: '',
petName: '',
petAge: '',
sex: '',
location: location,
service: prefillService || '',
preferredDate: '',
preferredTime: '',
ownerName: '',
phone: '',
email: '',
notes: '',
contactMethod: 'whatsapp',
});
const [errors, setErrors] = useStateB({});
useEffectB(() => { setForm(f => ({...f, location})); }, [location]);
const update = (k, v) => { setForm(f => ({...f, [k]: v})); setErrors(e => ({...e, [k]: null})); };
const steps = [
{ id: 0, label: 'About your pet' },
{ id: 1, label: 'Reason for visit' },
{ id: 2, label: 'Time & place' },
{ id: 3, label: 'Your contact' },
{ id: 4, label: 'Confirm' },
];
function validateStep(s) {
const e = {};
if (s === 0) {
if (!form.petType) e.petType = 'Pick a species';
if (!form.petName) e.petName = 'Pet name needed';
}
if (s === 1) {
if (!form.urgency) e.urgency = 'Tell us how urgent';
if (!form.service) e.service = 'Pick a reason';
}
if (s === 2) {
if (!form.location) e.location = 'Pick a location';
if (!form.preferredDate) e.preferredDate = 'Pick a preferred day';
}
if (s === 3) {
if (!form.ownerName) e.ownerName = 'Your name';
if (!form.phone || form.phone.length < 7) e.phone = 'Mobile number needed';
if (form.email && !/.+@.+\..+/.test(form.email)) e.email = 'Invalid email';
}
setErrors(e);
return Object.keys(e).length === 0;
}
function next() {
if (validateStep(step)) setStep(s => Math.min(steps.length-1, s+1));
}
function back() { setStep(s => Math.max(0, s-1)); }
if (form.urgency === 'now' && step <= 1) {
return (
! EMERGENCY — DO NOT FILL A FORM
Please call — now.
If this is an emergency, do not wait for a form confirmation. Pick up the phone — we'll triage on the call and prepare the team while you drive.
);
}
// success
if (step === 5) {
const svc = DB.services.find(s => s.id === form.service);
const loc = DB.locations.find(l => l.id === form.location);
return (
✓
06 REQUEST RECEIVED
Thank you, {form.ownerName.split(' ')[0] || 'friend'}.
We've received the request for {form.petName} . A team member from {loc?.short} will WhatsApp you within an hour during opening hours to confirm a time.
BOOKING — DRAFT REF. BVH-{Math.random().toString(36).slice(2,8).toUpperCase()}
);
}
return (
06 BOOK AN APPOINTMENT
Tell us a little about your patient.
Five short steps. We'll confirm by WhatsApp within an hour during opening hours. If anything is urgent, please call {DB.hospital.phoneMain} — don't wait for a form confirmation.
{steps.map(s => (
s.id?'done':''}`}>
{String(s.id+1).padStart(2,'0')} {s.label}
))}
{step === 0 && (
STEP 01 — ABOUT YOUR PET
Who are we seeing?
SPECIES
{['Dog','Cat','Rabbit','Bird','Exotic'].map(t => (
update('petType', t)}>{t}
))}
{errors.petType &&
{errors.petType} }
)}
{step === 1 && (
STEP 02 — REASON FOR VISIT
How urgent is this?
URGENCY
{[
{ k:'now', t:'Right now', d:'Emergency — accident, sudden illness', em:true },
{ k:'this-week', t:'This week', d:'Worrying but not urgent — soonest available' },
{ k:'routine', t:'Routine', d:'Check-up, vaccines, dental — any convenient slot' },
].map(u => (
update('urgency', u.k)}
style={{
textAlign:'left',
padding:'18px 20px',
border:'1px solid '+(form.urgency===u.k?(u.em?'var(--emergency)':'var(--vet)'):'var(--line-strong)'),
background: form.urgency===u.k?(u.em?'rgba(200,71,47,.06)':'rgba(30,42,120,.04)'):'var(--paper)',
borderRadius:6,
cursor:'pointer',
}}
>
{u.em && }
{u.t}
{u.d}
))}
{errors.urgency &&
{errors.urgency} }
REASON
{DB.services.map(s => (
update('service', s.id)}>{s.name}
))}
{errors.service &&
{errors.service} }
ANYTHING WE SHOULD KNOW (OPTIONAL)
)}
{step === 2 && (
STEP 03 — TIME & PLACE
When and where?
LOCATION
{DB.locations.map(l => (
{ update('location', l.id); setLocation(l.id); }}
style={{
textAlign:'left',
padding:'16px 18px',
border:'1px solid '+(form.location===l.id?'var(--vet)':'var(--line-strong)'),
background: form.location===l.id?'rgba(30,42,120,.04)':'var(--paper)',
borderRadius:6,
cursor:'pointer',
}}
>
{l.isFlagship?'FLAGSHIP HOSPITAL':'NEIGHBOURHOOD CLINIC'}
{l.name}
{l.addressLine1} {l.hoursLine}
))}
)}
{step === 3 && (
STEP 04 — YOUR CONTACT
How can we reach you?
CONFIRM MY BOOKING BY
{[{k:'whatsapp',t:'WhatsApp'},{k:'phone',t:'Phone call'},{k:'email',t:'Email'}].map(c => (
update('contactMethod', c.k)}>{c.t}
))}
)}
{step === 4 && (
)}
← Back
{step === 4 ? (
setStep(5)}>
Confirm booking →
) : (
Continue →
)}
);
}
function Row({ k, v }) {
return (
);
}
function BookingReview({ form }) {
const svc = DB.services.find(s => s.id === form.service);
const loc = DB.locations.find(l => l.id === form.location);
return (
STEP 05 — REVIEW
Does this look right?
{form.notes &&
}
✓
By submitting, you agree we can contact you about this appointment. No prices are charged at booking — we'll share a per-case estimate before any treatment begins.
);
}
Object.assign(window, { BookPage });