// Modern Vet — shared components const { useState, useEffect, useRef, useMemo, useCallback } = React; // ── ICONS ───────────────────────────────────────────────────────── const Icon = ({ name, className = "" }) => { const common = { width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.6, strokeLinecap: "round", strokeLinejoin: "round", className }; switch (name) { case "phone": return ; case "whatsapp": return ; case "menu": return ; case "close": return ; case "arrow-right": return ; case "chevron-down": return ; case "chevron-right": return ; case "map-pin": return ; case "clock": return ; case "emergency": return ; case "consult": return ; case "syringe": return ; case "surgery": return ; case "dentistry": return ; case "heart": return ; case "brain": return ; case "oncology": return ; case "eye": return ; case "ortho": return ; case "imaging": return ; case "physio": return ; case "grooming": return ; case "mobile": return ; case "chip": return ; case "paw": return ; case "check": return ; case "search": return ; case "globe": return ; case "calendar": return ; default: return null; } }; // ── BRAND MARK ──────────────────────────────────────────────────── // The wedge / pet silhouette mark from the logo, simplified as a recurring graphic device const Wedge = ({ className = "", color = "currentColor" }) => ( ); // ── LOGO LOCKUP ─────────────────────────────────────────────────── const Logo = ({ onNavy = false, onClick }) => ( { e.preventDefault(); onClick && onClick(); }} className="logo">
MODERN VET
SINCE 1995 · DUBAI
); // ── NAV ─────────────────────────────────────────────────────────── const NAV_ITEMS = [ { label: "Services", href: "#/services" }, { label: "Vets & Team", href: "#/vets" }, { label: "Branches", href: "#/branches" }, { label: "Prices", href: "#/prices" }, { label: "About", href: "#/about" }, ]; const Nav = ({ onBook, currentHash, branch, onBranchChange }) => { const [open, setOpen] = useState(false); const [scrolled, setScrolled] = useState(false); const [branchOpen, setBranchOpen] = useState(false); useEffect(() => { const onScroll = () => setScrolled(window.scrollY > 8); window.addEventListener("scroll", onScroll, { passive: true }); return () => window.removeEventListener("scroll", onScroll); }, []); const activeBranch = BRANCHES.find(b => b.slug === branch) || BRANCHES[0]; return (
(window.location.hash = "/")} />
setBranchOpen(false)}> {branchOpen && (
Choose your nearest branch
{BRANCHES.map(b => ( ))}
)}
{open && (
{NAV_ITEMS.map(item => ( setOpen(false)} className="nav-mobile-link">{item.label} ))}
)}
); }; // ── EMERGENCY STRIP ─────────────────────────────────────────────── const EmergencyStrip = () => (
24/7 Emergency Hospital · Al Wasl, Umm Suqeim · Call 800-VET WhatsApp
); // ── FOOTER ──────────────────────────────────────────────────────── const Footer = () => ( ); // ── MOBILE BOTTOM BAR ───────────────────────────────────────────── const MobileBar = ({ onBook }) => (
Call 800-VET WhatsApp
); // ── BOOKING MODAL (multi-step) ──────────────────────────────────── const BookModal = ({ open, onClose, branch, defaultService }) => { const [step, setStep] = useState(0); const [data, setData] = useState({ branch: branch || "al-wasl", service: defaultService || "pet-consultation", petType: "Dog", petName: "", petAge: "", date: "", time: "10:00", name: "", phone: "", email: "", notes: "", }); useEffect(() => { if (open) { setStep(0); setData(d => ({ ...d, branch: branch || d.branch, service: defaultService || d.service })); } }, [open, branch, defaultService]); useEffect(() => { const onKey = (e) => { if (e.key === "Escape") onClose(); }; if (open) window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [open, onClose]); if (!open) return null; const update = (k, v) => setData(d => ({ ...d, [k]: v })); const activeBranch = BRANCHES.find(b => b.slug === data.branch); const activeService = SERVICES.find(s => s.slug === data.service); const steps = ["Branch & service", "Your pet", "Date & contact", "Confirm"]; const next = () => setStep(s => Math.min(s + 1, steps.length - 1)); const prev = () => setStep(s => Math.max(s - 1, 0)); // Date helpers — generate next 14 days const days = Array.from({ length: 14 }, (_, i) => { const d = new Date(); d.setDate(d.getDate() + i); return d; }); const fmtDay = (d) => d.toLocaleDateString("en-US", { weekday: "short", month: "short", day: "numeric" }); const TIMES = ["08:00", "09:00", "10:00", "11:00", "12:00", "14:00", "15:00", "16:00", "17:00", "18:00", "19:00"]; return (
e.stopPropagation()} role="dialog" aria-label="Book appointment">
Book an appointment

A vet you can call by name.

No phone tag. Pick a branch, a time and we'll confirm by WhatsApp within an hour.

    {steps.map((s, i) => (
  1. {i < step ? "✓" : i + 1} {s}
  2. ))}
Emergency?
Call 800-VET — open now
{step === 0 && (

Where would you like to be seen?

{BRANCHES.map(b => ( ))}

What is this visit for?

{SERVICES.filter(s => !s.isEmergency).slice(0, 9).map(s => ( ))}
)} {step === 1 && (

Tell us about your pet