['except' => 15], 'searchTerm' => ['except' => ''] ]; public function mount($resultRefs = [], $searchTerm = '', $total = 0) { $this->resultRefs = $resultRefs; $this->searchTerm = $searchTerm; $this->total = $total; } public function showProfile($id, $model) { $this->extendCachedResults(); $modelName = __(strtolower($model)); $this->redirectRoute('profile.show_by_type_and_id', ['type' => $modelName, 'id' => $id]); } public function showPost($id) { $this->extendCachedResults(); $this->redirectRoute('post.show', ['id' => $id]); } public function showCall($id) { $this->extendCachedResults(); $this->redirectRoute('call.show', ['id' => $id]); } private function extendCachedResults() { $key = 'main_search_bar_results_' . Auth::guard('web')->id(); $cacheData = cache()->get($key); if ($cacheData) { // Re-store with extended TTL (e.g., reset TTL and add 5 more minutes) cache()->put($key, $cacheData, now()->addMinutes(timebank_config('main_search_bar.cache_results', 5))); } } public function updatedPage() { $this->dispatch('scroll-to-top'); } public function render() { // Group model IDs by type for efficient eager loading $modelsByType = collect($this->resultRefs)->groupBy('model'); // Eager load models with their reaction data $loadedModels = []; foreach ($modelsByType as $modelClass => $refs) { $ids = collect($refs)->pluck('id')->toArray(); if ($modelClass === \App\Models\Call::class) { $callQuery = $modelClass::with([ 'callable.locations.city.translations', 'callable.locations.division.translations', 'callable.locations.country.translations', 'translations' => function ($query) { $query->where('locale', App::getLocale()); }, 'tag.contexts.category.translations', 'tag.contexts.category.ancestors.translations', 'location.city.translations', 'location.country.translations', 'loveReactant.reactionCounters', ])->whereIn('id', $ids); if (!\Illuminate\Support\Facades\Auth::check()) { $callQuery->where('is_public', true); } $models = $callQuery->get()->keyBy('id'); } elseif ($modelClass === \App\Models\Post::class) { // Posts don't need reaction loading for now $models = $modelClass::with([ 'postable' => function ($query) { $query->select(['id', 'name']); }, 'category' => function ($query) { $query->with('translations'); }, 'translations' => function ($query) { $query ->where('locale', App::getLocale()) ->whereDate('from', '<=', now()) ->where(function ($query) { $query->whereDate('till', '>', now())->orWhereNull('till'); }); }, 'meeting.location.district.translations', 'meeting.location.city.translations', 'meeting.location.country.translations', ])->whereIn('id', $ids)->get()->keyBy('id'); } else { // Profile models (User, Organization, Bank) with reaction data $models = $modelClass::with([ 'loveReactant.reactionCounters' ])->whereIn('id', $ids)->get()->keyBy('id'); } $loadedModels[$modelClass] = $models; } // Map refs to actual models and result arrays $results = collect($this->resultRefs)->map(function ($ref) use ($loadedModels) { $modelClass = $ref['model']; $model = $loadedModels[$modelClass][$ref['id']] ?? null; if (!$model) { return null; } $highlight = $ref['highlight'] ?? []; $score = $ref['score'] ?? null; // POST & CALL MODELS switch ($modelClass) { case \App\Models\Call::class: $translation = $model->translations->first(); $tag = $model->tag; $tagContext = $tag?->contexts->first(); $tagCategory = $tagContext?->category; $tagColor = $tagCategory?->relatedColor ?? 'gray'; $tagName = $tag?->translation?->name ?? $tag?->name; $locationStr = null; if ($model->location) { $loc = $model->location; $locParts = []; if ($loc->city) { $cityName = optional($loc->city->translations->first())->name; if ($cityName) $locParts[] = $cityName; } if ($loc->country) { if ($loc->country->code === 'XX') { $locParts[] = __('Location not specified'); } elseif ($loc->country->code) { $locParts[] = strtoupper($loc->country->code); } } $locationStr = $locParts ? implode(', ', $locParts) : null; } // Build category hierarchy: ancestors (root first) + self $tagCategories = []; if ($tagCategory) { $ancestors = $tagCategory->ancestorsAndSelf()->get()->reverse(); $locale = App::getLocale(); foreach ($ancestors as $cat) { $catName = $cat->translations->firstWhere('locale', $locale)?->name ?? $cat->translations->first()?->name ?? ''; if ($catName) { $tagCategories[] = [ 'name' => $catName, 'color' => $cat->relatedColor ?? 'gray', ]; } } } return [ 'id' => $model->id, 'model' => $modelClass, 'category_id' => null, 'category' => trans_with_platform('@PLATFORM_NAME@ call'), 'title' => $tagName ?? '', 'excerpt' => $translation?->content ?? '', 'photo' => $model->callable?->profile_photo_url ?? '', 'location' => $locationStr, 'location_short' => $city ?? '', 'tag_name' => $tagName, 'tag_color' => $tagColor, 'tag_categories' => $tagCategories, 'callable_name' => $model->callable?->name ?? '', 'callable_location' => \App\Http\Livewire\Calls\ProfileCalls::buildCallableLocation($model->callable), 'till' => $model->till, 'expiry_badge_text' => \App\Http\Livewire\Calls\ProfileCalls::buildExpiryBadgeText($model->till), 'meeting_venue' => '', 'meeting_address' => '', 'meeting_city' => '', 'meeting_location' => '', 'meeting_date_from' => '', 'meeting_date_till' => '', 'status' => '', 'highlight' => $highlight, 'score' => $score, 'like_count' => $model->loveReactant?->reactionCounters->firstWhere('reaction_type_id', 3)?->count ?? 0, 'bookmark_count' => $model->loveReactant?->reactionCounters->firstWhere('reaction_type_id', 2)?->count ?? 0, 'star_count' => 0, ]; case \App\Models\Post::class: $categoryId = optional($model->category)->id; $categoryName = optional($model->category->translations->where('locale', app()->getLocale())->first())->name; $photoUrl = $model->getFirstMediaUrl('posts', 'hero'); return [ 'id' => $model->id, 'model' => $modelClass, 'category_id' => $categoryId, 'category' => $categoryName, 'title' => $model->translations->first()->title, 'excerpt' => $model->translations->first()->excerpt, 'photo' => $photoUrl, 'location' => '', 'location_short' => '', 'meeting_venue' => $model->meeting->venue ?? '', 'meeting_address' => $model->meeting->address ?? '', 'meeting_city' => $model->meeting->location->city->translations ?? '', 'meeting_location' => $model->meeting ? $model->meeting->getLocationFirst() : '', 'meeting_date_from' => $model->meeting->from ?? '', 'meeting_date_till' => $model->meeting->till ?? '', 'status' => '', 'highlight' => $highlight, 'score' => $score, 'bookmark_count' => 0, 'star_count' => 0, 'like_count' => 0, ]; // PROFILE MODELS case \App\Models\User::class: case \App\Models\Organization::class: case \App\Models\Bank::class: // Extract reaction counts using Laravel-Love's built-in methods $bookmarkCount = 0; $starCount = 0; $likeCount = 0; if ($model->loveReactant) { // Get reaction types first $bookmarkType = \Cog\Laravel\Love\ReactionType\Models\ReactionType::fromName('bookmark'); $starType = \Cog\Laravel\Love\ReactionType\Models\ReactionType::fromName('star'); $likeType = \Cog\Laravel\Love\ReactionType\Models\ReactionType::fromName('like'); // Get counts using the ReactionType objects and extract the count value if ($bookmarkType) { $bookmarkCounter = $model->loveReactant->getReactionCounterOfType($bookmarkType); $bookmarkCount = $bookmarkCounter->getCount(); } if ($starType) { $starCounter = $model->loveReactant->getReactionCounterOfType($starType); $starCount = $starCounter->getCount(); } if ($likeType) { $likeCounter = $model->loveReactant->getReactionCounterOfType($likeType); $likeCount = $likeCounter->getCount(); } } return [ 'id' => $model->id, 'model' => $modelClass, 'name' => $model->name, 'full_name' => $model->full_name, 'about_short' => $model->about_short, 'about' => $model->about, 'motivation' => $model->motivation, 'photo' => $model->profile_photo_path, 'location' => $model->getLocationFirst(false)['name'] ?? '', 'location_short' => $model->getLocationFirst(false)['name_short'] ?? '', 'skills' => $this->getSkills($model) ?? '', 'cyclos_skills' => $model->cyclos_skills ?? '', 'deleted_at' => $model->deleted_at, 'status' => '', 'highlight' => $highlight, 'score' => $score, 'bookmark_count' => $bookmarkCount, 'star_count' => $starCount, 'like_count' => $likeCount, ]; default: return null; } })->filter()->values(); // Use Livewire's built-in pagination $currentPage = $this->getPage(); $results = $results->slice(($currentPage - 1) * $this->perPage, $this->perPage)->values(); $paginator = new \Illuminate\Pagination\LengthAwarePaginator( $results, collect($this->resultRefs)->count(), $this->perPage, $currentPage, [ 'path' => request()->url(), 'pageName' => 'page' ] ); $paginator->withQueryString(); return view('livewire.search.show', ['results' => $paginator]); } }