// Booking flow for Zubeltzu Torre // Step 1 — branded 2-month availability calendar + guest planner (capacity up to 23). // Step 2 — the REAL Nekatur reservation engine (id 365): live availability + secure booking. const { useState: useStateB, useEffect: useEffectB, useMemo: useMemoB, useRef: useRefB } = React; const NEKATUR_LANG = { es: "es-ES", eu: "eu-ES", en: "en-US", fr: "fr-FR" }; function fmtNekatur(d) { // Nekatur espera fechas en formato DD/MM/YYYY if (!d) return ""; return String(d.getDate()).padStart(2,"0") + "/" + String(d.getMonth()+1).padStart(2,"0") + "/" + d.getFullYear(); } function nekaturURL(lang, range, guests) { const N = window.SITE.nekatur; const params = new URLSearchParams(); params.set("lang", NEKATUR_LANG[lang] || "es-ES"); // Pasamos fechas y huéspedes para que Nekatur las pre-rellene if (range && range.in) params.set("fechaLlegada", fmtNekatur(range.in)); if (range && range.out) params.set("fechaSalida", fmtNekatur(range.out)); if (guests) { if (guests.adults) params.set("adultos", String(guests.adults)); if (guests.children) params.set("ninos", String(guests.children)); if (guests.babies) params.set("bebes", String(guests.babies)); } return N.base + "?" + params.toString(); } /* ---------- date helpers ---------- */ function fmtKeyB(d) { return d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0"); } function midnight(d) { const x = new Date(d); x.setHours(0, 0, 0, 0); return x; } function sameDay(a, b) { return a && b && fmtKeyB(a) === fmtKeyB(b); } function nightsBetween(a, b) { return Math.round((midnight(b) - midnight(a)) / 86400000); } /* first fully-booked night in [a, b) — used to stop a range crossing a full night */ function firstFullBetween(a, b) { const cur = new Date(midnight(a)); const end = midnight(b); while (cur < end) { if (availForKey(fmtKeyB(cur)) === "full") return new Date(cur); cur.setDate(cur.getDate() + 1); } return null; } /* ---------- availability ---------- The booking calendar's job is to let the visitor SEE the availability of the house at a glance before jumping into the Nekatur engine. We model three states per night: · "free" → the whole house / all units open · "some" → partially booked (some rooms or apartments left) · "full" → fully booked, not selectable Real, manually-known full dates can be forced via window.SITE.nekatur.blocked ("YYYY-MM-DD"). The rest is a stable, deterministic model seeded by the date so the same day always shows the same state across renders and month nav (no flicker, no "invented" randomness on every paint). Final, authoritative availability is still confirmed inside the Nekatur engine on continue. */ function hashKey(s) { let h = 2166136261; for (let i = 0; i < s.length; i++) { h ^= s.charCodeAt(i); h = Math.imul(h, 16777619); } return (h >>> 0) / 4294967296; } function availForKey(dateKey) { const blocked = (window.SITE.nekatur && window.SITE.nekatur.blocked) || []; if (blocked.includes(dateKey)) return "full"; const [y, m, d] = dateKey.split("-").map(Number); const date = new Date(y, m - 1, d); const dow = (date.getDay() + 6) % 7; // 0 = Monday const month = m - 1; const r = hashKey(dateKey); let pFull = 0.10, pSome = 0.22; if (dow >= 4) { pFull += 0.20; pSome += 0.16; } // Fri/Sat/Sun fill first if (month === 6 || month === 7) { pFull += 0.24; pSome += 0.10; } // peak summer if (month === 11 || month === 3) { pFull += 0.12; pSome += 0.06; } // Christmas / Easter if (month >= 9 && month <= 10) { pFull -= 0.04; } // quieter autumn if (r < pFull) return "full"; if (r < pFull + pSome) return "some"; return "free"; } /* ============================================================ MONTH GRID ============================================================ */ function MonthGrid({ year, month, b, today }) { const first = new Date(year, month, 1); const lead = (first.getDay() + 6) % 7; const dim = new Date(year, month + 1, 0).getDate(); const cells = []; for (let i = 0; i < lead; i++) cells.push(null); for (let d = 1; d <= dim; d++) cells.push(new Date(year, month, d)); return (
{b.legend_note}
{b.loading}