['except' => ''], 'filtroStato' => ['except' => ''], ]; public function updatingSearch() { $this->resetPage(); } public function updatingFiltroStato() { $this->resetPage(); } public function sortBy(string $field) { if ($this->sortField === $field) { $this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc'; } else { $this->sortField = $field; $this->sortDirection = 'asc'; } } public function toggleActive(int $id) { // La lista è in sola lettura per i non-admin: creare/modificare/ // eliminare proclamatori è riservato all'amministratore. Il check sta // nel metodo perché la rotta index resta accessibile con // proclamatori.manage. $this->authorize('settings.manage'); $proclamatore = Proclamatore::findOrFail($id); $proclamatore->update(['attivo' => !$proclamatore->attivo]); } public function deleteProclamatore(int $id) { $this->authorize('settings.manage'); $proclamatore = Proclamatore::findOrFail($id); if ($proclamatore->assegnazioni()->aperte()->exists()) { $this->avvisaErrore("Il proclamatore {$proclamatore->nome_completo} ha assegnazioni aperte. Rientra prima i territori."); return; } if ($this->sorveglianteDiUnGruppo($proclamatore, 'spostarlo nel cestino')) { return; } // Nel cestino non resta membro di un gruppo. $proclamatore->update(['gruppo_servizio_id' => null]); $proclamatore->delete(); $this->avvisa("Proclamatore {$proclamatore->nome_completo} spostato nel cestino."); } public function anonimizza(int $id) { $this->authorize('settings.manage'); $proclamatore = Proclamatore::findOrFail($id); if ($this->sorveglianteDiUnGruppo($proclamatore, 'anonimizzarlo')) { return; } $proclamatore->anonimizza(); $this->avvisa("Dati personali del proclamatore anonimizzati (GDPR)."); } /** Il sorvegliante di un gruppo attivo si toglie sciogliendo il gruppo, non da qui. */ private function sorveglianteDiUnGruppo(Proclamatore $proclamatore, string $azione): bool { $gruppo = GruppoServizio::attivi()->where('sorvegliante_id', $proclamatore->id)->first(); if (! $gruppo) { return false; } $this->avvisaErrore("{$proclamatore->nome_completo} è il sorvegliante del gruppo {$gruppo->nome}: per {$azione} va prima sciolto il gruppo (Gruppi di servizio)."); return true; } public function render() { // withCount rather than letting the view call // ->assegnazioni()->aperte()->count() per row, which issued one // COUNT(*) per displayed proclamatore on every render. $query = Proclamatore::query()->withCount([ 'assegnazioni as assegnazioni_aperte_count' => fn ($q) => $q->whereNull('returned_at'), ]); if ($this->search !== '') { // In-memory filter because nome/cognome are encrypted $all = $query->get(); $filtered = $all->filter(function ($p) { return str_contains( mb_strtolower($p->nome . ' ' . $p->cognome), mb_strtolower($this->search) ); }); if ($this->filtroStato === 'attivo') { $filtered = $filtered->where('attivo', true); } elseif ($this->filtroStato === 'inattivo') { $filtered = $filtered->where('attivo', false); } // Sort in-memory $filtered = $filtered->sortBy(function ($p) { return match ($this->sortField) { 'nome' => mb_strtolower($p->nome), 'cognome' => mb_strtolower($p->cognome), default => mb_strtolower($p->cognome), }; }, SORT_REGULAR, $this->sortDirection === 'desc'); // Manual pagination $page = $this->getPage(); $perPage = 20; $items = $filtered->slice(($page - 1) * $perPage, $perPage)->values(); $proclamatori = new \Illuminate\Pagination\LengthAwarePaginator( $items, $filtered->count(), $perPage, $page, ['path' => request()->url()] ); } else { if ($this->filtroStato === 'attivo') { $query->where('attivo', true); } elseif ($this->filtroStato === 'inattivo') { $query->where('attivo', false); } // cognome/nome encrypted, so sort in-memory $all = $query->get()->sortBy(function ($p) { return match ($this->sortField) { 'nome' => mb_strtolower($p->nome), 'cognome' => mb_strtolower($p->cognome), default => mb_strtolower($p->cognome), }; }, SORT_REGULAR, $this->sortDirection === 'desc'); $page = $this->getPage(); $perPage = 20; $items = $all->slice(($page - 1) * $perPage, $perPage)->values(); $proclamatori = new \Illuminate\Pagination\LengthAwarePaginator( $items, $all->count(), $perPage, $page, ['path' => request()->url()] ); } return view('livewire.proclamatori.proclamatore-index', [ 'proclamatori' => $proclamatori, ]); } }