// Petzone — shared components (icons, logo, nav, footer, mobile bar, book sheet) const { useState, useEffect, useRef, useMemo } = React; // ============== ICONS (simple stroke set) ============== const Icon = ({ name, size = 22, stroke = 1.6, className = "" }) => { const common = { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: stroke, strokeLinecap: "round", strokeLinejoin: "round", className }; const paths = { stethoscope: <>, shield: <>, scalpel: <>, tooth: <>, flask: <>, scan: <>, pill: <>, bowl: <>, phone: <>, whatsapp: <>, pin: <>, clock: <>, mail: <>, arrow: <>, arrowLeft: <>, check: <>, star: <>, paw: <>, menu: <>, close: <>, globe: <>, heart: <>, chevron: <>, sparkles: <>, }; return {paths[name] || paths.paw}; }; // ============== LOGO (clean SVG redraw — original mark) ============== const PetzoneLogo = ({ size = 36, mono = false }) => { const c = mono ? "currentColor" : "var(--teal)"; return (
Petzone Veterinary · Dubai
); }; // ============== NAV ============== const Nav = ({ page, go, openBook }) => { const [scrolled, setScrolled] = useState(false); const [open, setOpen] = useState(false); const [servicesOpen, setServicesOpen] = useState(false); useEffect(() => { const onScroll = () => setScrolled(window.scrollY > 8); window.addEventListener("scroll", onScroll); return () => window.removeEventListener("scroll", onScroll); }, []); const link = (key, label) => ( ); return (
{open && (
{[["home","Home"],["services","Services"],["vets","Our vets"],["about","About"],["contact","Contact"]].map(([k,l]) => ( ))}
)}
); }; // ============== FOOTER ============== const Footer = ({ go, openBook }) => { const c = window.PZ_DATA.clinic; return (

A family-owned small-animal clinic on Sheikh Zayed Road. Caring for Dubai's dogs, cats, birds and small mammals since 2009.

Call us
Services
    {window.PZ_DATA.services.slice(0,6).map(s => (
  • ))}
Visit
  • {c.address.line1}
    {c.address.line2}
    {c.address.line3}
  • {c.phonePrimary}
    (2nd line {c.phoneSecondary} — confirming)
  • {c.email}
  • Schedule pending — listings disagree across 3 versions; awaiting client confirmation.
© {new Date().getFullYear()} Petzone Veterinary Clinic. Where pets come first. Sheikh Zayed Road · Al Wasl / Jumeirah · Dubai
); }; // ============== MOBILE BOTTOM BAR ============== const MobileBar = ({ openBook }) => (
Call
); // ============== BOOK SHEET (multi-step) ============== const BookSheet = ({ open, onClose, prefill }) => { const [step, setStep] = useState(1); const [form, setForm] = useState({ petType: "Dog", petName: "", service: prefill?.service || "Consultation & Wellness", ownerName: "", phone: "", email: "", date: "", time: "", notes: "", }); useEffect(() => { if (open) { setStep(1); setForm(f => ({ ...f, service: prefill?.service || f.service })); } }, [open, prefill]); if (!open) return null; const update = (k, v) => setForm(f => ({ ...f, [k]: v })); const canNext1 = !!form.petType && !!form.service; const canNext2 = !!form.ownerName && !!form.phone; const submitted = step === 4; return (
{submitted ? "We've got it" : "Book an appointment"}
{!submitted &&
Step {step} of 3 · about 60 seconds
}
{!submitted && (
{[1,2,3].map(n => (
))}
)}
{step === 1 && (
{["Dog","Cat","Bird","Small mammal"].map(t => ( ))}
update("petName", e.target.value)} />
)} {step === 2 && (
update("ownerName", e.target.value)} />
update("phone", e.target.value)} />
update("email", e.target.value)} />
We only collect the minimum we need to call you back. No medical-history fields — your vet will take that in person.
)} {step === 3 && (
update("date", e.target.value)} />