@extends('layouts.public') @section('title', 'Flight Results — ' . strtoupper($criteria['origin'] ?? '') . ' → ' . strtoupper($criteria['destination'] ?? '')) @push('styles') @endpush @section('content')
@php $rate = $appExchangeRate; $sym = $appCurrSymbol; $pxStep = max(1, (int)round(500 * $rate)); @endphp
Filter results
@if(!empty($offers) && count($offers) > 0)
Stops
@php $stopCounts = collect($offers)->groupBy(fn($o) => min($o->stops, 2))->map->count(); @endphp
@foreach([0=>'Direct',1=>'1 Stop',2=>'2+ Stops'] as $n => $label) @endforeach
Max Price
@php $maxPrice = round(collect($offers)->max(fn($o) => $o->price) * $rate) ?? (100000 * $rate); $minPrice = round(collect($offers)->min(fn($o) => $o->price) * $rate) ?? 0; @endphp
{{ $sym }}{{ number_format($minPrice) }} Up to {{ $sym }}{{ number_format($maxPrice) }}
Airlines
@php $airlines = collect($offers)->groupBy(fn($o) => $o->airline)->map(fn($g, $code) => ['name' => $g->first()->airlineName, 'count' => $g->count()]); @endphp
@foreach($airlines as $code => $info) @endforeach
Take-off Time
🌙 Night 12am–6am
🌅 Morning 6am–12pm
☀️ Afternoon 12pm–6pm
🌆 Evening 6pm–12am
Max Duration
@php $maxDur = collect($offers)->max(fn($o) => $o->durationSeconds); $maxDurH = ceil($maxDur / 3600); @endphp
Up to {{ $maxDurH }}h
@endif
{{-- /offcanvas-body --}}
{{-- /offcanvas --}}
{{-- /col-lg-3 --}}
@if($error) @php $isTimeout = str_contains($error, 'cURL error 28') || str_contains($error, 'timed out') || str_contains($error, 'Operation timed'); $retryUrl = request()->fullUrl(); @endphp
@if($isTimeout)
Search is taking too long

The flight API is responding slowly right now. This usually fixes itself in a few seconds.

Tip: Results are cached after the first successful search — so a retry is usually instant.

@else
Search failed

{{ $error }}

@endif
@elseif(empty($offers))
No flights found

Try different dates or airports.

