hotel-ai-widget
Version:
A customizable hotel chat widget for React and vanilla HTML
56 lines (55 loc) • 7.74 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { Car, ChevronDown, Clock, CreditCard, Hotel, MapPin, } from "lucide-react";
import { useEffect, useState } from "react";
export const ItinerarySection = ({ isStreaming, itinerary, className = "", }) => {
const [expandedDays, setExpandedDays] = useState([]);
// Always run hooks before any early returns
useEffect(() => {
if (itinerary &&
itinerary.data &&
Array.isArray(itinerary.data.itinerarySummary)) {
const itineraryData = itinerary.data.itinerarySummary.find((item) => item["view-type"] === "itinerary");
if (itineraryData &&
itineraryData.itinerary &&
Array.isArray(itineraryData.itinerary.days) &&
itineraryData.itinerary.days.length > 0) {
setExpandedDays(itineraryData.itinerary.days.map((_, index) => index));
}
}
}, [itinerary]);
return (_jsx("div", { className: `flex-1 flex flex-col overflow-hidden ${className}`, children: isStreaming ? (_jsx("div", { className: "flex-1 flex items-center justify-center", children: _jsx("div", { className: "animate-spin rounded-full h-6 w-6 border-t-2 border-blue-500" }) })) : !itinerary ? (_jsx("div", { className: "flex-1 flex items-center justify-center", children: _jsxs("div", { className: "text-center py-8", children: [_jsx(Hotel, { className: "w-8 h-8 text-gray-300 mx-auto mb-2" }), _jsx("p", { className: "text-gray-500 text-xs", children: "No itinerary available" }), _jsx("p", { className: "text-xs text-gray-400 mt-1", children: "Ask me to create one for you!" })] }) })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "bg-white px-3 py-2 border-b flex-shrink-0 border-gray-300", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h1", { className: "text-sm font-bold", children: "Itinerary" }), _jsxs("span", { className: "text-xs text-gray-500 bg-gray-100 px-2 py-1 rounded-full", children: [itinerary.data.itinerarySummary.find((item) => item["view-type"] === "itinerary")?.itinerary.days.length || 0, " ", "days"] })] }) }), _jsx("div", { className: "flex-1 px-3 py-2 overflow-y-auto", children: _jsx("div", { className: "space-y-3", children: itinerary.data.itinerarySummary
.find((item) => item["view-type"] === "itinerary")
?.itinerary.days.map((day, dayIndex) => (_jsxs("div", { className: "border border-gray-200 rounded-lg overflow-hidden", children: [_jsxs("button", { onClick: () => {
setExpandedDays((prev) => prev.includes(dayIndex)
? prev.filter((index) => index !== dayIndex)
: [...prev, dayIndex]);
}, className: "flex items-center justify-between w-full p-2 bg-gray-50 hover:bg-gray-100 transition-colors", children: [_jsxs("div", { className: "text-left", children: [_jsxs("h2", { className: "text-xs font-semibold text-gray-900", children: ["Day ", day.day] }), day.date && (_jsx("p", { className: "text-xs text-gray-500", children: new Date(day.date).toLocaleDateString("en-US", {
day: "numeric",
month: "short",
}) }))] }), _jsx(ChevronDown, { className: `w-3 h-3 text-gray-500 transition-transform duration-200 ${expandedDays.includes(dayIndex)
? "rotate-0"
: "-rotate-90"}` })] }), _jsx("div", { className: `transition-all duration-300 ease-in-out ${expandedDays.includes(dayIndex)
? "max-h-96 opacity-100"
: "max-h-0 opacity-0"} overflow-hidden`, children: day.inclusions?.length > 0 && (_jsx("div", { className: "p-2 space-y-2 bg-white", children: day.inclusions
.filter((inclusion) => inclusion.type === "attraction" ||
inclusion.type === "transport")
.map((inclusion, idx) => {
const hasMetadata = inclusion.metadata &&
inclusion.metadata.length > 0;
if (!hasMetadata)
return null;
return (_jsx("div", { className: "border border-gray-100 rounded-lg p-2 hover:border-gray-200 transition-colors", children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsx("div", { className: "w-5 h-5 rounded-md bg-gray-100 flex items-center justify-center flex-shrink-0 mt-0.5", children: inclusion.type === "attraction" ? (_jsx(MapPin, { className: "w-2.5 h-2.5 text-gray-500" })) : (_jsx(Car, { className: "w-2.5 h-2.5 text-gray-500" })) }), _jsxs("div", { className: "flex-1 min-w-0", children: [inclusion.type === "attraction" &&
inclusion.metadata[0]?.name && (_jsx("h3", { className: "font-medium text-gray-900 text-xs mb-1 line-clamp-1", children: inclusion.metadata[0].name })), inclusion.type === "transport" && (_jsx("h3", { className: "font-medium text-gray-900 text-xs mb-1", children: inclusion.metadata[0]?.["transport-type"] ||
inclusion["transport-type"] ||
"Transport" })), _jsxs("div", { className: "flex flex-wrap items-center gap-2 mb-1", children: [inclusion.time && (_jsxs("div", { className: "flex items-center gap-1 text-xs text-gray-600", children: [_jsx(Clock, { className: "w-2.5 h-2.5" }), _jsx("span", { children: inclusion.time })] })), (inclusion.metadata[0]?.payment ||
(inclusion.type === "transport" &&
inclusion.payment)) && (_jsxs("div", { className: "flex items-center gap-1 text-xs text-gray-600", children: [_jsx(CreditCard, { className: "w-2.5 h-2.5" }), _jsx("span", { children: inclusion.type === "transport"
? inclusion.payment ||
inclusion.metadata[0]?.payment
: inclusion.metadata[0]
?.payment })] }))] }), inclusion.type === "attraction" &&
inclusion.metadata[0]?.description && (_jsx("p", { className: "text-xs text-gray-600 line-clamp-2 mb-1", children: inclusion.metadata[0].description })), _jsx("span", { className: `inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium capitalize ${inclusion.type === "attraction"
? "bg-blue-100 text-blue-700"
: "bg-green-100 text-green-700"}`, children: inclusion.type })] })] }) }, idx));
}) })) })] }, dayIndex))) }) })] })) }));
};