@php $activeQuery = request()->except(['page']); // The filter panel's hidden blank placeholder inputs (type[]=""/ // bhk[]=""/amenities[]="") let an all-unchecked submission be told // apart from "not submitted at all" (see _filter-panel.blade.php) — // Laravel's ConvertEmptyStringsToNull middleware turns that blank entry // into a literal `null`, which must never reach a chip: left in, it // rendered as an unlabelled empty chip (type) or a stray " BHK" chip // with no number (bhk) even though nothing was actually selected. Only // plain sequential-list values are touched — 'fields' stays untouched, // since array_values() would mangle its associative structure (e.g. // fields[select][furnished_status]) into numeric keys. $activeQuery = array_map(function ($value) { if (is_array($value) && array_values($value) === $value) { return array_values(array_filter($value, fn ($v) => filled($v))); } return $value; }, $activeQuery); // $key accepts dot-notation for nested query params (e.g. // "fields.select.furnished_status") — used by the dynamic field chips // below, resolved via Arr::forget/get/set rather than plain // unset($updated[$key]), which only ever worked for flat top-level keys. $chipUrl = function ($key, $removeValue = null) use ($activeQuery) { $updated = $activeQuery; if ($removeValue === null) { \Illuminate\Support\Arr::forget($updated, $key); } else { $remaining = array_values(array_diff((array) \Illuminate\Support\Arr::get($updated, $key, []), [$removeValue])); if (empty($remaining)) { \Illuminate\Support\Arr::forget($updated, $key); } else { \Illuminate\Support\Arr::set($updated, $key, $remaining); } } $queryString = http_build_query($updated); return url()->current() . ($queryString ? '?' . $queryString : ''); }; $chips = []; if (filled($activeQuery['purpose'] ?? null)) { $chips[] = ['label' => $activeQuery['purpose'] === 'for_rent' ? 'For Rent' : 'For Sale', 'href' => $chipUrl('purpose')]; } foreach ((array) ($activeQuery['type'] ?? []) as $typeSlug) { $chips[] = ['label' => $propertyTypes[$typeSlug] ?? $typeSlug, 'href' => $chipUrl('type', $typeSlug)]; } if (filled($activeQuery['city'] ?? null)) { $chips[] = ['label' => 'In ' . $activeQuery['city'], 'href' => $chipUrl('city')]; } if (filled($activeQuery['q'] ?? null)) { $chips[] = ['label' => '"' . $activeQuery['q'] . '"', 'href' => $chipUrl('q')]; } if (filled($activeQuery['locality'] ?? null)) { $chips[] = ['label' => '"' . $activeQuery['locality'] . '"', 'href' => $chipUrl('locality')]; } if (filled($activeQuery['min'] ?? null)) { $chips[] = ['label' => 'From ' . \App\Models\Property::formatIndianCurrency($activeQuery['min']), 'href' => $chipUrl('min')]; } if (filled($activeQuery['max'] ?? null)) { $chips[] = ['label' => 'Under ' . \App\Models\Property::formatIndianCurrency($activeQuery['max']), 'href' => $chipUrl('max')]; } // bhk/fields[...] are type-dependent — a value left over from a // previously selected, now-deselected Property Type must not render as // an active chip once no currently selected type actually supports it, // even though it may still be sitting in the query string (the filter // panel no longer force-clears these on a type change — see // _filter-panel.blade.php — relying instead on both the sidebar's own // display gating AND PublicPropertySearchService silently ignoring it // server-side). Chips must agree with what's ACTUALLY being filtered, // not just what's present in the URL — mirrors // PublicPropertySearchService::typeSelectionSupportsBhk()/ // validKeysForSelectedTypes() exactly, so a chip only ever shows for a // filter that's genuinely still in effect. $fixedType = $fixedType ?? null; $selectedTypes = $fixedType !== null ? [$fixedType] : (array) ($activeQuery['type'] ?? []); if (count(array_intersect($selectedTypes, \App\Models\Property::typesWithBhkField())) > 0) { foreach ((array) ($activeQuery['bhk'] ?? []) as $bhk) { $chips[] = ['label' => $bhk . ' BHK', 'href' => $chipUrl('bhk', $bhk)]; } } foreach ((array) ($activeQuery['amenities'] ?? []) as $tagId) { $tagName = optional($propertyTags->firstWhere('id', (int) $tagId))->name ?? $tagId; $chips[] = ['label' => $tagName, 'href' => $chipUrl('amenities', $tagId)]; } // Dynamic, admin-configured type-specific filters (Property Field // Templates) — fields[select][][], fields[boolean][], // fields[number][][min|max]. Labelled via a fresh lookup rather than // whatever's in scope on this page load, since the results header (where // this partial is included) doesn't otherwise have the field templates // to hand — see PropertyFieldTemplate::filterableGroupsForTypes(). $activeFields = (array) ($activeQuery['fields'] ?? []); if (! empty($activeFields)) { $dynamicFieldKeys = array_unique(array_merge( array_keys((array) ($activeFields['select'] ?? [])), array_keys((array) ($activeFields['boolean'] ?? [])), array_keys((array) ($activeFields['number'] ?? [])) )); $fieldLabelsByKey = \App\Models\PropertyFieldTemplate::whereIn('field_key', $dynamicFieldKeys) ->pluck('field_label', 'field_key'); // Same scoping PublicPropertySearchService::validKeysForSelectedTypes() // applies server-side — a field_key only counts as "valid" here if it // actually belongs to one of the currently selected type(s); empty // $selectedTypes (type cleared) means nothing here is valid, matching // both the sidebar (no dynamic groups render) and the search query // (no dynamic filter applied). $validFieldKeysByType = empty($selectedTypes) ? [] : \App\Models\PropertyFieldTemplate::whereIn('property_type', $selectedTypes) ->whereIn('field_key', $dynamicFieldKeys) ->pluck('field_key') ->all(); $isValidKey = fn ($key) => in_array($key, $validFieldKeysByType, true); foreach ((array) ($activeFields['select'] ?? []) as $key => $values) { if (! $isValidKey($key)) { continue; } foreach ((array) $values as $value) { $chips[] = [ 'label' => ($fieldLabelsByKey[$key] ?? $key) . ': ' . $value, 'href' => $chipUrl("fields.select.{$key}", $value), ]; } } foreach ((array) ($activeFields['boolean'] ?? []) as $key => $value) { if (filled($value) && $isValidKey($key)) { $chips[] = ['label' => $fieldLabelsByKey[$key] ?? $key, 'href' => $chipUrl("fields.boolean.{$key}")]; } } foreach ((array) ($activeFields['number'] ?? []) as $key => $range) { if (! $isValidKey($key)) { continue; } $label = $fieldLabelsByKey[$key] ?? $key; if (filled($range['min'] ?? null)) { $chips[] = ['label' => $label . ': from ' . $range['min'], 'href' => $chipUrl("fields.number.{$key}.min")]; } if (filled($range['max'] ?? null)) { $chips[] = ['label' => $label . ': up to ' . $range['max'], 'href' => $chipUrl("fields.number.{$key}.max")]; } } } @endphp @if (!empty($chips))
@foreach ($chips as $chip) {{ $chip['label'] }} @endforeach Clear all
@endif