@extends('layouts.public') @section('content') @php /** @var array $restaurants @var array $cuisines @var array $tags @var array $filters @var string $view @var string $diet @var bool $openNow */ $tags = $tags ?? []; $view = in_array($view ?? 'grid', ['list', 'map'], true) ? $view : 'grid'; $diet = $diet ?? ''; $openNow = $openNow ?? false; $priceMax = (float) ($filters['price_max'] ?? 0); // Geo (F2/S6/S7/S8), all resolved by the controller. $origin is null when nothing // located the visitor — a radius measured from nowhere is not a filter, so the whole // distance control stays off the page rather than sitting there doing nothing. $radius = (float) ($radius ?? 0); $radiusMin = (float) ($radiusMin ?? 1); $radiusMax = (float) ($radiusMax ?? 25); $origin = $origin ?? null; // True when a radius was asked for and nothing could be measured from — see the note by the slider. $radiusIgnored = (bool) ($radiusIgnored ?? false); $mapAvailable = (bool) ($mapAvailable ?? false); $mapPoints = $mapPoints ?? []; $mapCapped = (bool) ($mapCapped ?? false); $mapMaxPins = (int) ($mapMaxPins ?? 500); $mapCluster = (bool) ($mapCluster ?? true); $geoBrowser = (bool) ($geoBrowser ?? false); $distUnit = \App\Services\Distance::unitLabel(); // The pin only travels in the query string when the browser is the thing that found it. $pinLat = $geoBrowser && is_numeric(request()->query('lat')) ? (string) request()->query('lat') : ''; $pinLng = $geoBrowser && is_numeric(request()->query('lng')) ? (string) request()->query('lng') : ''; // $restaurants holds only the current page; the total (across all pages) drives the counts. $total = (int) ($pager['total'] ?? count($restaurants)); // Preserve current query params (except view) when building toggle links. $baseQuery = request()->query(); unset($baseQuery['view']); $gridHref = route('restaurants') . '?' . http_build_query(array_merge($baseQuery, ['view' => 'grid'])); $listHref = route('restaurants') . '?' . http_build_query(array_merge($baseQuery, ['view' => 'list'])); $mapHref = route('restaurants') . '?' . http_build_query(array_merge($baseQuery, ['view' => 'map'])); $dietLabels = [ '004-leaf' => t_raw('common.diet_vegetarian_options'), '006-chili' => t_raw('common.diet_spicy_dishes'), '005-chef' => t_raw('common.diet_chefs_picks'), '008-protein' => t_raw('common.diet_egg_dishes'), '009-lemon' => t_raw('common.diet_zesty_dishes'), ]; // ----- Active-filter chips: build a removable chip per applied filter. Each chip // links back to this same page with just that one parameter dropped, so a buyer // can clear filters individually instead of only "Reset all". $cuisineLabels = []; foreach ($cuisines as $c) { $cuisineLabels[$c['slug']] = $c['name']; } $tagLabels = []; foreach ($tags as $t) { $tagLabels[$t['slug']] = $t['name']; } $dietChipLabels = ['veg' => t_raw('restaurant.diet_veg'), 'vegan' => t_raw('restaurant.diet_vegan'), 'protein' => t_raw('restaurant.diet_protein'), 'light' => t_raw('restaurant.diet_light')]; $sortChipLabels = ['rating' => t_raw('restaurant.sort_top_rated'), 'delivery' => t_raw('restaurant.sort_fastest_delivery'), 'price' => t_raw('restaurant.sort_lowest_min_order'), 'newest' => t_raw('restaurant.sort_newest')]; // A chip's link is the CURRENT query string minus one parameter — a plain link, so // removing a filter needs no JavaScript. Two parameters are deliberately handled // differently from the rest: // `view` is kept. It is how the visitor is looking at the results, not something // they filtered by, and dropping a chip must not throw them out of the map. // `page` is dropped. A narrower or wider result set has a different last page, and // page 7 of a 3-page result set is an empty screen that reads as "no results". $chipQuery = request()->query(); unset($chipQuery['page']); // The view that actually rendered, not the one that was asked for. An install with no // map configured downgrades `view=map` to the grid, and a chip must not hand back a // parameter the page just refused. if ($view === 'grid') { unset($chipQuery['view']); } else { $chipQuery['view'] = $view; } $chips = []; $chipFor = static function (string $param, string $label) use ($chipQuery, $__env): array { $q = $chipQuery; unset($q[$param]); return ['label' => $label, 'href' => route('restaurants') . ($q ? '?' . http_build_query($q) : '')]; }; if (($filters['q'] ?? '') !== '') { $chips[] = $chipFor('q', t_raw('restaurant.chip_search', [':q' => $filters['q']])); } if (($filters['city'] ?? '') !== '') { $chips[] = $chipFor('city', t_raw('restaurant.chip_city', [':city' => $filters['city']])); } if (($filters['cuisine'] ?? '') !== '') { $chips[] = $chipFor('cuisine', t_raw('restaurant.chip_cuisine', [':name' => $cuisineLabels[$filters['cuisine']] ?? $filters['cuisine']])); } if (($filters['tag'] ?? '') !== '') { $chips[] = $chipFor('tag', t_raw('restaurant.chip_tag', [':name' => $tagLabels[$filters['tag']] ?? $filters['tag']])); } if ($openNow) { $chips[] = $chipFor('open', t_raw('restaurant.open_now')); } if ($diet !== '') { $chips[] = $chipFor('diet', $dietChipLabels[$diet] ?? ucfirst($diet)); } if ($priceMax > 0) { $chips[] = $chipFor('price_max', t_raw('restaurant.chip_price_up_to', [':price' => money($priceMax)])); } if (($filters['min_rating'] ?? 0) > 0) { $chips[] = $chipFor('min_rating', t_raw('restaurant.chip_min_rating', [':rating' => number_format((float) $filters['min_rating'], 1)])); } // The radius chip carries the CLAMPED figure, not the one that was asked for, so the // chip and the result set always say the same thing. if ($radius > 0 && $origin !== null) { $chips[] = $chipFor('radius', t_raw('restaurant.chip_radius', [':distance' => rtrim(rtrim(number_format($radius, 1), '0'), '.') . ' ' . $distUnit])); } if (($filters['sort'] ?? '') !== '' && isset($sortChipLabels[$filters['sort']])) { $chips[] = $chipFor('sort', $sortChipLabels[$filters['sort']]); } // Clear all keeps only the view, for the same reason a chip does. $clearAllHref = route('restaurants') . ($view !== 'grid' ? '?view=' . $view : ''); @endphp