UNPKG

vue-hotel-booking-calendar

Version:

A Vue 3 calendar component suite for hotel bookings with price calculation, hotel dashboard, custom text labels, and flexible navigation. Features guest booking calendar and owner dashboard with elegant white design and full internationalization support.

694 lines (693 loc) 28.7 kB
import { defineComponent as ge, ref as Z, computed as M, onMounted as be, watch as ie, createElementBlock as k, openBlock as v, normalizeClass as j, createElementVNode as s, createCommentVNode as A, toDisplayString as u, Fragment as E, renderList as G, withKeys as he, withModifiers as me, createTextVNode as De, renderSlot as fe, normalizeStyle as ae } from "vue"; const ye = { class: "calendar-header" }, pe = ["disabled", "aria-label"], we = { class: "month-year" }, _e = ["disabled", "aria-label"], Se = { key: 0, class: "selection-error" }, Ce = { class: "error-content" }, Me = { class: "error-message" }, $e = { key: 0, class: "blocked-dates" }, xe = ["aria-label"], Be = { class: "calendar-body" }, Ie = { class: "weekdays" }, Pe = { class: "days-grid" }, Oe = ["onClick", "onMouseenter", "tabindex", "aria-label", "onKeydown"], Ve = { class: "day-content" }, Ne = { class: "day-number" }, Le = { key: 0, class: "day-price" }, Te = { key: 1, class: "price-summary" }, Fe = { class: "price-summary-header" }, Ee = ["aria-label"], Re = { class: "price-content" }, He = { class: "stay-info" }, Ge = { class: "nights" }, Ye = { class: "dates" }, Ae = { key: 0, class: "breakdown" }, je = { class: "breakdown-toggle" }, Ke = { class: "daily-list" }, Ue = { class: "totals" }, We = { class: "subtotal" }, ze = { class: "total" }, qe = ["disabled"], Je = { key: 2, class: "calendar-legend" }, Qe = { class: "legend-item" }, Xe = { class: "legend-item" }, Ze = { class: "legend-item" }, et = /* @__PURE__ */ ge({ __name: "HotelBookingCalendar", props: { modelValue: { default: () => ({ checkIn: null, checkOut: null }) }, availabilityData: { default: () => [] }, minDate: {}, maxDate: {}, locale: { default: "en-GB" }, disablePastDates: { type: Boolean, default: !0 }, allowPreviousMonthNavigation: { type: Boolean, default: !0 }, showPrices: { type: Boolean, default: !1 }, allowSingleDay: { type: Boolean, default: !1 }, theme: { default: "light" }, basePrice: { default: 85 }, currency: { default: "GBP" }, showPriceCalculation: { type: Boolean, default: !0 }, showSelectionErrors: { type: Boolean, default: !0 }, textLabels: { default: () => ({}) } }, emits: ["update:modelValue", "date-click", "date-select", "selection-change", "selection-error", "price-calculation", "book-now"], setup(L, { emit: K }) { const n = L, y = K, b = Z(/* @__PURE__ */ new Date()), oe = Z(null), O = Z(!1), p = Z(null), x = M(() => { if (!n.minDate) { if (n.disablePastDates) { const e = /* @__PURE__ */ new Date(); return e.setHours(0, 0, 0, 0), e; } return null; } return typeof n.minDate == "string" ? new Date(n.minDate) : n.minDate; }), Y = M(() => n.maxDate ? typeof n.maxDate == "string" ? new Date(n.maxDate) : n.maxDate : null), U = M(() => { const e = /* @__PURE__ */ new Map(); return n.availabilityData.forEach((o) => { e.set(o.date, o); }), e; }), ee = M(() => { const e = new Intl.DateTimeFormat(n.locale, { weekday: "short" }), o = []; for (let i = 0; i < 7; i++) { const d = new Date(2023, 0, i + 1); o.push(e.format(d)); } return o; }), te = M(() => { const e = b.value.getFullYear(), o = b.value.getMonth(), i = new Date(e, o, 1), d = new Date(e, o + 1, 0), h = new Date(i), c = new Date(d); h.setDate(h.getDate() - h.getDay()), c.setDate(c.getDate() + (6 - c.getDay())); const w = [], m = new Date(h); for (; m <= c; ) { const $ = H(m), P = { date: new Date(m), dateString: $, isToday: $ === H(/* @__PURE__ */ new Date()), isCurrentMonth: m.getMonth() === o, isPreviousMonth: m.getMonth() < o, isNextMonth: m.getMonth() > o, availability: U.value.get($) }; w.push(P), m.setDate(m.getDate() + 1); } return w; }), W = M(() => { if (n.allowPreviousMonthNavigation || !x.value) return !0; const e = new Date(b.value); e.setMonth(e.getMonth() - 1), e.setDate(1); const o = new Date(x.value); return o.setDate(1), e >= o; }), R = M(() => { if (!Y.value) return !0; const e = new Date(b.value); e.setMonth(e.getMonth() + 1), e.setDate(1); const o = new Date(Y.value); return o.setDate(1), e <= o; }), C = M(() => { var e, o, i, d, h, c, w, m, $, P, X, ue, de; return { previousMonth: ((e = n.textLabels) == null ? void 0 : e.previousMonth) || "Previous month", nextMonth: ((o = n.textLabels) == null ? void 0 : o.nextMonth) || "Next month", bookingSummary: ((i = n.textLabels) == null ? void 0 : i.bookingSummary) || "Booking Summary", nights: ((d = n.textLabels) == null ? void 0 : d.nights) || "nights", night: ((h = n.textLabels) == null ? void 0 : h.night) || "night", priceBreakdown: ((c = n.textLabels) == null ? void 0 : c.priceBreakdown) || "Price breakdown", total: ((w = n.textLabels) == null ? void 0 : w.total) || "Total", bookNow: ((m = n.textLabels) == null ? void 0 : m.bookNow) || "Book Now", available: (($ = n.textLabels) == null ? void 0 : $.available) || "Available", checkoutOnly: ((P = n.textLabels) == null ? void 0 : P.checkoutOnly) || "Checkout Only", blocked: ((X = n.textLabels) == null ? void 0 : X.blocked) || "Blocked", clearSelection: ((ue = n.textLabels) == null ? void 0 : ue.clearSelection) || "Clear selection", dismissError: ((de = n.textLabels) == null ? void 0 : de.dismissError) || "Dismiss error" }; }), _ = M(() => { const { checkIn: e, checkOut: o } = n.modelValue; if (!e || !o) return null; const i = new Date(e), d = new Date(o), h = Math.ceil((d.getTime() - i.getTime()) / (1e3 * 60 * 60 * 24)); if (h <= 0) return null; const c = []; let w = 0; const m = new Date(i); for (; m < d; ) { const $ = H(m), P = U.value.get($), X = (P == null ? void 0 : P.price) || n.basePrice || 85; c.push({ date: $, price: X }), w += X, m.setDate(m.getDate() + 1); } return { basePrice: n.basePrice || 85, nights: h, dailyPrices: c, totalPrice: w, currency: n.currency || "GBP", averagePerNight: w / h }; }), H = (e) => { const o = e.getFullYear(), i = String(e.getMonth() + 1).padStart(2, "0"), d = String(e.getDate()).padStart(2, "0"); return `${o}-${i}-${d}`; }, se = (e) => new Intl.DateTimeFormat(n.locale, { month: "long", year: "numeric" }).format(e), T = (e) => new Intl.NumberFormat(n.locale, { style: "currency", currency: n.currency || "GBP" }).format(e), z = (e, o) => { const i = new Date(e), d = new Date(o), h = new Intl.DateTimeFormat(n.locale, { month: "short", day: "numeric" }); return `${h.format(i)} - ${h.format(d)}`; }, ne = (e) => new Intl.DateTimeFormat(n.locale, { month: "short", day: "numeric" }).format(new Date(e)), le = (e) => e.map((o) => ne(o)).join(", "), q = (e) => { var o; return ((o = e.availability) == null ? void 0 : o.price) || n.basePrice || 0; }, J = (e) => { if (!e.isCurrentMonth) return !0; if (n.disablePastDates) { const o = /* @__PURE__ */ new Date(); o.setHours(0, 0, 0, 0); const i = new Date(e.date); if (i.setHours(0, 0, 0, 0), i < o) return !0; } return !!(x.value && e.date < x.value || Y.value && e.date > Y.value); }, Q = (e) => !!(J(e) || F(e) === "blocked"), F = (e) => { var o; return ((o = e.availability) == null ? void 0 : o.status) || "available"; }, re = (e) => { var o, i; return ((i = (o = p.value) == null ? void 0 : o.blockedDates) == null ? void 0 : i.includes(e)) || !1; }, a = (e, o) => { const i = new Date(e), d = new Date(o), h = new Date(i), c = []; for (h.setDate(h.getDate() + 1); h < d; ) { const w = H(h), m = U.value.get(w); (m == null ? void 0 : m.status) === "blocked" && c.push(w), h.setDate(h.getDate() + 1); } return c; }, l = (e) => e === n.modelValue.checkIn || e === n.modelValue.checkOut, t = (e) => { const { checkIn: o, checkOut: i } = n.modelValue; return !o || !i ? !1 : e > o && e < i; }, r = (e) => e === n.modelValue.checkIn, g = (e) => e === n.modelValue.checkOut, f = (e) => { const o = e.date.toLocaleDateString(n.locale, { weekday: "long", year: "numeric", month: "long", day: "numeric" }), i = F(e), d = q(e); return `${o}, ${i}${d ? `, ${T(d)}` : ""}`; }, D = () => { p.value = null; }, S = (e, o) => ({ type: e, message: { "blocked-dates-in-range": "Selected dates include unavailable periods. Please choose different dates.", "min-stay-not-met": "Minimum stay requirement not met for selected dates.", "max-stay-exceeded": "Selected stay exceeds maximum allowed duration.", "invalid-range": "Invalid date range selected." }[e], blockedDates: o }), B = () => { const e = { checkIn: null, checkOut: null }; y("update:modelValue", e), y("selection-change", e), D(), O.value = !1; }, V = () => { if (_.value && n.modelValue.checkIn && n.modelValue.checkOut) { const e = { selection: { checkIn: n.modelValue.checkIn, checkOut: n.modelValue.checkOut }, calculation: _.value }; y("book-now", e); } }, I = (e) => { if (Q(e)) return; D(); const { checkIn: o, checkOut: i } = n.modelValue, d = e.dateString; if (y("date-click", d, F(e)), !o || o && i) { const h = { checkIn: d, checkOut: null }; y("update:modelValue", h), y("selection-change", h), O.value = !0; } else if (o && !i) { if (d === o && !n.allowSingleDay) return; const h = d < o ? d : o, c = d < o ? o : d, w = a(h, c); if (w.length > 0) { const $ = S("blocked-dates-in-range", w); p.value = $, y("selection-error", $); const P = { checkIn: d, checkOut: null }; y("update:modelValue", P), y("selection-change", P), O.value = !0; return; } const m = { checkIn: h, checkOut: c }; y("update:modelValue", m), y("selection-change", m), O.value = !1; } }, N = (e) => { J(e) || (oe.value = e.dateString); }, ce = () => { if (!W.value) return; const e = new Date(b.value); e.setMonth(e.getMonth() - 1), b.value = e; }, ve = () => { if (!R.value) return; const e = new Date(b.value); e.setMonth(e.getMonth() + 1), b.value = e; }; return be(() => { if (n.modelValue.checkIn) { const e = new Date(n.modelValue.checkIn); b.value = new Date(e.getFullYear(), e.getMonth(), 1); } }), ie(() => n.modelValue, (e) => { e.checkIn && !e.checkOut ? O.value = !0 : O.value = !1; }, { deep: !0 }), ie(_, (e) => { y("price-calculation", e); }, { immediate: !0 }), (e, o) => { var i, d, h; return v(), k("div", { class: j(["hotel-booking-calendar", [ `theme-${e.theme}`, { "show-prices": e.showPrices }, { "has-selection-error": p.value } ]]) }, [ s("div", ye, [ s("button", { type: "button", class: "nav-button prev", onClick: ce, disabled: !W.value, "aria-label": C.value.previousMonth }, " ‹ ", 8, pe), s("div", we, [ s("h2", null, u(se(b.value)), 1) ]), s("button", { type: "button", class: "nav-button next", onClick: ve, disabled: !R.value, "aria-label": C.value.nextMonth }, " › ", 8, _e) ]), p.value && e.showSelectionErrors ? (v(), k("div", Se, [ o[0] || (o[0] = s("div", { class: "error-icon" }, "⚠️", -1)), s("div", Ce, [ s("div", Me, u(p.value.message), 1), (i = p.value.blockedDates) != null && i.length ? (v(), k("div", $e, " Blocked dates: " + u(le(p.value.blockedDates)), 1)) : A("", !0) ]), s("button", { onClick: D, class: "error-dismiss", "aria-label": C.value.dismissError }, "✕", 8, xe) ])) : A("", !0), s("div", Be, [ s("div", Ie, [ (v(!0), k(E, null, G(ee.value, (c) => (v(), k("div", { key: c, class: "weekday" }, u(c), 1))), 128)) ]), s("div", Pe, [ (v(!0), k(E, null, G(te.value, (c) => (v(), k("div", { key: c.dateString, class: j(["day-cell", { "other-month": !c.isCurrentMonth, today: c.isToday, selected: l(c.dateString), "in-range": t(c.dateString), "range-start": r(c.dateString), "range-end": g(c.dateString), available: F(c) === "available", blocked: F(c) === "blocked", "checkout-only": F(c) === "checkout-only", disabled: J(c), "click-disabled": Q(c), "error-blocked": re(c.dateString) }]), onClick: (w) => I(c), onMouseenter: (w) => N(c), role: "button", tabindex: Q(c) ? -1 : 0, "aria-label": f(c), onKeydown: [ he((w) => I(c), ["enter"]), he(me((w) => I(c), ["prevent"]), ["space"]) ] }, [ s("div", Ve, [ s("span", Ne, u(c.date.getDate()), 1), e.showPrices && q(c) ? (v(), k("div", Le, u(T(q(c))), 1)) : A("", !0) ]) ], 42, Oe))), 128)) ]) ]), e.showPriceCalculation && _.value ? (v(), k("div", Te, [ s("div", Fe, [ s("h4", null, u(C.value.bookingSummary), 1), s("button", { onClick: B, class: "clear-btn", "aria-label": C.value.clearSelection }, "✕", 8, Ee) ]), s("div", Re, [ s("div", He, [ s("span", Ge, u(_.value.nights) + " " + u(_.value.nights === 1 ? C.value.night : C.value.nights), 1), s("span", Ye, u((d = e.modelValue) != null && d.checkIn && ((h = e.modelValue) != null && h.checkOut) ? z(e.modelValue.checkIn, e.modelValue.checkOut) : ""), 1) ]), _.value.dailyPrices.length > 1 ? (v(), k("div", Ae, [ s("details", je, [ s("summary", null, [ De(u(C.value.priceBreakdown) + " ", 1), o[1] || (o[1] = s("span", { class: "arrow" }, "▼", -1)) ]), s("div", Ke, [ (v(!0), k(E, null, G(_.value.dailyPrices, (c) => (v(), k("div", { key: c.date, class: "daily-row" }, [ s("span", null, u(ne(c.date)), 1), s("span", null, u(T(c.price)), 1) ]))), 128)) ]) ]) ])) : A("", !0), s("div", Ue, [ s("div", We, [ s("span", null, u(_.value.nights) + " × " + u(T(_.value.averagePerNight)), 1), s("span", null, u(T(_.value.totalPrice)), 1) ]), s("div", ze, [ s("span", null, u(C.value.total), 1), s("strong", null, u(T(_.value.totalPrice)), 1) ]) ]), s("button", { onClick: V, class: "book-btn", disabled: !_.value }, u(C.value.bookNow), 9, qe) ]) ])) : A("", !0), (e.$slots.legend, v(), k("div", Je, [ fe(e.$slots, "legend", {}, () => [ s("div", Qe, [ o[2] || (o[2] = s("div", { class: "legend-indicator available" }, null, -1)), s("span", null, u(C.value.available), 1) ]), s("div", Xe, [ o[3] || (o[3] = s("div", { class: "legend-indicator checkout-only" }, null, -1)), s("span", null, u(C.value.checkoutOnly), 1) ]), s("div", Ze, [ o[4] || (o[4] = s("div", { class: "legend-indicator blocked" }, null, -1)), s("span", null, u(C.value.blocked), 1) ]) ], !0) ])) ], 2); }; } }), ke = (L, K) => { const n = L.__vccOpts || L; for (const [y, b] of K) n[y] = b; return n; }, tt = /* @__PURE__ */ ke(et, [["__scopeId", "data-v-fd5ea05e"]]), nt = { class: "dashboard-header" }, at = ["aria-label"], ot = { class: "current-month" }, st = ["aria-label"], lt = { class: "calendar-container" }, rt = { class: "calendar-grid" }, ct = { class: "grid-header" }, it = { class: "room-header" }, ut = { class: "date-number" }, dt = { class: "date-weekday" }, ht = { class: "room-name" }, gt = ["onClick", "title"], kt = { class: "span-content" }, vt = { class: "span-text" }, bt = ["onClick", "title"], mt = { key: 0, class: "booking-indicator" }, Dt = { class: "guest-initials" }, ft = { class: "legend" }, yt = /* @__PURE__ */ ge({ __name: "HotelDashboardCalendar", props: { rooms: {}, bookings: {}, selectedMonth: { default: () => /* @__PURE__ */ new Date() }, theme: { default: "light" }, statusConfig: {}, allowPreviousMonthNavigation: { type: Boolean, default: !1 }, textLabels: { default: () => ({}) } }, emits: ["update:selectedMonth", "booking-click", "booking-create"], setup(L, { emit: K }) { const n = L, y = K, b = Z(new Date(n.selectedMonth)), oe = [ { key: "available", label: "Available", color: "#666", backgroundColor: "#f9f9f9", darkBackgroundColor: "#2a2a2a" }, { key: "confirmed", label: "Confirmed", color: "#166534", backgroundColor: "#dcf8c6", darkBackgroundColor: "#1a4d14" }, { key: "pending", label: "Pending", color: "#92400e", backgroundColor: "#fef3c7", darkBackgroundColor: "#4a3c00" }, { key: "checked-in", label: "Checked In", color: "#1e40af", backgroundColor: "#dbeafe", darkBackgroundColor: "#1e3a8a" }, { key: "checked-out", label: "Checked Out", color: "#7c3aed", backgroundColor: "#f3e8ff", darkBackgroundColor: "#5b21b6" }, { key: "cancelled", label: "Cancelled", color: "#dc2626", backgroundColor: "#fee2e2", darkBackgroundColor: "#7f1d1d" } ], O = M( () => n.statusConfig || oe ), p = M(() => { var a, l, t, r, g, f; return { previousMonth: ((a = n.textLabels) == null ? void 0 : a.previousMonth) || "← Previous", nextMonth: ((l = n.textLabels) == null ? void 0 : l.nextMonth) || "Next →", room: ((t = n.textLabels) == null ? void 0 : t.room) || "Room", available: ((r = n.textLabels) == null ? void 0 : r.available) || "Available", createBooking: ((g = n.textLabels) == null ? void 0 : g.createBooking) || "Click to create booking", clickForDetails: ((f = n.textLabels) == null ? void 0 : f.clickForDetails) || "Click for details" }; }), x = M(() => { const a = b.value.getFullYear(), l = b.value.getMonth(), t = new Date(a, l + 1, 0).getDate(), r = /* @__PURE__ */ new Date(); r.setHours(0, 0, 0, 0); const g = []; for (let f = 1; f <= t; f++) { const D = new Date(a, l, f), S = `${a}-${String(l + 1).padStart(2, "0")}-${String(f).padStart(2, "0")}`; g.push({ day: f, dateString: S, date: D, isToday: D.getTime() === r.getTime(), isWeekend: D.getDay() === 0 || D.getDay() === 6, weekday: new Intl.DateTimeFormat("en-US", { weekday: "short" }).format(D) }); } return g; }), Y = M(() => { const a = {}; return n.rooms.forEach((l) => { a[l.id] = [], n.bookings.filter( (r) => r.roomNumber === l.number ).forEach((r) => { const g = new Date(r.checkIn), f = new Date(r.checkOut), D = b.value.getFullYear(), S = b.value.getMonth(), B = new Date(D, S, 1), V = new Date(D, S + 1, 0); if (g <= V && f > B) { let I, N; if (g >= B ? I = g.getDate() : I = 1, f <= V ? N = f.getDate() - 1 : N = V.getDate(), N = Math.max(I, N), I >= 1 && N <= V.getDate() && I <= N) { const ce = _(r.status); a[l.id].push({ booking: r, startDay: I, endDay: N, length: N - I + 1, statusConfig: ce }); } } }), a[l.id].sort((r, g) => r.startDay - g.startDay); }), a; }), U = (a) => new Intl.DateTimeFormat("en-US", { year: "numeric", month: "long" }).format(a), ee = (a) => { if (a < 0 && !n.allowPreviousMonthNavigation) { const t = /* @__PURE__ */ new Date(), r = new Date(b.value.getFullYear(), b.value.getMonth(), 1), g = new Date(t.getFullYear(), t.getMonth(), 1); if (r <= g) return; } const l = new Date(b.value); l.setMonth(l.getMonth() + a), b.value = l, y("update:selectedMonth", l); }, te = (a, l) => n.bookings.some( (t) => t.roomNumber === a.number && W(l, t) ), W = (a, l) => { const t = new Date(a), r = new Date(l.checkIn), g = new Date(l.checkOut); return t >= r && t < g; }, R = (a, l) => n.bookings.find( (t) => t.roomNumber === a.number && W(l, t) ) || null, C = (a, l) => { const t = R(a, l); return t ? t.status : "available"; }, _ = (a) => O.value.find((l) => l.key === a) || O.value[0], H = (a, l) => { const t = [], r = x.value.find((g) => g.dateString === l); return r != null && r.isToday && t.push("is-today"), r != null && r.isWeekend && t.push("is-weekend"), te(a, l) && t.push("has-booking"), t; }, se = (a, l) => { const t = C(a, l), r = _(t); return { backgroundColor: n.theme === "dark" && r.darkBackgroundColor ? r.darkBackgroundColor : r.backgroundColor, color: r.color }; }, T = (a, l) => { const t = R(a, l); return t ? t.guestName.split(" ").map((r) => r.charAt(0).toUpperCase()).join("").substring(0, 2) : ""; }, z = (a, l) => { const t = new Date(a), g = new Date(l).getTime() - t.getTime(); return Math.ceil(g / (1e3 * 60 * 60 * 24)); }, ne = (a, l) => { const t = R(a, l); if (!t) return `${p.value.room} ${a.number} - ${p.value.available} (${p.value.createBooking})`; const r = _(t.status), g = z(t.checkIn, t.checkOut); return `${t.guestName} - ${p.value.room} ${a.number} - ${r.label} - ${g} nights (${p.value.clickForDetails})`; }, le = (a, l) => { const t = R(a, l); t ? y("booking-click", t) : y("booking-create", { roomId: a.id, date: l }); }, q = (a) => { var f; const l = [], t = Y.value[a.id] || [], r = /* @__PURE__ */ new Set(), g = [...t].sort((D, S) => D.startDay - S.startDay); for (let D = 1; D <= x.value.length; D++) { if (r.has(D)) continue; const S = g.find((B) => B.startDay === D); if (S) { const B = ((f = x.value[D - 1]) == null ? void 0 : f.dateString) || ""; l.push({ type: "booking-span", booking: S.booking, startDay: S.startDay, endDay: S.endDay, length: S.length, statusConfig: S.statusConfig, startDate: B }); for (let V = S.startDay; V <= S.endDay; V++) r.add(V); } else { const B = x.value[D - 1]; B && l.push({ type: "date-cell", dateString: B.dateString, day: D }); } } return l; }, J = (a) => ({ backgroundColor: n.theme === "dark" && a.statusConfig.darkBackgroundColor ? a.statusConfig.darkBackgroundColor : a.statusConfig.backgroundColor, color: a.statusConfig.color, border: `1px solid ${a.statusConfig.color}`, borderRadius: "4px", gridColumnStart: (a.startDay + 1).toString(), // +1 because room column is first gridColumnEnd: (a.endDay + 2).toString() // +2 because grid-end is exclusive and room column is first }), Q = (a) => { const l = z(a.booking.checkIn, a.booking.checkOut), t = a.booking.guestName; return a.length === 1 ? t.split(" ").map((r) => r.charAt(0)).join("").substring(0, 2) : a.length <= 3 ? t.split(" ")[0] : a.length <= 6 ? `${t.split(" ")[0]} (${l}n)` : `${t} - ${l} nights`; }, F = (a) => { const l = z(a.booking.checkIn, a.booking.checkOut), t = n.rooms.find((r) => r.number === a.booking.roomNumber); return `${a.booking.guestName} - Room ${t == null ? void 0 : t.number} - ${a.statusConfig.label} - ${l} nights`; }, re = (a) => { y("booking-click", a); }; return ie(() => n.selectedMonth, (a) => { a && (b.value = new Date(a)); }), (a, l) => (v(), k("div", { class: j(["hotel-dashboard-calendar", `theme-${a.theme}`]), style: ae({ "--days-in-month": x.value.length }) }, [ s("div", nt, [ s("button", { onClick: l[0] || (l[0] = (t) => ee(-1)), class: "nav-btn", "aria-label": p.value.previousMonth }, u(p.value.previousMonth), 9, at), s("h2", ot, u(U(b.value)), 1), s("button", { onClick: l[1] || (l[1] = (t) => ee(1)), class: "nav-btn", "aria-label": p.value.nextMonth }, u(p.value.nextMonth), 9, st) ]), s("div", lt, [ s("div", rt, [ s("div", ct, [ s("div", it, u(p.value.room), 1), (v(!0), k(E, null, G(x.value, (t) => (v(), k("div", { key: t.dateString, class: j(["date-header", { "is-today": t.isToday, "is-weekend": t.isWeekend }]) }, [ s("div", ut, u(t.day), 1), s("div", dt, u(t.weekday), 1) ], 2))), 128)) ]), (v(!0), k(E, null, G(n.rooms, (t) => (v(), k("div", { key: t.id, class: "room-row" }, [ s("div", ht, u(t.number), 1), (v(!0), k(E, null, G(q(t), (r, g) => (v(), k(E, { key: `${t.id}-${g}` }, [ r.type === "booking-span" ? (v(), k("div", { key: 0, class: j(["booking-span-cell", H(t, r.startDate)]), style: ae(J(r)), onClick: (f) => re(r.booking), title: F(r) }, [ s("div", kt, [ s("span", vt, u(Q(r)), 1) ]) ], 14, gt)) : (v(), k("div", { key: 1, class: j(["date-cell", H(t, r.dateString)]), style: ae(se(t, r.dateString)), onClick: (f) => le(t, r.dateString), title: ne(t, r.dateString) }, [ te(t, r.dateString) ? (v(), k("div", mt, [ s("span", Dt, u(T(t, r.dateString)), 1) ])) : A("", !0) ], 14, bt)) ], 64))), 128)) ]))), 128)) ]) ]), s("div", ft, [ (v(!0), k(E, null, G(O.value, (t) => (v(), k("div", { key: t.key, class: "legend-item" }, [ s("div", { class: "legend-color", style: ae({ backgroundColor: t.backgroundColor, borderColor: t.color }) }, null, 4), s("span", null, u(t.label), 1) ]))), 128)) ]) ], 6)); } }), pt = /* @__PURE__ */ ke(yt, [["__scopeId", "data-v-f67bbf1d"]]), _t = { install(L) { L.component("HotelBookingCalendar", tt), L.component("HotelDashboardCalendar", pt); } }; export { tt as HotelBookingCalendar, pt as HotelDashboardCalendar, _t as default };