++ Richieste dal modulo pubblico, territori cartacei, S-13 mensile per email

- /richiesta: modulo pubblico (nuovo territorio o riconsegna) con campo
  trappola, tempo minimo e limite orario; nome e note cifrati, avviso per
  email a chi ha richieste.gestisci (amministratore, assistente)
- Home: riquadro Richieste con i proclamatori dal nome simile; porta su
  Assegna/Rientra già esistenti, che chiudono la richiesta; Scarta
- Cartaceo sull'assegnazione (Assegna e Il mio gruppo), etichetta
  nell'elenco degli assegnati, pagina Cartacei, passa per l'XML
- registro:invia-s13 agli amministratori l'ultima domenica del mese;
  richieste:pulizia dopo 90 giorni dalla gestione
- Privacy, README e HANDOFF aggiornati; test in RichiesteTest

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Francesco Picone
2026-10-21 17:32:09 +02:00
parent 5e40f0fe74
commit 7904c96db8
36 changed files with 1563 additions and 24 deletions

View File

@@ -1805,6 +1805,12 @@ html { scroll-behavior: smooth; }
}
.tm-assegnato-numero { color: #4f46e5; font-size: 14px; font-weight: 700; }
.tm-assegnato-numero:hover { text-decoration: underline; }
/* Campo trappola del modulo pubblico delle richieste: fuori dallo schermo,
non `display:none` (alcuni programmi saltano i campi nascosti così). */
.tm-trappola {
position: absolute; left: -10000px; top: auto;
width: 1px; height: 1px; overflow: hidden;
}
/* Il numero come pulsante ("Il mio gruppo": apre l'anteprima): stesso aspetto. */
button.tm-assegnato-numero {
background: none; border: 0; padding: 0; cursor: pointer;
@@ -1817,6 +1823,11 @@ button.tm-assegnato-numero:focus-visible {
margin-left: 6px; padding: 2px 6px; border-radius: 4px;
background: #f3f4f6; color: #9ca3af; font-size: 12px;
}
/* Il proclamatore ha chiesto la cartolina cartacea (elenco Cartacei). */
.tm-cartaceo {
margin-left: 4px; padding: 2px 6px; border-radius: 4px;
background: #fffbeb; color: #b45309; font-size: 12px; font-weight: 600;
}
.tm-assegnato-info { color: #6b7280; font-size: 12px; }
.tm-assegnato-info b { color: #1f2937; font-size: 14px; font-weight: 500; }
.tm-assegnato-giorni {

View File

@@ -120,6 +120,11 @@
<svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/></svg>
Assegnazioni
</a>
<a href="{{ route('assegnazioni.cartacei') }}"
class="flex items-center gap-3 px-3 py-2.5 text-sm font-medium rounded-lg transition-all duration-150 {{ request()->routeIs('assegnazioni.cartacei') ? 'sidebar-active' : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900' }}">
<svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/></svg>
Cartacei
</a>
@endcan
@can('campagne.manage')

View File

@@ -26,6 +26,13 @@
{{-- Form --}}
<div x-show="formOpen" x-cloak class="bg-white rounded-xl shadow-sm border border-gray-200 p-4 sm:p-6 mb-6 max-w-3xl">
@if($richiesta)
{{-- Partita da una richiesta del modulo pubblico (Home): assegnando, risulta evasa. --}}
<div class="mb-4 rounded-lg border border-indigo-100 bg-indigo-50 px-4 py-3 text-sm text-indigo-900" role="status">
Richiesta di <strong>{{ $richiesta->nome }}</strong> del {{ $richiesta->created_at->format('d/m/Y') }}@if($richiesta->note): «{{ $richiesta->note }}»@endif.
Assegnando il territorio, la richiesta risulta evasa.
</div>
@endif
<form wire:submit="save" class="space-y-4">
{{-- L'anteprima segue la scelta nel browser (evento "scelta" di
<x-scelta>, miniatura nelle opzioni): scegliere un
@@ -65,6 +72,12 @@
@error('assigned_at') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<label class="flex items-center gap-2 text-sm text-gray-700">
<input wire:model="cartaceo" type="checkbox" class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500">
Ha chiesto la cartolina cartacea
<a href="{{ route('assegnazioni.cartacei') }}" class="text-xs text-indigo-600 hover:underline">(vedi i cartacei fuori)</a>
</label>
<div class="flex flex-col-reverse gap-3 pt-4 sm:flex-row sm:items-center">
<x-btn variante="primary" type="submit">Assegna</x-btn>
@if($ritorno)

View File

@@ -0,0 +1,47 @@
<div>
<div class="mb-6">
<h1 class="text-2xl font-bold text-gray-900">Territori cartacei</h1>
<p class="text-sm text-gray-500 mt-1">
Le cartoline cartacee fuori e a chi: territori assegnati per cui il proclamatore ha chiesto il cartaceo.
Al rientro escono dall'elenco.
</p>
</div>
<div class="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden">
@if($assegnazioni->isEmpty())
<p class="px-5 py-8 text-center text-sm text-gray-500">Nessun territorio cartaceo fuori.</p>
@else
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200 text-sm table-cards">
<thead class="bg-gray-50">
<tr>
<th class="px-4 py-3 text-left text-xs font-semibold text-gray-600 uppercase">Territorio</th>
<th class="px-4 py-3 text-left text-xs font-semibold text-gray-600 uppercase">Proclamatore</th>
<th class="px-4 py-3 text-left text-xs font-semibold text-gray-600 uppercase">Dal</th>
<th class="px-4 py-3 text-right text-xs font-semibold text-gray-600 uppercase">Giorni</th>
<th class="px-4 py-3"></th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100">
@foreach($assegnazioni as $a)
<tr wire:key="cartaceo-{{ $a->id }}">
<td data-label="Territorio" class="px-4 py-3">
<a data-ritorno href="{{ route('territori.show', $a->territorio_id) }}" class="font-semibold text-indigo-600 hover:underline">N° {{ $a->territorio?->numero }}</a>
<span class="text-gray-500">{{ $a->territorio?->zona?->nome }}</span>
</td>
<td data-label="Proclamatore" class="px-4 py-3">{{ $a->proclamatore?->nome_completo }}</td>
<td data-label="Dal" class="px-4 py-3 tabular-nums">{{ $a->assigned_at->format('d/m/Y') }}</td>
<td data-label="Giorni" class="px-4 py-3 text-right tabular-nums">{{ $a->giorni }}</td>
<td class="px-4 py-3 text-right cell-actions">
@can('territori.return')
<x-btn data-ritorno variante="primary" tono="tenue" dimensione="sm" :href="route('assegnazioni.rientra', $a)">Rientro</x-btn>
@endcan
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endif
</div>
</div>

View File

@@ -45,7 +45,7 @@
(data-ritorno); indirizzo relativo e niente a capo: pesa meno. --}}
<div wire:key="assegnato-{{ $a->id }}" data-cerca="{{ $cerca[$a->id] }}" x-show="corrisponde($el.dataset.cerca)" class="tm-assegnato">
<div class="tm-assegnato-testa">
<span><a data-ritorno href="{{ route('territori.show', $a->territorio_id) }}" class="tm-assegnato-numero">N° {{ $a->territorio?->numero }}</a> @if($a->territorio?->zona?->nome)<span class="tm-assegnato-zona">{{ $a->territorio->zona->nome }}</span>@endif</span>
<span><a data-ritorno href="{{ route('territori.show', $a->territorio_id) }}" class="tm-assegnato-numero">N° {{ $a->territorio?->numero }}</a> @if($a->territorio?->zona?->nome)<span class="tm-assegnato-zona">{{ $a->territorio->zona->nome }}</span>@endif @if($a->cartaceo)<span class="tm-cartaceo">cartaceo</span>@endif</span>
<span class="tm-assegnato-info"><b>{{ $nome }}</b> · {{ $a->assigned_at->format('d/m/Y') }} · <span class="tm-assegnato-giorni {{ $a->giorni > 120 ? 'tm-g-tardi' : ($a->giorni > 90 ? 'tm-g-presto' : '') }}">{{ $a->giorni }}g</span></span>
</div>
@if($a->link_in_sospeso)

View File

@@ -7,6 +7,13 @@
<h1 class="text-2xl font-bold text-gray-900">Rientro Territorio</h1>
</div>
@if($richiesta)
{{-- Partito da una richiesta di riconsegna (Home): registrando il rientro, risulta evasa. --}}
<div class="mb-4 rounded-lg border border-indigo-100 bg-indigo-50 px-4 py-3 text-sm text-indigo-900 max-w-lg" role="status">
Riconsegna annunciata da <strong>{{ $richiesta->nome }}</strong> il {{ $richiesta->created_at->format('d/m/Y') }}@if($richiesta->note): «{{ $richiesta->note }}»@endif.
</div>
@endif
{{-- Assignment summary --}}
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-4 mb-6">
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">

View File

@@ -89,7 +89,7 @@
data-miniatura="{{ $t->miniaturaGruppoUrl() }}"
data-pdf="{{ $t->pdf_path ? route('mio-gruppo.pdf', $t) : '' }}"
x-on:click="anteprima = { titolo: $el.dataset.titolo, miniatura: $el.dataset.miniatura, pdf: $el.dataset.pdf }">N° {{ $t->numero }}</button>@else<span class="tm-assegnato-numero">N° {{ $t->numero }}</span>@endif @if($t->zona?->nome)<span class="tm-assegnato-zona">{{ $t->zona->nome }}</span>@endif
@if($t->in_priorita)<span class="ml-1 inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide" style="background:#fef3c7;color:#92400e">★ Prioritario</span>@endif</span>
@if($t->in_priorita)<span class="ml-1 inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide" style="background:#fef3c7;color:#92400e">★ Prioritario</span>@endif @if($a?->cartaceo)<span class="tm-cartaceo">cartaceo</span>@endif</span>
@if($a)
<span class="tm-assegnato-info"><b>{{ $a->proclamatore?->nome_completo }}</b> · dal {{ $a->assigned_at->format('d/m/Y') }} · <span class="tm-assegnato-giorni {{ $a->giorni > 120 ? 'tm-g-tardi' : ($a->giorni > 90 ? 'tm-g-presto' : '') }}">{{ $a->giorni }}g</span></span>
@else
@@ -126,6 +126,10 @@
class="block w-full rounded-lg border-gray-300 text-base sm:text-sm focus:ring-indigo-500 focus:border-indigo-500">
@error('dataAssegnazione') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
</div>
<label class="flex items-center gap-2 text-sm text-gray-700">
<input wire:model="cartaceo" type="checkbox" class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500">
Ha chiesto la cartolina cartacea
</label>
<div class="flex flex-wrap gap-2">
<x-btn variante="primary" wire:click="assegna">Assegna</x-btn>
<x-btn variante="ghost" wire:click="annullaAssegnazione">Annulla</x-btn>

View File

@@ -78,6 +78,61 @@
@endif
</div>
{{-- Richieste dal modulo pubblico: si confermano portandole sul modulo
di assegnazione o di rientro, che le chiude da solo. --}}
@can('richieste.gestisci')
<section class="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden mb-6" aria-labelledby="titolo-richieste">
<div class="px-5 py-4 border-b flex flex-wrap items-center gap-3" style="background:linear-gradient(135deg,#eef2ff,#e0e7ff);border-color:#c7d2fe">
<div>
<h3 id="titolo-richieste" class="text-sm font-semibold" style="color:#3730a3">Richieste ({{ $richieste->count() }})</h3>
<p class="text-xs" style="color:#4f46e5">Dal modulo pubblico: <code class="select-all">{{ route('richiesta') }}</code></p>
</div>
</div>
@forelse($richieste as $voce)
@php
$r = $voce['richiesta'];
$a = $voce['assegnazione'];
@endphp
<div class="px-5 py-4 border-b border-gray-100 last:border-b-0" wire:key="richiesta-{{ $r->id }}">
<div class="flex flex-wrap items-baseline justify-between gap-2">
<p class="text-sm text-gray-900">
<span class="inline-flex rounded-full px-2 py-0.5 text-xs font-medium {{ $r->tipo === \App\Models\Richiesta::RICONSEGNA ? 'bg-amber-50 text-amber-800' : 'bg-indigo-50 text-indigo-700' }}">{{ $r->tipo_etichetta }}</span>
<strong class="ml-1">{{ $r->nome }}</strong>
@if($r->numero_territorio) · territorio N° {{ $r->numero_territorio }} @endif
</p>
<span class="text-xs text-gray-500">{{ $r->created_at->format('d/m/Y H:i') }}</span>
</div>
@if($r->note)
<p class="mt-1 text-sm text-gray-600 italic">«{{ $r->note }}»</p>
@endif
<div class="mt-3 flex flex-wrap items-center gap-2">
@if($r->tipo === \App\Models\Richiesta::NUOVO)
<span class="text-xs text-gray-500">{{ $voce['simili']->isNotEmpty() ? 'Chi è? Assegna a:' : 'Nessun proclamatore con un nome simile.' }}</span>
@foreach($voce['simili'] as $p)
<x-btn data-ritorno variante="secondary" tono="tenue" dimensione="sm"
:href="route('assegnazioni.assegna', ['proclamatore' => $p->id, 'richiesta' => $r->id, 'dalla_home' => 1])">{{ $p->nome_completo }} →</x-btn>
@endforeach
<x-btn data-ritorno variante="ghost" dimensione="sm"
:href="route('assegnazioni.assegna', ['richiesta' => $r->id, 'dalla_home' => 1])">{{ $voce['simili']->isNotEmpty() ? 'Nessuno di questi: apri il modulo' : 'Apri il modulo' }}</x-btn>
@elseif($a)
<span class="text-xs text-gray-500">Assegnato a <strong>{{ $a->proclamatore?->nome_completo }}</strong> dal {{ $a->assigned_at->format('d/m/Y') }}</span>
<x-btn data-ritorno variante="primary" tono="tenue" dimensione="sm"
:href="route('assegnazioni.rientra', ['assegnazione' => $a->id, 'richiesta' => $r->id])">Registra rientro →</x-btn>
@else
<span class="text-xs text-amber-800">Il territorio N° {{ $r->numero_territorio }} non risulta assegnato.</span>
@endif
<x-btn variante="danger" tono="tenue" dimensione="sm" class="ml-auto"
wire:click="scartaRichiesta({{ $r->id }})"
wire:confirm="Scartare la richiesta di {{ $r->nome }}?">Scarta</x-btn>
</div>
</div>
@empty
<p class="px-5 py-4 text-sm text-gray-500">Nessuna richiesta aperta.</p>
@endforelse
</section>
@endcan
{{-- Quick lists --}}
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
{{-- Da assegnare --}}

View File

@@ -18,7 +18,8 @@
<ul class="list-disc list-inside space-y-1">
<li><strong>Proclamatori</strong>: solo nome e cognome, cifrati nel database ({{ $cifratura }}), se sono attivi e l'eventuale gruppo di servizio di cui fanno parte. Nessun numero di telefono né indirizzo email.</li>
<li><strong>Territori e piantine</strong>: numero, zona, tipologia, confini, mappe e PDF — nessun dato personale.</li>
<li><strong>Assegnazioni</strong>: collegamento tra proclamatore e territorio, con date di assegnazione e rientro, conteggio nelle campagne, codice del link alla piantina, stato del suo invio (inviato o no, e con quale canale) e, se l'ha data il sorvegliante di un gruppo di servizio, il nome del gruppo.</li>
<li><strong>Assegnazioni</strong>: collegamento tra proclamatore e territorio, con date di assegnazione e rientro, conteggio nelle campagne, codice del link alla piantina, stato del suo invio (inviato o no, e con quale canale) se il proclamatore ha chiesto la cartolina cartacea e, se l'ha data il sorvegliante di un gruppo di servizio, il nome del gruppo.</li>
<li><strong>Richieste dal modulo pubblico</strong>: chi chiede un territorio o ne annuncia la riconsegna scrive il proprio nome, l'eventuale numero del territorio e una nota. Nome e nota sono cifrati nel database ({{ $cifratura }}) e non finiscono nel registro delle attività. Dell'indirizzo IP resta solo un'impronta temporanea, per limitare i tentativi.</li>
<li><strong>Utenti dell'applicazione</strong>: nome, email (che va confermata), password conservata solo come impronta non reversibile, ruolo. Il sorvegliante di un gruppo di servizio entra con un'email fittizia creata dall'applicazione (iniziale del nome e cognome), che non riceve posta e non va confermata. La sua utenza è collegata al suo proclamatore e viene eliminata quando il gruppo si scioglie; anche il gruppo, sciolto, viene eliminato.</li>
<li><strong>Registro delle attività</strong>: chi ha fatto cosa e quando. I proclamatori vi compaiono solo con un identificativo numerico, mai con il nome.</li>
</ul>
@@ -29,6 +30,7 @@
<ul class="list-disc list-inside space-y-1">
<li>{{ $conteggi['proclamatori'] }} proclamatori, di cui {{ $conteggi['proclamatoriAttivi'] }} attivi; {{ $conteggi['anonimizzati'] }} nel cestino o anonimizzati.</li>
<li>{{ $conteggi['assegnazioni'] }} assegnazioni nello storico, di cui {{ $conteggi['assegnazioniAperte'] }} in corso.</li>
<li>{{ $conteggi['richieste'] }} richieste dal modulo pubblico, di cui {{ $conteggi['richiesteAperte'] }} da gestire.</li>
<li>{{ $conteggi['utenti'] }} utenti dell'applicazione.</li>
<li>{{ $conteggi['attivita'] }} voci nel registro delle attività@if($conteggi['attivitaDal']), dal {{ \Illuminate\Support\Carbon::parse($conteggi['attivitaDal'])->format('d/m/Y') }}@endif.</li>
</ul>
@@ -59,6 +61,7 @@
@endforeach
</ul>
<p class="mt-2">Il proclamatore non ha un account: riceve solo il link alla piantina del territorio che gli è assegnato. Fa eccezione il sorvegliante di un gruppo di servizio, che ha un'utenza (email fittizia e password) con cui vede solo il proprio gruppo: i territori del suo pacchetto e i nomi dei membri.</p>
<p class="mt-2">Il modulo pubblico di richiesta non mostra nessun dato: chi lo compila scrive soltanto. Le richieste le vedono e le gestiscono, dalla Home, solo i ruoli con il permesso sulle richieste.</p>
</section>
<section>
@@ -67,6 +70,7 @@
<li><strong>Cifratura</strong>: nome e cognome dei proclamatori sono cifrati con {{ $cifratura }} prima di essere salvati; la chiave non sta nel database.</li>
<li><strong>Accesso</strong>: password personale, conferma dell'email, blocco temporaneo dopo troppi tentativi; la sessione scade dopo {{ $durataSessione }} minuti di inattività.</li>
<li><strong>Permessi</strong>: ogni ruolo vede e modifica solo ciò che gli serve (vedi sopra).</li>
<li><strong>Modulo pubblico</strong>: protetto dallo spam con un campo trappola, un tempo minimo di compilazione e un limite di richieste per indirizzo.</li>
<li><strong>Registro delle attività</strong>: le operazioni sono registrate e conservate per {{ $auditRetention }} giorni.</li>
<li><strong>Comunicazioni</strong>: l'applicazione risponde all'indirizzo <code>{{ $indirizzo }}</code>@if($https), su connessione cifrata (HTTPS)@else. <span class="text-red-700 font-medium">Attenzione: l'indirizzo non usa HTTPS, le comunicazioni non sono cifrate.</span>@endif.</li>
<li><strong>Hosting</strong>: i dati risiedono sul server gestito dagli amministratori dell'applicazione, non su servizi cloud di terze parti.</li>
@@ -88,7 +92,7 @@
<li><strong>Condivisione del link</strong>: il messaggio con il nome del proclamatore e il link passa per l'app scelta da chi assegna il territorio (WhatsApp, Telegram, SMS…), dal suo telefono, non dall'applicazione.</li>
<li><strong>Posta</strong>:
@if($postaAttiva)
le email agli utenti dell'applicazione (conferma dell'indirizzo) partono dal server di posta <code>{{ $hostPosta ?? 'configurato' }}</code>. Ai proclamatori non si mandano email.
le email agli utenti dell'applicazione partono dal server di posta <code>{{ $hostPosta ?? 'configurato' }}</code>: conferma dell'indirizzo, avviso di una nuova richiesta dal modulo pubblico a chi le gestisce, e il modulo S-13 (registro delle assegnazioni, in PDF) agli amministratori l'ultima domenica del mese. Ai proclamatori non si mandano email.
@else
nessun server di posta configurato: l'applicazione non invia email. Ai proclamatori non se ne mandano comunque.
@endif
@@ -104,6 +108,7 @@
<li>Territori e proclamatori eliminati restano nel cestino finché non vengono eliminati definitivamente.</li>
<li>Il registro delle attività è conservato per <strong>{{ $auditRetention }} giorni</strong> (modificabile nelle impostazioni), poi cancellato automaticamente.</li>
<li>Lo storico delle assegnazioni è conservato per la durata necessaria alla gestione territoriale.</li>
<li>Le richieste dal modulo pubblico sono cancellate automaticamente <strong>{{ \App\Console\Commands\PuliziaRichieste::GIORNI }} giorni</strong> dopo essere state gestite.</li>
<li>I backup e gli export XML scaricati dagli amministratori contengono nome e cognome dei proclamatori <strong>in chiaro</strong>: vanno custoditi in un luogo protetto e cancellati quando non servono più.</li>
</ul>
</section>

View File

@@ -0,0 +1,74 @@
<div class="bg-white shadow-xl rounded-2xl p-6 sm:p-8 my-8" style="border-top:4px solid #6366f1">
{{-- Modulo pubblico (ModuloRichiesta): nessun dato già presente si vede
qui, solo i campi da compilare. --}}
<div class="text-center mb-6">
<div class="mx-auto h-14 w-14 rounded-xl flex items-center justify-center text-white font-bold text-xl mb-4 shadow-lg" style="background:linear-gradient(135deg,#4338ca,#6366f1)">T2</div>
<h1 class="text-2xl font-bold text-gray-900">Richiesta territorio</h1>
<p class="text-gray-500 text-sm mt-1">{{ $congregazione }}</p>
</div>
@if($inviata)
<div class="rounded-lg bg-green-50 border border-green-200 px-4 py-3 text-sm text-green-800" role="status">
<p class="font-semibold">Richiesta inviata.</p>
<p class="mt-1">Il responsabile dei territori la vedrà e ti farà sapere.</p>
</div>
<div class="mt-5 text-center">
<x-btn variante="secondary" wire:click="nuova">Fai un'altra richiesta</x-btn>
</div>
@else
<form wire:submit="invia" class="space-y-5">
<fieldset>
<legend class="block text-sm font-medium text-gray-700 mb-2">Cosa ti serve? *</legend>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2">
<label class="flex items-center gap-2 rounded-lg border border-gray-200 px-3 py-3 text-sm cursor-pointer has-[:checked]:border-indigo-400 has-[:checked]:bg-indigo-50">
<input type="radio" wire:model.live="tipo" value="{{ \App\Models\Richiesta::NUOVO }}" class="h-4 w-4 text-indigo-600">
Chiedo un territorio nuovo
</label>
<label class="flex items-center gap-2 rounded-lg border border-gray-200 px-3 py-3 text-sm cursor-pointer has-[:checked]:border-indigo-400 has-[:checked]:bg-indigo-50">
<input type="radio" wire:model.live="tipo" value="{{ \App\Models\Richiesta::RICONSEGNA }}" class="h-4 w-4 text-indigo-600">
Riconsegno un territorio
</label>
</div>
</fieldset>
<div>
<label for="nome" class="block text-sm font-medium text-gray-700">Nome e cognome *</label>
<input wire:model="nome" type="text" id="nome" autocomplete="name" maxlength="100"
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 text-base sm:text-sm px-4 py-2.5">
@error('nome') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
@if($tipo === \App\Models\Richiesta::RICONSEGNA)
<div>
<label for="numero" class="block text-sm font-medium text-gray-700">N° del territorio *</label>
<input wire:model="numero" type="text" id="numero" inputmode="numeric" maxlength="20" autocomplete="off"
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 text-base sm:text-sm px-4 py-2.5">
@error('numero') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
@endif
<div>
<label for="note" class="block text-sm font-medium text-gray-700">
{{ $tipo === \App\Models\Richiesta::RICONSEGNA ? 'Note' : 'Esigenze particolari / note' }}
</label>
<textarea wire:model="note" id="note" rows="3" maxlength="1000"
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 text-base sm:text-sm px-4 py-2.5"></textarea>
@error('note') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
</div>
{{-- Trappola per i programmi che riempiono ogni campo: nascosta a chi
guarda e ai lettori di schermo. --}}
<div class="tm-trappola" aria-hidden="true">
<label for="sito">Lascia vuoto questo campo</label>
<input wire:model="sito" type="text" id="sito" tabindex="-1" autocomplete="off">
</div>
<x-btn variante="primary" type="submit" class="w-full">Invia la richiesta</x-btn>
<p class="text-xs text-gray-500">
Nome e note servono solo a gestire questa richiesta: li vedono il responsabile dei territori e i suoi
assistenti, e vengono cancellati {{ \App\Console\Commands\PuliziaRichieste::GIORNI }} giorni dopo che la richiesta è stata gestita.
</p>
</form>
@endif
</div>

View File

@@ -0,0 +1,7 @@
Ciao {!! $utente->name !!},
in allegato il modulo S-13 (registro di assegnazione dei territori) dell'anno di servizio {!! $anno->label !!}, aggiornato al {!! $data !!}.
Lo manda TerManager2 l'ultima domenica di ogni mese agli amministratori.
TerManager2