import { FolkShape } from "./folk-shape"; import { css, html } from "./tags"; const styles = css` :host { background: white; border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); min-width: 280px; min-height: 160px; } .header { display: flex; align-items: center; justify-content: space-between; padding: 8px 12px; color: white; border-radius: 8px 8px 0 0; font-size: 12px; font-weight: 600; cursor: move; } .header.FLIGHT { background: #2563eb; } .header.HOTEL { background: #7c3aed; } .header.CAR_RENTAL { background: #d97706; } .header.TRAIN { background: #059669; } .header.BUS { background: #0891b2; } .header.FERRY { background: #0284c7; } .header.ACTIVITY { background: #0d9488; } .header.RESTAURANT { background: #ea580c; } .header.OTHER { background: #475569; } .header-title { display: flex; align-items: center; gap: 6px; } .header-actions button { background: transparent; border: none; color: white; cursor: pointer; padding: 2px 6px; border-radius: 4px; font-size: 14px; } .header-actions button:hover { background: rgba(255, 255, 255, 0.2); } .booking-body { padding: 12px; } .provider { font-size: 16px; font-weight: 700; color: #1e293b; margin-bottom: 4px; } .details { font-size: 12px; color: #475569; line-height: 1.5; margin-bottom: 8px; } .meta-row { display: flex; gap: 12px; font-size: 11px; margin-bottom: 4px; } .meta-item { display: flex; align-items: center; gap: 4px; } .meta-label { color: #94a3b8; } .meta-value { color: #1e293b; font-weight: 500; } .confirmation { margin-top: 8px; padding: 6px 8px; background: #f1f5f9; border-radius: 4px; font-size: 11px; display: flex; justify-content: space-between; } .confirmation .label { color: #94a3b8; } .confirmation .code { font-family: monospace; font-weight: 600; color: #1e293b; } .cost { font-size: 18px; font-weight: 700; color: #1e293b; margin-top: 8px; } .status-badge { display: inline-block; font-size: 10px; font-weight: 600; padding: 2px 8px; border-radius: 10px; margin-top: 8px; } .status-badge.PLANNED { background: #e2e8f0; color: #475569; } .status-badge.BOOKED { background: #dbeafe; color: #1d4ed8; } .status-badge.CONFIRMED { background: #dcfce7; color: #15803d; } .status-badge.CANCELLED { background: #fee2e2; color: #dc2626; } `; const BOOKING_TYPE_ICONS: Record = { FLIGHT: "\u2708\uFE0F", HOTEL: "\uD83C\uDFE8", CAR_RENTAL: "\uD83D\uDE97", TRAIN: "\uD83D\uDE84", BUS: "\uD83D\uDE8C", FERRY: "\u26F4\uFE0F", ACTIVITY: "\uD83C\uDFAF", RESTAURANT: "\uD83C\uDF7D\uFE0F", OTHER: "\uD83D\uDCCC", }; declare global { interface HTMLElementTagNameMap { "folk-booking": FolkBooking; } } export class FolkBooking extends FolkShape { static override tagName = "folk-booking"; static { const sheet = new CSSStyleSheet(); const parentRules = Array.from(FolkShape.styles.cssRules) .map((r) => r.cssText) .join("\n"); const childRules = Array.from(styles.cssRules) .map((r) => r.cssText) .join("\n"); sheet.replaceSync(`${parentRules}\n${childRules}`); this.styles = sheet; } #bookingType = "OTHER"; #provider = ""; #confirmationNumber = ""; #details = ""; #cost: number | null = null; #currency = "USD"; #startDate = ""; #endDate = ""; #bookingStatus = "PLANNED"; #headerEl: HTMLElement | null = null; #bodyEl: HTMLElement | null = null; get bookingType() { return this.#bookingType; } set bookingType(v: string) { this.#bookingType = v; this.#render(); this.dispatchEvent(new CustomEvent("content-change")); } get provider() { return this.#provider; } set provider(v: string) { this.#provider = v; this.#render(); this.dispatchEvent(new CustomEvent("content-change")); } get confirmationNumber() { return this.#confirmationNumber; } set confirmationNumber(v: string) { this.#confirmationNumber = v; this.#render(); this.dispatchEvent(new CustomEvent("content-change")); } get details() { return this.#details; } set details(v: string) { this.#details = v; this.#render(); this.dispatchEvent(new CustomEvent("content-change")); } get cost() { return this.#cost; } set cost(v: number | null) { this.#cost = v; this.#render(); this.dispatchEvent(new CustomEvent("content-change")); } get currency() { return this.#currency; } set currency(v: string) { this.#currency = v; this.#render(); } get startDate() { return this.#startDate; } set startDate(v: string) { this.#startDate = v; this.#render(); } get endDate() { return this.#endDate; } set endDate(v: string) { this.#endDate = v; this.#render(); } get bookingStatus() { return this.#bookingStatus; } set bookingStatus(v: string) { this.#bookingStatus = v; this.#render(); this.dispatchEvent(new CustomEvent("content-change")); } override createRenderRoot() { const root = super.createRenderRoot(); const wrapper = document.createElement("div"); wrapper.innerHTML = html`
\uD83D\uDCCC Booking
`; const slot = root.querySelector("slot"); const containerDiv = slot?.parentElement as HTMLElement; if (containerDiv) { containerDiv.replaceWith(wrapper); } this.#headerEl = wrapper.querySelector(".header"); this.#bodyEl = wrapper.querySelector(".booking-body"); const closeBtn = wrapper.querySelector(".close-btn") as HTMLButtonElement; closeBtn.addEventListener("click", (e) => { e.stopPropagation(); this.dispatchEvent(new CustomEvent("close")); }); this.#render(); return root; } #escapeHtml(text: string): string { const div = document.createElement("div"); div.textContent = text; return div.innerHTML; } #formatDate(dateStr: string): string { if (!dateStr) return ""; const d = new Date(dateStr); return d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }); } #render() { if (!this.#headerEl || !this.#bodyEl) return; const icon = BOOKING_TYPE_ICONS[this.#bookingType] || BOOKING_TYPE_ICONS.OTHER; // Update header this.#headerEl.className = `header ${this.#bookingType}`; const iconEl = this.#headerEl.querySelector(".type-icon"); const labelEl = this.#headerEl.querySelector(".type-label"); if (iconEl) iconEl.textContent = icon; if (labelEl) labelEl.textContent = this.#bookingType.replace("_", " "); // Build body let bodyHTML = ""; if (this.#provider) { bodyHTML += `
${this.#escapeHtml(this.#provider)}
`; } if (this.#details) { bodyHTML += `
${this.#escapeHtml(this.#details)}
`; } if (this.#startDate || this.#endDate) { bodyHTML += `
`; if (this.#startDate) { bodyHTML += `
From:${this.#formatDate(this.#startDate)}
`; } if (this.#endDate) { bodyHTML += `
To:${this.#formatDate(this.#endDate)}
`; } bodyHTML += `
`; } if (this.#confirmationNumber) { bodyHTML += `
Confirmation${this.#escapeHtml(this.#confirmationNumber)}
`; } if (this.#cost !== null) { bodyHTML += `
${this.#currency} ${this.#cost.toLocaleString()}
`; } bodyHTML += `${this.#bookingStatus}`; this.#bodyEl.innerHTML = bodyHTML; } override toJSON() { return { ...super.toJSON(), type: "folk-booking", bookingType: this.#bookingType, provider: this.#provider, confirmationNumber: this.#confirmationNumber, details: this.#details, cost: this.#cost, currency: this.#currency, startDate: this.#startDate, endDate: this.#endDate, bookingStatus: this.#bookingStatus, }; } }