import "./index.css"; import { v4 as uuidv4 } from "uuid"; import { useStreamContext, type UIMessage, } from "@langchain/langgraph-sdk/react-ui"; import { useEffect, useState } from "react"; import { X } from "lucide-react"; import { Button } from "@/components/ui/button"; import { TripDetails } from "../../../trip-planner/types"; import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, } from "@/components/ui/carousel"; import { format } from "date-fns"; import { Accommodation } from "agent/types"; import { capitalizeSentence } from "../../../utils/capitalize"; import { Message } from "@langchain/langgraph-sdk"; import { getToolResponse } from "../../utils/get-tool-response"; import { DO_NOT_RENDER_ID_PREFIX } from "@/lib/ensure-tool-responses"; const StarSVG = ({ fill = "white" }: { fill?: string }) => ( ); function AccommodationCard({ accommodation, }: { accommodation: Accommodation; }) { return (

{accommodation.name}

{accommodation.rating}

ยท

{accommodation.price}

{capitalizeSentence(accommodation.city)}

); } function SelectedAccommodation({ accommodation, onHide, tripDetails, onBook, }: { accommodation: Accommodation; onHide: () => void; tripDetails: TripDetails; onBook: (accommodation: Accommodation) => void; }) { const startDate = new Date(tripDetails.startDate); const endDate = new Date(tripDetails.endDate); const totalTripDurationDays = Math.max( startDate.getDate() - endDate.getDate(), 1, ); const totalPrice = totalTripDurationDays * accommodation.price; return (
{accommodation.name}

{accommodation.name}

{accommodation.rating}

{capitalizeSentence(accommodation.city)}

Check-in {format(startDate, "MMM d, yyyy")}
Check-out {format(endDate, "MMM d, yyyy")}
Guests {tripDetails.numberOfGuests}
Total Price ${totalPrice.toLocaleString()}
); } function BookedAccommodation({ accommodation, tripDetails, }: { accommodation: Accommodation; tripDetails: TripDetails; }) { const startDate = new Date(tripDetails.startDate); const endDate = new Date(tripDetails.endDate); const totalTripDurationDays = Math.max( startDate.getDate() - endDate.getDate(), 1, ); const totalPrice = totalTripDurationDays * accommodation.price; return (

Booked Accommodation

Address:
{accommodation.name}, {capitalizeSentence(accommodation.city)}
Rating:
{accommodation.rating}
Dates:
{format(startDate, "MMM d, yyyy")} -{" "} {format(endDate, "MMM d, yyyy")}
Guests:
{tripDetails.numberOfGuests}
Total Price:
${totalPrice.toLocaleString()}
); } export default function AccommodationsList({ toolCallId, tripDetails, accommodations, }: { toolCallId: string; tripDetails: TripDetails; accommodations: Accommodation[]; }) { const thread = useStreamContext< { messages: Message[]; ui: UIMessage[] }, { MetaType: { ui: UIMessage | undefined } } >(); const [selectedAccommodation, setSelectedAccommodation] = useState< Accommodation | undefined >(); const [accommodationBooked, setAccommodationBooked] = useState(false); useEffect(() => { if (typeof window === "undefined" || accommodationBooked) return; const toolResponse = getToolResponse(toolCallId, thread); if (toolResponse) { setAccommodationBooked(true); try { const parsedContent: { accommodation: Accommodation; tripDetails: TripDetails; } = JSON.parse(toolResponse.content as string); setSelectedAccommodation(parsedContent.accommodation); } catch { console.error("Failed to parse tool response content."); } } }, []); function handleBookAccommodation(accommodation: Accommodation) { const orderDetails = { accommodation, tripDetails, }; thread.submit({ messages: [ { type: "tool", tool_call_id: toolCallId, id: `${DO_NOT_RENDER_ID_PREFIX}${uuidv4()}`, name: "book-accommodation", content: JSON.stringify(orderDetails), }, { type: "human", content: `Booked ${accommodation.name} for ${tripDetails.numberOfGuests}.`, }, ], }); setAccommodationBooked(true); if (selectedAccommodation?.id !== accommodation.id) { setSelectedAccommodation(accommodation); } } if (accommodationBooked && selectedAccommodation) { return ( ); } else if (accommodationBooked) { return
Successfully booked accommodation!
; } if (selectedAccommodation) { return ( setSelectedAccommodation(undefined)} accommodation={selectedAccommodation} onBook={handleBookAccommodation} /> ); } return (
{accommodations.map((accommodation) => ( setSelectedAccommodation(accommodation)} > ))}
); }