From a35b0056e11507037e68a3e52a7e02251f94abd1 Mon Sep 17 00:00:00 2001 From: benzimariano Date: Tue, 9 Jun 2026 11:26:32 +0200 Subject: [PATCH] finale 2.0.0.0 --- app/Http/Controllers/RicercaController.php | 58 +++++++ app/Models/Tag.php | 62 +++++++ app/Traits/HasTagsLight.php | 30 ++++ ...d_ruolo_nel_gruppo_to_gruppo_individuo.php | 23 +++ .../2026_06_08_194155_create_tags_tables.php | 38 +++++ .../views/partials/_tag-filter-bar.blade.php | 34 ++++ .../views/partials/_tag-selector.blade.php | 123 ++++++++++++++ resources/views/ricerca/index.blade.php | 155 ++++++++++++++++++ 8 files changed, 523 insertions(+) create mode 100644 app/Http/Controllers/RicercaController.php create mode 100644 app/Models/Tag.php create mode 100644 app/Traits/HasTagsLight.php create mode 100644 database/migrations/2026_06_08_182714_add_ruolo_nel_gruppo_to_gruppo_individuo.php create mode 100644 database/migrations/2026_06_08_194155_create_tags_tables.php create mode 100644 resources/views/partials/_tag-filter-bar.blade.php create mode 100644 resources/views/partials/_tag-selector.blade.php create mode 100644 resources/views/ricerca/index.blade.php diff --git a/app/Http/Controllers/RicercaController.php b/app/Http/Controllers/RicercaController.php new file mode 100644 index 00000000..4b6e7b64 --- /dev/null +++ b/app/Http/Controllers/RicercaController.php @@ -0,0 +1,58 @@ +authorizeRead('individui'); + + $allTags = Tag::orderBy('name')->get(); + + $tagSlugs = (array) $request->input('tag', []); + + if (empty($tagSlugs)) { + return view('ricerca.index', compact('allTags')); + } + + $tagSlugs = array_filter($tagSlugs); + $selectedTags = Tag::whereIn('slug', $tagSlugs)->get(); + + $results = []; + $totals = []; + + if (count($tagSlugs) === 1) { + $tag = $selectedTags->first(); + $results['individui'] = $tag->individui()->orderBy('cognome')->orderBy('nome')->get(); + $results['gruppi'] = $tag->gruppi()->orderBy('nome')->get(); + $results['eventi'] = $tag->eventi()->orderBy('data_specifica')->orderBy('nome_evento')->get(); + $results['documenti'] = $tag->documenti()->orderBy('nome_file')->get(); + $results['mailingLists'] = $tag->mailingLists()->orderBy('nome')->get(); + } else { + $results['individui'] = Individuo::withAllTags($tagSlugs)->orderBy('cognome')->orderBy('nome')->get(); + $results['gruppi'] = Gruppo::withAllTags($tagSlugs)->orderBy('nome')->get(); + $results['eventi'] = Evento::withAllTags($tagSlugs)->orderBy('data_specifica')->orderBy('nome_evento')->get(); + $results['documenti'] = Documento::withAllTags($tagSlugs)->orderBy('nome_file')->get(); + $results['mailingLists'] = MailingList::withAllTags($tagSlugs)->orderBy('nome')->get(); + } + + $totals = [ + 'individui' => $results['individui']->count(), + 'gruppi' => $results['gruppi']->count(), + 'eventi' => $results['eventi']->count(), + 'documenti' => $results['documenti']->count(), + 'mailingLists' => $results['mailingLists']->count(), + ]; + + return view('ricerca.index', compact('selectedTags', 'tagSlugs', 'results', 'totals', 'allTags')); + } +} diff --git a/app/Models/Tag.php b/app/Models/Tag.php new file mode 100644 index 00000000..0a927734 --- /dev/null +++ b/app/Models/Tag.php @@ -0,0 +1,62 @@ + 'integer', + ]; + + protected static function boot(): void + { + parent::boot(); + + static::creating(function (self $tag) { + if (empty($tag->slug)) { + $tag->slug = str()->slug($tag->name); + } + }); + } + + public function individui(): MorphToMany + { + return $this->morphedByMany(Individuo::class, 'taggable'); + } + + public function gruppi(): MorphToMany + { + return $this->morphedByMany(Gruppo::class, 'taggable'); + } + + public function eventi(): MorphToMany + { + return $this->morphedByMany(Evento::class, 'taggable'); + } + + public function documenti(): MorphToMany + { + return $this->morphedByMany(Documento::class, 'taggable'); + } + + public function mailingLists(): MorphToMany + { + return $this->morphedByMany(MailingList::class, 'taggable'); + } + + public function getCountAttribute(): int + { + return $this->individui()->count() + + $this->gruppi()->count() + + $this->eventi()->count() + + $this->documenti()->count() + + $this->mailingLists()->count(); + } +} diff --git a/app/Traits/HasTagsLight.php b/app/Traits/HasTagsLight.php new file mode 100644 index 00000000..841d8d04 --- /dev/null +++ b/app/Traits/HasTagsLight.php @@ -0,0 +1,30 @@ +morphToMany(Tag::class, 'taggable'); + } + + public function scopeWithAllTags($query, array $tags) + { + foreach ($tags as $tag) { + $query->whereHas('tags', fn ($q) => $q->where('slug', $tag)); + } + + return $query; + } + + public function scopeWithAnyTags($query, array $tags) + { + $query->whereHas('tags', fn ($q) => $q->whereIn('slug', $tags)); + + return $query; + } +} diff --git a/database/migrations/2026_06_08_182714_add_ruolo_nel_gruppo_to_gruppo_individuo.php b/database/migrations/2026_06_08_182714_add_ruolo_nel_gruppo_to_gruppo_individuo.php new file mode 100644 index 00000000..d53df107 --- /dev/null +++ b/database/migrations/2026_06_08_182714_add_ruolo_nel_gruppo_to_gruppo_individuo.php @@ -0,0 +1,23 @@ +string('ruolo_nel_gruppo')->nullable()->after('ruolo_ids'); + }); + } + } + + public function down(): void + { + } +}; diff --git a/database/migrations/2026_06_08_194155_create_tags_tables.php b/database/migrations/2026_06_08_194155_create_tags_tables.php new file mode 100644 index 00000000..1a9313e9 --- /dev/null +++ b/database/migrations/2026_06_08_194155_create_tags_tables.php @@ -0,0 +1,38 @@ +id(); + $table->string('name', 100); + $table->string('slug', 100)->unique(); + $table->string('color', 7)->nullable(); + $table->integer('order_column')->default(0); + $table->timestamps(); + }); + } + + if (!Schema::hasTable('taggables')) { + Schema::create('taggables', function (Blueprint $table) { + $table->foreignId('tag_id')->constrained()->cascadeOnDelete(); + $table->morphs('taggable'); + $table->primary(['tag_id', 'taggable_id', 'taggable_type']); + }); + } + } + + public function down(): void + { + Schema::dropIfExists('taggables'); + Schema::dropIfExists('tags'); + } +}; diff --git a/resources/views/partials/_tag-filter-bar.blade.php b/resources/views/partials/_tag-filter-bar.blade.php new file mode 100644 index 00000000..3a602076 --- /dev/null +++ b/resources/views/partials/_tag-filter-bar.blade.php @@ -0,0 +1,34 @@ +@php + $filterTags = $filterTags ?? (\App\Models\Tag::orderBy('name')->get()); + $activeTags = (array) request('tag', []); +@endphp +@if($filterTags->isNotEmpty()) +
+ Tag: + @foreach($filterTags as $tag) + @php + $isActive = in_array($tag->slug, $activeTags); + $query = request()->query(); + if ($isActive) { + $newTags = array_values(array_diff($activeTags, [$tag->slug])); + if (empty($newTags)) { + unset($query['tag']); + } else { + $query['tag'] = $newTags; + } + } else { + $query['tag'] = array_merge($activeTags, [$tag->slug]); + } + $url = request()->url() . '?' . http_build_query($query); + @endphp + + {{ $tag->name }} + + @endforeach + @if(!empty($activeTags)) + + Cancella filtri + + @endif +
+@endif diff --git a/resources/views/partials/_tag-selector.blade.php b/resources/views/partials/_tag-selector.blade.php new file mode 100644 index 00000000..0f34714b --- /dev/null +++ b/resources/views/partials/_tag-selector.blade.php @@ -0,0 +1,123 @@ +@php + $allTags = $allTags ?? \App\Models\Tag::orderBy('name')->get(); + $selectedTags = old('tags', $selectedTags ?? []); + $tagFieldName = $tagFieldName ?? 'tags'; + $selectorId = 'tag-selector-' . md5($tagFieldName); + $selectedTagObjects = $allTags->whereIn('id', $selectedTags); +@endphp + +
+ + +
+
+ @foreach($selectedTagObjects as $tag) + + {{ $tag->name }} + + + @endforeach +
+ +
+ +
+ +
+ @foreach($allTags as $tag) + + @endforeach + @if($allTags->isEmpty()) +

