"use client"; import Link from "next/link"; import { useCallback, useEffect, useId, useRef, useState, useSyncExternalStore, } from "react"; import { createPortal } from "react-dom"; import { bookingStyleReviews, overallRatingOutOfFive, } from "@/lib/mocks/bookingReviews"; import { siteConfig } from "@/lib/mocks/site"; function useIsClient() { return useSyncExternalStore( () => () => {}, () => true, () => false, ); } type ReviewsMenuProps = { variant?: "default" | "topBar" }; export function ReviewsMenu({ variant = "default" }: ReviewsMenuProps) { const [open, setOpen] = useState(false); const isTopBar = variant === "topBar"; const mounted = useIsClient(); const triggerRef = useRef(null); const panelRef = useRef(null); const close = useCallback(() => setOpen(false), []); useEffect(() => { if (!open) return; const prev = document.body.style.overflow; document.body.style.overflow = "hidden"; const triggerEl = triggerRef.current; function onKey(e: KeyboardEvent) { if (e.key === "Escape") close(); } document.addEventListener("keydown", onKey); queueMicrotask(() => { panelRef.current ?.querySelector("button[aria-label='Close']") ?.focus(); }); return () => { document.body.style.overflow = prev; document.removeEventListener("keydown", onKey); triggerEl?.focus(); }; }, [open, close]); const dialog = open && mounted ? (
    {bookingStyleReviews.map((r) => (
  • {r.author}

    {r.country} · {r.stayDate}

    {r.rating.toFixed(1)}/{r.maxRating}

    {r.title}

    {r.text}

    Stayed in: {r.roomType}

  • ))}
Read all reviews
) : null; return ( <> {mounted && dialog ? createPortal(dialog, document.body) : null} ); } /** Booking.com–style wordmark: “Booking” + yellow dot + “.com” */ function BookingDotLogo({ className = "", compact = false, }: { className?: string; compact?: boolean; }) { if (compact) { return ( Booking .com ); } return (
Booking .com
); } /** Five circles: filled amount per position = min(1, max(0, rating - i)) */ function CircleRatingRow({ rating, max = 5 }: { rating: number; max?: number }) { const uid = useId().replace(/:/g, ""); const size = 26; const vb = 24; const cx = 12; const cy = 12; const r = 8; const stroke = "#d6d3d1"; return (
{Array.from({ length: max }, (_, i) => { const fill = Math.min(1, Math.max(0, rating - i)); const clipW = vb * fill; const clipId = `${uid}-clip-${i}`; return ( {fill > 0 ? ( <> ) : null} ); })}
); } function CircleRatingMini({ rating }: { rating: number }) { const uid = useId().replace(/:/g, ""); const max = 5; const vb = 24; const cx = 12; const cy = 12; const r = 7; return ( {Array.from({ length: max }, (_, i) => { const fill = Math.min(1, Math.max(0, rating - i)); const clipW = vb * fill; const clipId = `${uid}-m-${i}`; return ( {fill > 0 ? ( <> ) : null} ); })} ); }