'use client'; import { useState } from "react"; import Section from "@/components/Section"; import DealCard from "@/components/DealCard"; type Result = { results: any[] }; export default function Page() { const [activeTab, setActiveTab] = useState<'flights' | 'resorts'>('flights'); const [origin, setOrigin] = useState("YOW"); const [dest, setDest] = useState("CUN,PUJ,MBJ"); const [startDate, setStartDate] = useState(new Date().toISOString().slice(0,10)); const [endDate, setEndDate] = useState(new Date(Date.now() + 1000*60*60*24*60).toISOString().slice(0,10)); const [minN, setMinN] = useState(5); const [maxN, setMaxN] = useState(9); const [budget, setBudget] = useState(''); const [nonStop, setNonStop] = useState(false); const [loading, setLoading] = useState(false); const [results, setResults] = useState([]); const [useDeals, setUseDeals] = useState(true); const [useSky, setUseSky] = useState(true); const [useG, setUseG] = useState(true); const [useAC, setUseAC] = useState(true); const [useAT, setUseAT] = useState(true); // Resort comparison state const [resortLoading, setResortLoading] = useState(false); const [resortResults, setResortResults] = useState([]); const [selectedResorts, setSelectedResorts] = useState([]); const [resortOrigin, setResortOrigin] = useState("YOW"); const [resortDate, setResortDate] = useState(new Date().toISOString().slice(0,10)); const [resortNights, setResortNights] = useState(7); const [resortBudget, setResortBudget] = useState(5500); const [prefs, setPrefs] = useState({ beach: 8, pool: 8, golf: 5, spa: 7, food: 9, nightlife: 6, shopping: 4, culture: 5, outdoor: 6, family: 5 }); async function onSubmit(e: React.FormEvent) { e.preventDefault(); setLoading(true); setResults([]); const payload = { origin: origin.trim().toUpperCase(), destinations: dest.split(',').map(s => s.trim().toUpperCase()).filter(Boolean), startDate, endDate, tripLengthMin: Number(minN), tripLengthMax: Number(maxN), budget: budget === '' ? null : Number(budget), currency: "CAD", nonStopOnly: nonStop, sources: [ useDeals ? "Deals" : "", useSky ? "Skyscanner" : "", useG ? "GoogleFlights" : "", useAC ? "AirCanada" : "", useAT ? "AirTransat" : "" ].filter(Boolean) }; const res = await fetch("/api/search", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(payload) }); const data: Result = await res.json(); // Sort by destination, then by source/provider const sorted = (data.results || []).sort((a: any, b: any) => { // First sort by destination const destCompare = (a.destination || '').localeCompare(b.destination || ''); if (destCompare !== 0) return destCompare; // Then by source/provider return (a.source || '').localeCompare(b.source || ''); }); setResults(sorted); setLoading(false); } const availableResorts = [ "Dreams Onyx Resort & Spa", "Excellence Riviera Cancun", "Secrets Maroma Beach", "Hyatt Ziva Cancun", "Moon Palace Cancun", "Barcelo Maya Riviera", "Grand Sirenis Riviera Maya", "Iberostar Selection Paraiso Maya", "Hotel Xcaret Mexico", "Dreams Punta Cana", "Excellence Punta Cana", "Secrets Cap Cana", "Hyatt Ziva Cap Cana", "Iberostar Grand Bavaro" ]; async function onResortCompare(e: React.FormEvent) { e.preventDefault(); if (selectedResorts.length === 0) { alert("Please select at least one resort"); return; } setResortLoading(true); setResortResults([]); const payload = { resorts: selectedResorts, departureDate: resortDate, origin: resortOrigin, tripLength: resortNights, budget: resortBudget === '' ? null : Number(resortBudget), contingencyPercent: 15, preferences: prefs }; const res = await fetch("/api/resort-compare", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(payload) }); const data = await res.json(); setResortResults(data.comparisons || data.allComparisons || []); setResortLoading(false); } function toggleResort(resort: string) { setSelectedResorts(prev => prev.includes(resort) ? prev.filter(r => r !== resort) : [...prev, resort] ); } return (
{/* Tab Switcher */}
{/* Flight Search Tab */} {activeTab === 'flights' && ( <>
setOrigin(e.target.value.toUpperCase())} maxLength={4} placeholder="YOW" />
setDest(e.target.value)} placeholder="CUN,PUJ,MBJ" />
setStartDate(e.target.value)} />
setEndDate(e.target.value)} />
setMinN(Number(e.target.value))} min={1} />
setMaxN(Number(e.target.value))} min={minN} />
setBudget(e.target.value === '' ? '' : Number(e.target.value))} />
{!loading && results.length === 0 && (
No results yet. Fill the form and hit search.
)} {results.length > 0 && (() => { // Group by destination const grouped: Record = {}; results.forEach((r: any) => { const dest = r.destination || 'Unknown'; if (!grouped[dest]) grouped[dest] = []; grouped[dest].push(r); }); return Object.keys(grouped).sort().map(destination => (

{destination}

{(() => { // Group by source/provider within this destination const bySource: Record = {}; grouped[destination].forEach((r: any) => { const src = r.source || 'Other'; if (!bySource[src]) bySource[src] = []; bySource[src].push(r); }); return Object.keys(bySource).sort().map(source => (

{source}

{bySource[source].map((r: any) => )}
)); })()}
)); })()}
)} {/* Resort Comparison Tab */} {activeTab === 'resorts' && ( <>
{/* Basic Settings */}
setResortOrigin(e.target.value.toUpperCase())} maxLength={4} placeholder="YOW" />
setResortDate(e.target.value)} />
setResortNights(Number(e.target.value))} min={1} />
setResortBudget(e.target.value === '' ? '' : Number(e.target.value))} placeholder="5500" />
{/* Preference Sliders */}
{Object.keys(prefs).map(key => (
setPrefs({...prefs, [key]: Number(e.target.value)})} className="w-full" />
{prefs[key as keyof typeof prefs]}
))}
{/* Resort Selection */}
{availableResorts.map(resort => ( ))}
{!resortLoading && resortResults.length === 0 && (
No results yet. Select resorts and hit compare.
)} {resortResults.length > 0 && (
{resortResults.map((comp: any) => (

{comp.resort.name}

{comp.resort.destination}, {comp.resort.country} ({comp.resort.airportCode})

{comp.matchScore}
Match Score
TripAdvisor
{comp.resort.tripAdvisorRating}/5.0 ⭐ ({comp.resort.tripAdvisorReviews?.toLocaleString()} reviews)
Price Tier
{comp.resort.priceRange}
Estimated Cost (2 people)
${comp.estimatedTotalMin?.toLocaleString()}-${comp.estimatedTotalMax?.toLocaleString()}
{comp.budgetStatus && (
{comp.budgetStatus}
)}
Resort Features:
Beach: {comp.resort.features.beach} Pool: {comp.resort.features.pool} Food: {comp.resort.features.food} Spa: {comp.resort.features.spa} Nightlife: {comp.resort.features.nightlife} Golf: {comp.resort.features.golf}
))}
)}
)}
); }