// ============================================================
// Enfield Royal Clinic — shared components (atoms + chrome)
// ============================================================
const { useState, useEffect, useRef, useMemo, useCallback } = React;
// -------------- Icons (inline, tiny, no heavy lib) ---------------
const Icon = ({ name, size = 18, stroke = 1.5, ...rest }) => {
const s = { width: size, height: size, fill: 'none', stroke: 'currentColor', strokeWidth: stroke, strokeLinecap: 'round', strokeLinejoin: 'round', ...rest.style };
const props = { viewBox: '0 0 24 24', xmlns: 'http://www.w3.org/2000/svg', style: s, ...rest };
switch (name) {
case 'arrow-right': return ();
case 'arrow-up-right': return ();
case 'chevron-down': return ();
case 'phone': return ();
case 'whatsapp': return ();
case 'mail': return ();
case 'pin': return ();
case 'menu': return ();
case 'close': return ();
case 'check': return ();
case 'shield': return ();
case 'lock': return ();
case 'eye-off': return ();
case 'sparkle': return ();
case 'search': return ();
case 'instagram': return ();
case 'facebook': return ();
case 'youtube': return ();
case 'x': return ();
default: return null;
}
};
// ---------- Brand rosette (decorative — official master SVG flagged in media-manifest) ----------
const Rosette = ({ size = 28, color = 'currentColor' }) => (
);
// ---------- Lockup ----------
const BrandLockup = ({ inverse = false, compact = false }) => {
const color = inverse ? '#FFFFFF' : 'var(--primary)';
const gold = inverse ? 'var(--accent)' : 'var(--accent)';
return (
Enfield Royal
Clinic · Dubai · Since 2011
);
};
// ---------- Compliance chip ----------
const ComplianceTag = ({ kind = 'verified', children, style }) => {
const klass = 'chip ' + (kind === 'verified' ? 'chip-verified' : kind === 'warn' ? 'chip-warn' : '');
return (
{children}
);
};
// ---------- Image with placeholder fallback ----------
const Img = ({ src, alt, label, ...rest }) => {
const [err, setErr] = useState(false);
if (err || !src) {
return {label || alt || 'IMAGE'}
;
}
return
setErr(true)} loading="lazy" {...rest} />;
};
// ---------- Router (hash) ----------
const RouterCtx = React.createContext({ path: '/', go: () => {} });
const useRouter = () => React.useContext(RouterCtx);
const RouterProvider = ({ children }) => {
const [path, setPath] = useState(() => {
const h = window.location.hash.replace(/^#/, '');
return h && h.startsWith('/') ? h : '/';
});
useEffect(() => {
const onHash = () => {
const h = window.location.hash.replace(/^#/, '');
setPath(h && h.startsWith('/') ? h : '/');
window.scrollTo({ top: 0, behavior: 'instant' });
};
window.addEventListener('hashchange', onHash);
return () => window.removeEventListener('hashchange', onHash);
}, []);
const go = useCallback((p) => {
window.location.hash = p;
}, []);
return {children};
};
const Link = ({ to, children, className, style, onClick }) => {
const { go } = useRouter();
return (
{
e.preventDefault();
if (onClick) onClick(e);
go(to);
}}
>
{children}
);
};
// ---------- Top promotional / compliance bar ----------
const TopBar = () => (
);
// ---------- Mega-menu (Treatments dropdown) ----------
const MegaMenu = ({ open, onClose }) => {
const areas = window.ERC_DATA.areas;
return (
Treatments by area
Care planned around your candidacy, not a price list.
Every treatment begins with a doctor-led consultation. We don't publish prices — every plan is individual and quoted after review.
View all treatment areas
{areas.map((a) => (
{a.eyebrow}
{a.name}
))}
);
};
// ---------- Navbar ----------
const Navbar = () => {
const [menuOpen, setMenuOpen] = useState(false);
const [scrolled, setScrolled] = useState(false);
const [mobileOpen, setMobileOpen] = useState(false);
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 8);
window.addEventListener('scroll', onScroll, { passive: true });
onScroll();
return () => window.removeEventListener('scroll', onScroll);
}, []);
const { path } = useRouter();
const isActive = (p) => (p === '/' ? path === '/' : path.startsWith(p));
return (
setMenuOpen(false)} />
{mobileOpen && setMobileOpen(false)} />}
);
};
const MobileMenu = ({ onClose }) => (
{[
{ to: '/treatments', label: 'Treatments' },
{ to: '/doctors', label: 'Doctors' },
{ to: '/before-after', label: 'Before & After' },
{ to: '/about', label: 'About' },
{ to: '/locations', label: 'Locations' },
{ to: '/contact', label: 'Contact' },
].map((i) => (
{i.label}
))}
Book a Consultation
);
// ---------- Footer ----------
const Footer = () => {
const D = window.ERC_DATA;
return (
);
};
const FooterCol = ({ title, links }) => (
{title}
{links.map(l => (
-
{l.label}
))}
);
// ---------- Mobile bottom action bar ----------
const MobileBottomBar = () => {
const D = window.ERC_DATA;
return (
);
};
// ---------- Eyebrow + dividers helper ----------
const SectionHead = ({ eyebrow, title, lede, align = 'left', children }) => (
{eyebrow &&
{eyebrow}}
{title &&
{title}
}
{lede &&
{lede}
}
{children}
);
// Export to window
Object.assign(window, {
Icon, Rosette, BrandLockup, ComplianceTag, Img,
RouterProvider, useRouter, Link,
Navbar, Footer, MobileBottomBar, SectionHead,
});