Nessun tag disponibile. Crea i tag nelle Impostazioni.

+ @endif + +
+
+ +
+ @foreach($selectedTags as $selectedId) + + @endforeach +
+
+ +@once +@push('scripts') + +@endpush +@endonce diff --git a/resources/views/ricerca/index.blade.php b/resources/views/ricerca/index.blade.php new file mode 100644 index 00000000..1261bbf8 --- /dev/null +++ b/resources/views/ricerca/index.blade.php @@ -0,0 +1,155 @@ +@extends('layouts.adminlte') + +@section('title', 'Ricerca per Tag') +@section('page_title', 'Ricerca per Tag') + +@section('content') +
+
+

+ @isset($selectedTags) + Risultati per: + @foreach($selectedTags as $t) + {{ $t->name }} + @endforeach + @if(count($tagSlugs) > 1) + (intersezione — tutti i tag richiesti) + @endif + @else + Seleziona uno o più tag + @endisset +

+
+
+ @if(!isset($selectedTags) || $selectedTags->isEmpty()) +

Clicca sui tag per selezionarli (Ctrl+click per più tag).

+
+
+ @foreach($allTags as $t) + + @endforeach + @if($allTags->isEmpty()) +

Nessun tag disponibile. Crea i tag nelle Impostazioni.

