++ scelta di territori e proclamatori con ricerca

Al posto delle tendine (Assegna, Registro, editor delle piantine) un
campo in cui si scrive e compaiono le proposte più vicine: uguale, inizia
con, contiene, errore di battitura ("forse cercavi"); parole in qualsiasi
ordine, senza badare a maiuscole e accenti. Campo vuoto: la tendina
completa. Fatto anche per il telefono (16px, voci da 44px, scelta al tocco).

- Logica pura in resources/js/scelta.js con test node (tests/js).
- Opzioni dal server: Territorio/Proclamatore::opzioneScelta(); i
  territori già assegnati si trovano ("già assegnato a …") ma non si
  scelgono. Nomi cifrati ordinati e cercati decifrati, mai in SQL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Francesco Picone
2026-10-19 15:35:56 +02:00
parent 2873424c3c
commit fda428f242
16 changed files with 814 additions and 76 deletions

View File

@@ -40,7 +40,6 @@ class Assegna extends Component
public ?int $territorio_id = null;
public ?int $proclamatore_id = null;
public string $assigned_at = '';
public string $territorioSearch = '';
public string $linkSearch = '';
// Optional pre-selection from parent context
@@ -270,26 +269,20 @@ class Assegna extends Component
public function render()
{
$territoriQuery = Territorio::where('attivo', true)
->whereDoesntHave('assegnazioni', fn($q) => $q->aperte())
->with(['zona', 'tipologia']);
if (trim($this->territorioSearch) !== '') {
$term = trim($this->territorioSearch);
$territoriQuery->where(function ($q) use ($term) {
$q->where('numero', 'like', "%{$term}%")
->orWhereHas('zona', fn($z) => $z->where('nome', 'like', "%{$term}%"))
->orWhereHas('tipologia', fn($t) => $t->where('nome', 'like', "%{$term}%"));
});
}
$territoriDisponibili = $territoriQuery
->orderBy('numero')
->get();
$proclamatoriAttivi = Proclamatore::attivi()
// Le opzioni dei campi di scelta con ricerca (<x-scelta>). Ci sono anche
// i territori già assegnati, che non si possono scegliere: cercandone
// uno si legge a chi è, invece di un "nessun risultato".
$opzioniTerritori = Territorio::attivi()
->with(['zona', 'tipologia', 'assegnazioneCorrente.proclamatore'])
->get()
->sortBy(fn($p) => mb_strtolower($p->cognome . ' ' . $p->nome));
->sortBy('numero', SORT_NATURAL)
->map(fn (Territorio $t) => $t->opzioneScelta(
$t->assegnazioneCorrente ? 'già assegnato a ' . ($t->assegnazioneCorrente->proclamatore?->nome_completo ?? '—') : null
))
->values()
->all();
$opzioniProclamatori = Proclamatore::opzioniScelta(Proclamatore::attivi()->get());
// All currently assigned territories with links
$assegnazioniAperte = Assegnazione::aperte()
@@ -326,8 +319,8 @@ class Assegna extends Component
return view('livewire.assegnazioni.assegna', [
'invio' => $invio,
'postaAttiva' => $invio ? app(ConfigurazionePosta::class)->funzionante() : false,
'territoriDisponibili' => $territoriDisponibili,
'proclamatoriAttivi' => $proclamatoriAttivi,
'opzioniTerritori' => $opzioniTerritori,
'opzioniProclamatori' => $opzioniProclamatori,
'assegnazioniAperte' => $assegnazioniAperte,
'assegnazioniAperteVisibili' => $assegnazioniAperteVisibili,
'sogliaRientro' => $sogliaRientro,