// Shared UI components for VIP Beauty Lounge prototype. const { useState, useEffect, useRef, useMemo, useCallback } = React; // ── Logo (uses the verified red+white SVG file) ───────────────────────────── function Logo({ height = 28, mode = 'red' }) { return ( VIP Beauty Lounge ); } // ── Star rating glyph ─────────────────────────────────────────────────────── function Stars({ n = 5, size = 14 }) { return ( {Array.from({ length: 5 }).map((_, i) => ( ))} ); } // ── Trust strip (5.0 · 421 · Al Manara) ───────────────────────────────────── function TrustStrip({ tone = 'light' }) { const dark = tone === 'dark'; return (
5.0
Fresha rating
from 421 guests
421
five-star reviews
6 this week
VIP
Royal Room
private by request
Open
Villa 148, Al Manara
Daily 10:00 — 22:00
); } // ── Service row used inside Services and home grids ───────────────────────── function ServiceRow({ name, price, duration, signature, onBook }) { return (
{signature && Signature} {name} {duration && {duration}}
); } // ── Section header with eyebrow + display + lede ──────────────────────────── function SectionHeader({ eyebrow, title, lede, align = 'left' }) { return (
{eyebrow &&
{eyebrow}
}

{title}

{lede &&

{lede}

}
); } // ── Header / nav ──────────────────────────────────────────────────────────── function Header({ route, navigate, dark = false }) { const [open, setOpen] = useState(false); const [scrolled, setScrolled] = useState(false); useEffect(() => { const onScroll = () => setScrolled(window.scrollY > 24); onScroll(); window.addEventListener('scroll', onScroll, { passive: true }); return () => window.removeEventListener('scroll', onScroll); }, []); const nav = [ ['home', 'Home'], ['services', 'Services'], ['vip', 'VIP Room'], ['gallery', 'Gallery'], ['about', 'About'], ['reviews', 'Reviews'], ['contact', 'Visit'], ]; return (
{ e.preventDefault(); navigate('home'); }} href="#home">
+971 555 080 506
{open && (
{nav.map(([id, label]) => ( { e.preventDefault(); setOpen(false); navigate(id); }}>{label} ))}
)}
); } // ── Mobile bottom action bar ──────────────────────────────────────────────── function MobileBar({ navigate }) { return (
Call WhatsApp
); } // ── Footer ────────────────────────────────────────────────────────────────── function Footer({ navigate }) { return ( ); } // ── Quick book sheet (used from "Book" buttons) ──────────────────────────── function BookSheet({ open, onClose, preselect }) { const [step, setStep] = useState(0); const [pick, setPick] = useState(preselect || null); const [date, setDate] = useState('Sat 24 May'); const [time, setTime] = useState('17:30'); const [room, setRoom] = useState('Main floor'); const [name, setName] = useState(''); const [phone, setPhone] = useState(''); useEffect(() => { if (open) { setStep(0); setPick(preselect || null); } }, [open, preselect]); if (!open) return null; const allSvc = window.SERVICES.flatMap(c => c.items.map(it => ({ ...it, cat: c.title }))); const popular = ['Hair Cut','Beard Signature','Signature Manicure','Signature Pedicure','Hydra Facial + Diamond Peel','Keratin / Brazilian Blowout']; const slots = ['10:00','10:30','11:00','12:30','14:00','15:30','17:30','18:00','19:30','20:30']; const dates = ['Fri 23 May','Sat 24 May','Sun 25 May','Mon 26 May','Tue 27 May','Wed 28 May']; return (
e.stopPropagation()}>
Book an appointment
{['Service','Time','Room','Confirm'].map((label, i) => (
i ? 'is-done' : ''}`}> {i + 1} {label}
))}
{step === 0 && (

What would you like booked?

{popular.map(p => { const svc = allSvc.find(s => s.name === p); if (!svc) return null; return ( ); })}
Browse the full menu
{window.SERVICES.map(cat => (
{cat.title}
    {cat.items.map(it => (
  • ))}
))}
)} {step === 1 && (

Pick a date and time

{dates.map(d => ( ))}
{slots.map(s => ( ))}

Times shown are illustrative. Final availability is reconciled with Fresha at confirmation.

)} {step === 2 && (

Where would you like to be seated?

{[ { id: 'Main floor', sub: 'Standard service · included', add: 0 }, { id: 'Private Room', sub: 'Private suite · one stylist', add: 150 }, { id: 'Royal Room', sub: 'Royal Room — full suite, full team', add: 200 }, ].map(r => ( ))}
)} {step === 3 && (

Confirm your reservation

Service{pick?.name || '—'}
Date{date} · {time}
Seating{room}
Estimated total AED {(pick?.price || 0) + (room === 'Private Room' ? 150 : room === 'Royal Room' ? 200 : 0)}

A team member will confirm by WhatsApp within a few minutes during opening hours. No payment is taken here.

)}
{step > 0 && }
{step < 3 && ( )} {step === 3 && ( )}
); } Object.assign(window, { Logo, Stars, TrustStrip, ServiceRow, SectionHeader, Header, MobileBar, Footer, BookSheet });