333 lines
14 KiB
PHP
333 lines
14 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Livewire\Search;
|
|
|
|
use App\Models\Bank;
|
|
use App\Models\Organization;
|
|
use App\Models\Post;
|
|
use App\Models\User;
|
|
use App\Traits\LocationTrait;
|
|
use App\Traits\ProfileTrait;
|
|
use Illuminate\Pagination\Paginator;
|
|
use Illuminate\Support\Facades\App;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Livewire\Component;
|
|
use Livewire\WithPagination;
|
|
|
|
class Show extends Component
|
|
{
|
|
use WithPagination;
|
|
use ProfileTrait;
|
|
use LocationTrait;
|
|
|
|
public $searchTerm = '';
|
|
public $resultRefs = [];
|
|
public $total = 0;
|
|
public $perPage = 15;
|
|
|
|
protected $queryString = [
|
|
'perPage' => ['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]);
|
|
}
|
|
}
|