+ @endif +
+ @if($allTags->isNotEmpty()) +
+ +
+ @endif +
+ @else +
+ @php + $indexRoutes = [ + 'individui' => 'individui.index', + 'gruppi' => 'gruppi.index', + 'eventi' => 'eventi.index', + 'documenti' => 'documenti.index', + 'mailingLists' => 'mailing-liste.index', + ]; + $tagParams = collect($tagSlugs)->map(fn($s) => "tag[]={$s}")->implode('&'); + @endphp + + @foreach([ + ['key' => 'individui', 'color' => 'info', 'icon' => 'fa-user', 'label' => 'Individui'], + ['key' => 'gruppi', 'color' => 'success', 'icon' => 'fa-users', 'label' => 'Gruppi'], + ['key' => 'eventi', 'color' => 'warning', 'icon' => 'fa-calendar-alt', 'label' => 'Eventi'], + ['key' => 'documenti', 'color' => 'secondary', 'icon' => 'fa-file', 'label' => 'Documenti'], + ['key' => 'mailingLists', 'color' => 'purple', 'icon' => 'fa-list', 'label' => 'Mailing List'], + ] as $box) +
+
+ +
+ {{ $box['label'] }} + {{ $totals[$box['key']] }} + @if($totals[$box['key']] > 0 && isset($indexRoutes[$box['key']])) + Vedi tutti » + @endif +
+
+
+ @endforeach +
+ + @php + $sections = [ + 'individui' => ['color' => 'info', 'icon' => 'fa-user', 'title' => 'Individui', 'cols' => ['Cognome', 'Nome', 'Email'], 'fields' => ['cognome', 'nome', 'email_primaria']], + 'gruppi' => ['color' => 'success', 'icon' => 'fa-users', 'title' => 'Gruppi', 'cols' => ['Nome', 'Descrizione'], 'fields' => ['nome', 'descrizione_limit']], + 'eventi' => ['color' => 'warning', 'icon' => 'fa-calendar-alt', 'title' => 'Eventi', 'cols' => ['Evento', 'Data', 'Ora'], 'fields' => ['nome_evento', 'data', 'ora']], + 'documenti' => ['color' => 'secondary', 'icon' => 'fa-file', 'title' => 'Documenti', 'cols' => ['Nome File', 'Tipo'], 'fields' => ['nome_file', 'tipo']], + 'mailingLists' => ['color' => 'purple', 'icon' => 'fa-list', 'title' => 'Mailing List', 'cols' => ['Nome', 'Contatti', 'Stato'], 'fields' => ['nome', 'contatti_count', 'stato']], + ]; + @endphp + + @foreach($sections as $key => $section) + @if($totals[$key] > 0) +
+
+
{{ $section['title'] }} ({{ $totals[$key] }})
+
+
+ + + @foreach($section['cols'] as $col)@endforeach + + + + @foreach($results[$key] as $item) + + @if($key === 'individui') + + + + + @elseif($key === 'gruppi') + + + + @elseif($key === 'eventi') + + + + + @elseif($key === 'documenti') + + + + @elseif($key === 'mailingLists') + + + + + @endif + + @endforeach + +
{{ $col }}
{{ $item->cognome }}{{ $item->nome }}{{ $item->email_primaria ?? '-' }}{{ $item->nome }}{{ Str::limit($item->descrizione, 80) ?? '-' }}{{ $item->nome_evento }}{{ $item->data_specifica ? $item->data_specifica->format('d/m/Y') : ($item->tipo_recorrenza ?? '-') }}{{ $item->ora_inizio ? $item->ora_inizio->format('H:i') : '-' }}{{ $item->nome_file }}{{ $item->tipo ?? '-' }}{{ $item->nome }}{{ $item->contatti->count() }} + @if($item->attiva) + Attiva + @else + Disattiva + @endif +
+
+
+ @endif + @endforeach + + @if(array_sum($totals) === 0) +
+ Nessun elemento trovato con tutti i tag selezionati. +
+ @endif + + + @endisset +
+
+@endsection \ No newline at end of file