New Search
@else {{-- Demo/estimated prices notice --}} @if(!empty($isDemoResult))
Estimated prices shown
Live flight data is currently unavailable for this route. Prices and times shown are indicative only — search again or try a different route for real fares.
@endif {{-- Mobile sticky filter+sort bar --}}
Cheapest
Quickest
Best
Direct only
@php $cheapest = collect($offers)->sortBy('price')->first(); $fastest = collect($offers)->sortBy('durationSeconds')->first(); @endphp
Cheapest
{{ $sym }}{{ number_format(round($cheapest->price * $rate)) }}
Quickest
{{ $fastest->formatDuration() }}
Best
Price + speed
{{ count($offers) }} flights found
{{-- Departure time chart --}} @php $hourCounts = []; foreach($offers as $_o) { $_h = $_o->departureDateTime ? (int)\Carbon\Carbon::parse($_o->departureDateTime)->format('G') : 0; $hourCounts[$_h] = ($hourCounts[$_h] ?? 0) + 1; } $maxHourCount = max(array_values($hourCounts) ?: [1]); @endphp
Departure time distribution ✕ clear
@for($_h = 0; $_h < 24; $_h++) @php $_cnt = $hourCounts[$_h] ?? 0; $_px = $maxHourCount > 0 ? max(3, (int)round($_cnt / $maxHourCount * 40)) : 3; $_lbl = in_array($_h, [0,6,12,18,23]) ? str_pad($_h,2,'0',STR_PAD_LEFT) : ''; @endphp
{{ $_lbl }}
@endfor
@php $sortedByPrice = collect($offers)->sortBy('price')->values(); $sortedByDuration = collect($offers)->sortBy('durationSeconds')->values(); $cheapestOffer = $sortedByPrice->first(); $fastestOffer = $sortedByDuration->first(); $maxOfferPrice = collect($offers)->max(fn($o) => $o->price); $minOfferPrice = collect($offers)->min(fn($o) => $o->price); // Best = lowest (price/maxP + duration/maxD) score $maxDurSec = collect($offers)->max(fn($o) => $o->durationSeconds); $bestOffer = collect($offers)->sortBy(fn($o) => ($o->price / max($maxOfferPrice,1)) + ($o->durationSeconds / max($maxDurSec,1)) )->first(); @endphp @foreach($offers as $i => $offer) @php $depHour = $offer->departureDateTime ? (int)\Carbon\Carbon::parse($offer->departureDateTime)->format('G') : 12; $pricePct = $maxOfferPrice > $minOfferPrice ? round(($offer->price - $minOfferPrice) / ($maxOfferPrice - $minOfferPrice) * 100) : 50; $barColor = $pricePct < 33 ? '#16a34a' : ($pricePct < 66 ? '#f59e0b' : '#ef4444'); $isCheapest = ($offer->id === $cheapestOffer->id); $isFastest = ($offer->id === $fastestOffer->id); $isBest = ($offer->id === $bestOffer->id); // Build Google Flights link $gDate = $offer->departureDateTime ? \Carbon\Carbon::parse($offer->departureDateTime)->format('Y-m-d') : ($criteria['departureDate'] ?? ''); $gLink = 'https://www.google.com/travel/flights?q=Flights+from+' . $offer->origin . '+to+' . $offer->destination . '+on+' . $gDate; @endphp
{{-- Badges --}} @if($isCheapest || $isFastest || $isBest)
@if($isCheapest)Cheapest@endif @if($isFastest && !$isCheapest)Fastest@endif @if($isBest && !$isCheapest && !$isFastest)Best Value@endif
@endif {{-- 3-col grid: airline | itinerary | price --}}
{{-- Airline --}}
{{ Str::words($offer->airlineName ?: $offer->airline, 2, '') }}
{{-- Itinerary: outbound + optional return leg --}}
{{-- Outbound --}}
{{ $offer->departureDateTime ? \Carbon\Carbon::parse($offer->departureDateTime)->format('H:i') : '—' }}
{{ $offer->origin }}
{{ $offer->stops===0?'Direct':$offer->stops.' stop'.($offer->stops>1?'s':'') }}
{{ $offer->arrivalDateTime ? \Carbon\Carbon::parse($offer->arrivalDateTime)->format('H:i') : '—' }} @php $extraDays=\Carbon\Carbon::parse($offer->departureDateTime)->startOfDay()->diffInDays(\Carbon\Carbon::parse($offer->arrivalDateTime)->startOfDay()); @endphp @if($extraDays>0)+{{ $extraDays }}@endif
{{ $offer->destination }}
{{ $offer->formatDuration() }}
{{-- Return leg (inline) --}} @if($offer->isRoundTrip && $offer->returnDeparture)
{{ \Carbon\Carbon::parse($offer->returnDeparture)->format('H:i') }}
{{ $offer->destination }}
{{ $offer->returnStops===0?'Direct':$offer->returnStops.' stop'.($offer->returnStops>1?'s':'') }}
{{ $offer->returnArrival ? \Carbon\Carbon::parse($offer->returnArrival)->format('H:i') : '—' }}
{{ $offer->origin }}
{{ $offer->formatReturnDuration() }}
@endif
{{-- Price + Select --}}
{{ $sym }}{{ number_format(round($offer->price * $rate)) }}
{{ $offer->fareClass }} · per person
@php $vmData = json_encode([ 'origin' => $offer->origin, 'dest' => $offer->destination, 'date' => $gDate, 'priceINR' => round($offer->price), 'price' => round($offer->price * $rate), 'sym' => $sym, 'airline' => $offer->airline, 'airlineName' => $offer->airlineName ?: $offer->airline, 'depTime' => $offer->departureDateTime ? \Carbon\Carbon::parse($offer->departureDateTime)->format('H:i') : '', 'arrTime' => $offer->arrivalDateTime ? \Carbon\Carbon::parse($offer->arrivalDateTime)->format('H:i') : '', 'duration' => $offer->formatDuration(), 'stops' => $offer->stops, 'fareClass' => $offer->fareClass, 'adults' => intval($criteria['adults'] ?? 1), 'isRT' => $offer->isRoundTrip, 'retDate' => !empty($criteria['returnDate']) ? $criteria['returnDate'] : '', 'retDepTime' => $offer->returnDeparture ? \Carbon\Carbon::parse($offer->returnDeparture)->format('H:i') : '', 'retArrTime' => $offer->returnArrival ? \Carbon\Carbon::parse($offer->returnArrival)->format('H:i') : '', 'retDuration' => $offer->isRoundTrip ? $offer->formatReturnDuration() : '', 'retStops' => $offer->returnStops, ]); @endphp
{{-- Footer: airline · aircraft · baggage · expand --}} {{-- Expandable segment details --}} @if(!empty($offer->segments))
@foreach($offer->segments as $sIdx => $seg) @php // Support both raw Amadeus format (nested) and normalized flat format $segDep = is_array($seg['departure'] ?? null) ? ($seg['departure']['at'] ?? '') : ($seg['departure'] ?? ''); $segArr = is_array($seg['arrival'] ?? null) ? ($seg['arrival']['at'] ?? '') : ($seg['arrival'] ?? ''); $segFrom = is_array($seg['departure'] ?? null) ? ($seg['departure']['iataCode'] ?? '') : ($seg['from'] ?? ''); $segTo = is_array($seg['arrival'] ?? null) ? ($seg['arrival']['iataCode'] ?? '') : ($seg['to'] ?? ''); $segDur = isset($seg['durationFmt']) ? $seg['durationFmt'] : (isset($seg['duration']) && is_int($seg['duration']) ? \App\DTOs\FlightOffer::formatSeconds($seg['duration']) : ($seg['duration'] ?? '')); @endphp
{{ $seg['flightNumber'] ?? ($seg['carrier'] ?? '').($seg['number'] ?? '') }}
{{ $seg['aircraft'] ?? '' }}
{{ $segDep ? \Carbon\Carbon::parse($segDep)->format('H:i') : '' }} {{ $segFrom }} {{ $segArr ? \Carbon\Carbon::parse($segArr)->format('H:i') : '' }} {{ $segTo }}
{{ $segDur }}
@if($sIdx < count($offer->segments)-1) @php $layoverCity = $segTo ?: 'connection'; $arrT = $segArr ? \Carbon\Carbon::parse($segArr) : null; $nextSeg = $offer->segments[$sIdx+1]; $nextDep = is_array($nextSeg['departure'] ?? null) ? ($nextSeg['departure']['at'] ?? '') : ($nextSeg['departure'] ?? ''); $depT = $nextDep ? \Carbon\Carbon::parse($nextDep) : null; $layoverMin = ($arrT && $depT) ? $arrT->diffInMinutes($depT) : 0; $layoverStr = $layoverMin >= 60 ? floor($layoverMin/60).'h '.($layoverMin%60).'m' : $layoverMin.'m'; @endphp
{{ $layoverStr }} layover in {{ $layoverCity }}
@endif @endforeach
@endif {{-- Return segment expand (if round trip) --}} {{-- Return leg is already shown inline in rc-grid above --}}
@endforeach
@endif
@endsection @push('scripts') @endpush