From afa501c838961c21ccc70b6a7206c3e18cf25cf1 Mon Sep 17 00:00:00 2001 From: TopherMayor Date: Fri, 1 May 2026 11:20:26 -0700 Subject: [PATCH] Show trip dates on option cards --- public/index.html | 29 ++++++++++++++++++++++++++++- server.js | 2 ++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/public/index.html b/public/index.html index 2342a03..477365a 100644 --- a/public/index.html +++ b/public/index.html @@ -1678,6 +1678,8 @@ budgetScenarios: [], priceUpdatedAt: '', priceHistoryRunCount: 0, + tripCheckIn: '', + tripCheckOut: '', sortMode: localStorage.getItem('cabo_sort_mode') || 'vote-desc', budgetGuestCount: Number(localStorage.getItem('cabo_budget_guest_count') || 0), priceSourceSelections: (() => { @@ -1894,6 +1896,8 @@ const msg = JSON.parse(event.data); if (msg.type === 'init') { state.categories = msg.categories; + state.tripCheckIn = msg.tripCheckIn || ''; + state.tripCheckOut = msg.tripCheckOut || ''; state.guestRoster = msg.guestRoster || []; state.options = msg.options; state.budgetScenarios = msg.budgetScenarios || []; @@ -2021,6 +2025,21 @@ return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }); } + function formatTripDate(value) { + if (!value) return ''; + const date = new Date(`${value}T00:00:00Z`); + if (Number.isNaN(date.getTime())) return ''; + return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' }); + } + + function formatTripDateRange(checkIn, checkOut) { + const start = formatTripDate(checkIn); + const end = formatTripDate(checkOut); + if (!start && !end) return ''; + if (start && end) return `${start} to ${end}`; + return start || end; + } + function formatBookingType(bookingType, priceBasis) { const typeLabels = { package: 'Package', @@ -2340,10 +2359,11 @@ function getPointContext(point) { if (!point) return ''; + const tripDates = formatTripDateRange(point.tripCheckIn, point.tripCheckOut); const unitContext = point.tripNights && point.unitPrice ? `${formatCurrency(point.unitPrice, point.currency || 'USD')} x ${point.tripNights} nights` : ''; - return [unitContext, point.unitDisplayPrice || point.displayPrice || point.decisionNote || ''] + return [tripDates ? `Dates: ${tripDates}` : '', unitContext, point.unitDisplayPrice || point.displayPrice || point.decisionNote || ''] .filter(Boolean) .join(' ยท '); } @@ -2386,6 +2406,9 @@ const selectedSeries = getOptionSourceSeries(opt, selectedSourceKey, tabId); const selectedMeta = getOptionSourceMeta(opt, selectedSourceKey, tabId); const selectedPoint = selectedSeries.at(-1) || ((tabId === BUNDLE_TAB_ID || !isStandaloneComponentTab(tabId)) ? opt.latestPricePoint : null); + const tripCheckIn = selectedPoint?.tripCheckIn || opt.latestPricePoint?.tripCheckIn || state.tripCheckIn || ''; + const tripCheckOut = selectedPoint?.tripCheckOut || opt.latestPricePoint?.tripCheckOut || state.tripCheckOut || ''; + const tripDates = formatTripDateRange(tripCheckIn, tripCheckOut); const insights = selectedPoint ? { source: selectedMeta?.sourceLabel || selectedPoint.source || 'Automation feed', sourceUrl: selectedMeta?.sourceUrl || selectedPoint.sourceUrl || null, @@ -2456,6 +2479,10 @@ Status
${escapeHtml(statusLabel)}
+
+ Dates +
${escapeHtml(tripDates || 'Not specified')}
+
`); diff --git a/server.js b/server.js index 4a70069..23290de 100644 --- a/server.js +++ b/server.js @@ -691,6 +691,8 @@ function buildRealtimeSnapshot() { type: 'init', pollsOpen: data.pollsOpen, categories: data.categories, + tripCheckIn: TRIP_CHECK_IN, + tripCheckOut: TRIP_CHECK_OUT, guestRoster: getGuestRoster().map((guest) => ({ name: guest.name, role: guest.role || 'guest',