++ gruppi: il gruppo sciolto si elimina; il sorvegliante entra con un nome utente dal nome del gruppo
- Sciolto, il gruppo non resta nello storico: si elimina (via sciolto_at;
la migrazione elimina anche quelli gia' sciolti). I territori solo nel
pacchetto tornano in reparto; quelli gia' dati restano ai membri, e
l'assegnazione conserva il nome del gruppo (assegnazioni.gruppo_nome).
- Creando il gruppo non si chiede l'email: users.username dal nome del
gruppo ("Gruppo Zisa" -> gruppo.zisa), users.email facoltativa. Login con
"Email o nome utente". Nome del gruppo unico.
- Sciolto il gruppo il nome utente si libera (l'utenza disattivata prende
ex.sorvegliante.<id>). XML: nome utente e gruppo_nome.
- Profilo, testata, cambio password e Utenti mostrano il nome utente dove
manca l'email. Informativa privacy, README, HANDOFF e test aggiornati.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
{{ $forced ? 'Imposta una nuova password' : 'Cambia password' }}
|
||||
</h1>
|
||||
<p class="mt-1 text-sm text-gray-500">
|
||||
Account: <span class="font-medium text-gray-700 break-all">{{ $user->email }}</span>
|
||||
Account: <span class="font-medium text-gray-700 break-all">{{ $user->identificativo }}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
{{-- L'email in un campo nascosto: senza, i gestori di password non
|
||||
sanno a quale account associare la credenziale che salvano. --}}
|
||||
<input type="hidden" name="email" autocomplete="username" value="{{ $user->email }}">
|
||||
<input type="hidden" name="email" autocomplete="username" value="{{ $user->identificativo }}">
|
||||
|
||||
@unless($forced)
|
||||
{{-- Dopo un ripristino non si chiede: la password attuale e'
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true" style="width:20px;height:20px;opacity:.75"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/></svg>
|
||||
<span class="flex flex-col leading-tight text-left">
|
||||
<span class="text-sm font-medium">{{ auth()->user()->name }}</span>
|
||||
<span class="text-xs" style="opacity:.7">{{ auth()->user()->email }} · {{ ucfirst(auth()->user()->roles->first()?->name ?? 'utente') }}</span>
|
||||
<span class="text-xs" style="opacity:.7">{{ auth()->user()->identificativo }} · {{ ucfirst(auth()->user()->roles->first()?->name ?? 'utente') }}</span>
|
||||
</span>
|
||||
</x-btn>
|
||||
</div>
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
<form method="POST" action="{{ route('login.store') }}" class="space-y-5">
|
||||
@csrf
|
||||
<div>
|
||||
<label for="email" class="block text-sm font-medium text-gray-700">Email</label>
|
||||
<input name="email" value="{{ old('email') }}" type="email" id="email" autocomplete="email"
|
||||
{{-- Email, o nome utente per il sorvegliante di un gruppo di servizio --}}
|
||||
<label for="email" class="block text-sm font-medium text-gray-700">Email o nome utente</label>
|
||||
<input name="email" value="{{ old('email') }}" type="text" id="email" autocomplete="username"
|
||||
autocapitalize="none" autocorrect="off" spellcheck="false"
|
||||
class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 text-sm px-4 py-2.5">
|
||||
@error('email') <p class="mt-1 text-sm text-red-600">{{ $message }}</p> @enderror
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<p class="mt-1">Consegna queste credenziali a {{ $creato->sorvegliante?->nome_completo }}: la password si vede <strong>solo ora</strong> e al primo accesso va cambiata.</p>
|
||||
<dl class="mt-3 grid grid-cols-[auto_1fr] gap-x-3 gap-y-1">
|
||||
<dt class="text-green-700">Indirizzo</dt><dd><code>{{ route('login') }}</code></dd>
|
||||
<dt class="text-green-700">Email</dt><dd><code>{{ $creato->sorvegliante?->utente?->email }}</code></dd>
|
||||
<dt class="text-green-700">Nome utente</dt><dd><code class="select-all">{{ $creato->sorvegliante?->utente?->username }}</code></dd>
|
||||
<dt class="text-green-700">Password</dt><dd><code class="select-all">{{ $passwordTemporanea }}</code></dd>
|
||||
</dl>
|
||||
<div class="mt-3 flex flex-wrap gap-2">
|
||||
@@ -29,6 +29,7 @@
|
||||
<label for="nome-gruppo" class="block text-sm font-medium text-gray-700 mb-1">Nome del gruppo *</label>
|
||||
<input wire:model="nome" id="nome-gruppo" type="text" placeholder="es. Zisa"
|
||||
class="block w-full rounded-lg border-gray-300 text-base sm:text-sm focus:ring-indigo-500 focus:border-indigo-500">
|
||||
<p class="text-xs text-gray-500 mt-1">Dal nome nasce il nome utente del sorvegliante (es. «Gruppo Zisa» → <code>gruppo.zisa</code>).</p>
|
||||
@error('nome') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
|
||||
</div>
|
||||
<div>
|
||||
@@ -37,13 +38,6 @@
|
||||
<p class="text-xs text-gray-500 mt-1">Un proclamatore attivo che non fa già parte di un gruppo. Diventa anche membro del gruppo.</p>
|
||||
@error('sorveglianteId') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
|
||||
</div>
|
||||
<div>
|
||||
<label for="email-sorvegliante" class="block text-sm font-medium text-gray-700 mb-1">Email per l'accesso *</label>
|
||||
<input wire:model="email" id="email-sorvegliante" type="email" autocomplete="off"
|
||||
class="block w-full rounded-lg border-gray-300 text-base sm:text-sm focus:ring-indigo-500 focus:border-indigo-500">
|
||||
<p class="text-xs text-gray-500 mt-1">Resta solo nell'utenza del sorvegliante (non nel proclamatore) e non va confermata.</p>
|
||||
@error('email') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
|
||||
</div>
|
||||
<x-btn variante="primary" type="submit">Crea il gruppo</x-btn>
|
||||
</form>
|
||||
</section>
|
||||
@@ -55,15 +49,12 @@
|
||||
<li class="px-4 py-3 flex flex-wrap items-center justify-between gap-3">
|
||||
<div>
|
||||
<a data-ritorno href="{{ route('gruppi.show', $g) }}" class="font-semibold text-indigo-600 hover:underline">{{ $g->nome }}</a>
|
||||
@if($g->sciolto_at)
|
||||
<span class="ml-1 inline-flex rounded-full bg-gray-100 px-2 py-0.5 text-xs text-gray-600">sciolto il {{ $g->sciolto_at->format('d/m/Y') }}</span>
|
||||
@endif
|
||||
<p class="text-xs text-gray-500">
|
||||
Sorvegliante: {{ $g->sorvegliante?->nome_completo ?? '—' }}
|
||||
@unless($g->sciolto_at) · {{ $g->membri_count }} membri · {{ $g->territori_count }} territori nel pacchetto @endunless
|
||||
· {{ $g->membri_count }} membri · {{ $g->territori_count }} territori nel pacchetto
|
||||
</p>
|
||||
</div>
|
||||
<x-btn data-ritorno variante="secondary" tono="tenue" dimensione="sm" :href="route('gruppi.show', $g)">{{ $g->sciolto_at ? 'Dettaglio' : 'Gestisci' }}</x-btn>
|
||||
<x-btn data-ritorno variante="secondary" tono="tenue" dimensione="sm" :href="route('gruppi.show', $g)">Gestisci</x-btn>
|
||||
</li>
|
||||
@empty
|
||||
<li class="px-4 py-8 text-center text-sm text-gray-500">Nessun gruppo di servizio.</li>
|
||||
|
||||
@@ -7,15 +7,10 @@
|
||||
<h1 class="text-2xl font-bold text-gray-900">Gruppo {{ $gruppo->nome }}</h1>
|
||||
<p class="text-sm text-gray-500 mt-1">
|
||||
Sorvegliante: <strong>{{ $gruppo->sorvegliante?->nome_completo ?? '—' }}</strong>
|
||||
@if($attivo && $gruppo->sorvegliante?->utente)
|
||||
· accede con <code>{{ $gruppo->sorvegliante->utente->email }}</code>
|
||||
@if($gruppo->sorvegliante?->utente)
|
||||
· nome utente <code class="select-all">{{ $gruppo->sorvegliante->utente->identificativo }}</code>
|
||||
@endif
|
||||
</p>
|
||||
@unless($attivo)
|
||||
<p class="mt-2 inline-flex rounded-full bg-gray-100 px-3 py-1 text-xs text-gray-700">
|
||||
Sciolto il {{ $gruppo->sciolto_at->format('d/m/Y') }} · {{ $assegnazioniDelGruppo }} assegnazioni nate dal gruppo restano nello storico
|
||||
</p>
|
||||
@endunless
|
||||
</div>
|
||||
|
||||
@if($passwordTemporanea)
|
||||
@@ -25,7 +20,6 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($attivo)
|
||||
{{-- ─── Pacchetto ─────────────────────────────────────────── --}}
|
||||
<section class="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden mb-6" aria-labelledby="titolo-pacchetto">
|
||||
<h2 id="titolo-pacchetto" class="px-4 py-3 border-b border-gray-100 text-sm font-semibold text-gray-800">
|
||||
@@ -127,8 +121,7 @@
|
||||
<x-btn variante="secondary" wire:click="nuovaPassword"
|
||||
wire:confirm="Generare una nuova password temporanea per {{ $gruppo->sorvegliante?->nome_completo }}? Quella attuale smette di funzionare.">Nuova password temporanea</x-btn>
|
||||
<x-btn variante="danger" wire:click="sciogli"
|
||||
wire:confirm="Togliere il ruolo di sorvegliante a {{ $gruppo->sorvegliante?->nome_completo }}? Il gruppo si scioglie: i territori non ancora dati tornano in reparto, i membri restano senza gruppo e l'utenza del sorvegliante viene disattivata. Le assegnazioni già fatte restano.">Togli il ruolo e sciogli il gruppo</x-btn>
|
||||
wire:confirm="Togliere il ruolo di sorvegliante a {{ $gruppo->sorvegliante?->nome_completo }}? Il gruppo si scioglie e viene eliminato: i territori non ancora dati tornano in reparto, i membri restano senza gruppo e l'utenza del sorvegliante viene disattivata. Le assegnazioni già fatte restano ai membri.">Togli il ruolo e sciogli il gruppo</x-btn>
|
||||
</div>
|
||||
</section>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@@ -18,8 +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 e stato del suo invio (inviato o no, e con quale canale).</li>
|
||||
<li><strong>Utenti dell'applicazione</strong>: nome, email (che va confermata, tranne per i sorveglianti di gruppo), password conservata solo come impronta non reversibile, ruolo. L'utenza di un sorvegliante è collegata al suo proclamatore e viene disattivata quando il gruppo si scioglie.</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>Utenti dell'applicazione</strong>: nome, email (che va confermata), password conservata solo come impronta non reversibile, ruolo. Il sorvegliante di un gruppo di servizio non ha email: entra con un nome utente ricavato dal nome del gruppo. La sua utenza è collegata al suo proclamatore e viene disattivata quando il gruppo si scioglie; 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>
|
||||
</section>
|
||||
@@ -58,7 +58,7 @@
|
||||
<li><strong>{{ ucfirst($ruolo['nome']) }}</strong>: {{ $ruolo['permessi'] ? implode('; ', $ruolo['permessi']) : 'nessun permesso' }}.</li>
|
||||
@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 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 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 (nome utente e password) con cui vede solo il proprio gruppo: i territori del suo pacchetto e i nomi dei membri.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -100,7 +100,7 @@
|
||||
<section>
|
||||
<h2 class="text-lg font-semibold text-gray-900 mb-2">Conservazione dei dati</h2>
|
||||
<ul class="list-disc list-inside space-y-1">
|
||||
<li>I dati di un proclamatore possono essere anonimizzati su richiesta: nome e cognome vengono cancellati in modo irreversibile, insieme a nome ed email dell'utenza se è stato sorvegliante di un gruppo.</li>
|
||||
<li>I dati di un proclamatore possono essere anonimizzati su richiesta: nome e cognome vengono cancellati in modo irreversibile, insieme al nome dell'utenza se è stato sorvegliante di un gruppo.</li>
|
||||
<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>
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
</div>
|
||||
|
||||
{{-- Gruppo di servizio --}}
|
||||
@if($gruppoSorvegliato || $gruppoMembro || $gruppiPassati->isNotEmpty())
|
||||
@if($gruppoSorvegliato || $gruppoMembro)
|
||||
<section class="bg-white rounded-xl shadow-sm border border-gray-200 p-6 mb-6" aria-labelledby="titolo-gruppo">
|
||||
<h3 id="titolo-gruppo" class="text-lg font-semibold text-gray-900 mb-3">Gruppo di servizio</h3>
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
@if($utenza)
|
||||
<p class="mt-4 border-t border-gray-100 pt-3 text-sm text-gray-600">
|
||||
Utenza
|
||||
@can('settings.manage') <code>{{ $utenza->email }}</code> @endcan
|
||||
@can('settings.manage') <code>{{ $utenza->identificativo }}</code> @endcan
|
||||
· {{ $utenza->password_change_required ? 'password temporanea, ancora da cambiare' : 'password personale impostata' }}
|
||||
· {{ $ultimoAccesso ? 'ultimo accesso il ' . \Illuminate\Support\Carbon::parse($ultimoAccesso)->format('d/m/Y H:i') : 'non è ancora entrato' }}
|
||||
</p>
|
||||
@@ -94,15 +94,6 @@
|
||||
sorvegliante {{ $gruppoMembro->sorvegliante?->nome_completo ?? '—' }}.
|
||||
</p>
|
||||
@endif
|
||||
|
||||
@if($gruppiPassati->isNotEmpty())
|
||||
<p class="{{ $gruppoSorvegliato || $gruppoMembro ? 'mt-3' : '' }} text-xs text-gray-500">
|
||||
In passato sorvegliante di:
|
||||
@foreach($gruppiPassati as $g)
|
||||
{{ $g->nome }} (sciolto il {{ $g->sciolto_at->format('d/m/Y') }}){{ $loop->last ? '.' : ',' }}
|
||||
@endforeach
|
||||
</p>
|
||||
@endif
|
||||
</section>
|
||||
@endif
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<div class="min-w-0">
|
||||
<h2 class="text-xl font-bold text-gray-900 truncate">{{ $user->name }}</h2>
|
||||
<p class="text-sm text-gray-500 truncate mt-0.5">
|
||||
<span class="break-all">{{ $user->email }}</span>
|
||||
<span class="break-all">{{ $user->identificativo }}</span>
|
||||
<span class="ml-1 inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-indigo-50 text-indigo-700 align-middle">
|
||||
{{ ucfirst($user->roles->first()?->name ?? 'utente') }}
|
||||
</span>
|
||||
@@ -59,7 +59,7 @@
|
||||
{{-- Dati profilo --}}
|
||||
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-1">Dati profilo</h3>
|
||||
<p class="text-sm text-gray-500 mb-4">Aggiorna nome e cognome ed email.</p>
|
||||
<p class="text-sm text-gray-500 mb-4">{{ $user->isSorvegliante() ? 'Aggiorna nome e cognome.' : 'Aggiorna nome e cognome ed email.' }}</p>
|
||||
|
||||
@if(session('profile_success'))
|
||||
<div class="mb-4 rounded-lg bg-green-50 border border-green-200 px-4 py-2.5 text-sm text-green-800">
|
||||
@@ -73,11 +73,20 @@
|
||||
<input wire:model="name" type="text" id="name" class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:ring-indigo-500 focus:border-indigo-500 text-sm">
|
||||
@error('name') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
|
||||
</div>
|
||||
@if($user->isSorvegliante())
|
||||
{{-- Il sorvegliante entra con il nome utente del gruppo, senza email --}}
|
||||
<div>
|
||||
<p class="block text-sm font-medium text-gray-700">Nome utente</p>
|
||||
<p class="mt-1 text-sm"><code class="select-all">{{ $user->username }}</code></p>
|
||||
<p class="mt-1 text-xs text-gray-500">Viene dal nome del gruppo: lo usi per entrare, insieme alla password.</p>
|
||||
</div>
|
||||
@else
|
||||
<div>
|
||||
<label for="email" class="block text-sm font-medium text-gray-700">Email</label>
|
||||
<input wire:model="email" type="email" id="email" class="mt-1 block w-full rounded-lg border-gray-300 shadow-sm focus:ring-indigo-500 focus:border-indigo-500 text-sm">
|
||||
@error('email') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
|
||||
</div>
|
||||
@endif
|
||||
<div class="flex justify-end">
|
||||
<x-btn variante="primary" type="submit">Salva modifiche</x-btn>
|
||||
</div>
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td data-label="Proclamatore" class="px-3 py-2">{{ $a->proclamatore?->nome_completo ?? 'N/A' }}@if($a->gruppo)<span class="ml-1 inline-flex rounded-full bg-purple-50 px-2 py-0.5 text-xs text-purple-700" title="Assegnato dal sorvegliante del gruppo di servizio">via gruppo {{ $a->gruppo->nome }}</span>@endif</td>
|
||||
<td data-label="Proclamatore" class="px-3 py-2">{{ $a->proclamatore?->nome_completo ?? 'N/A' }}@if($a->gruppo_nome)<span class="ml-1 inline-flex rounded-full bg-purple-50 px-2 py-0.5 text-xs text-purple-700" title="Assegnato dal sorvegliante del gruppo di servizio">via gruppo {{ $a->gruppo_nome }}</span>@endif</td>
|
||||
<td data-label="Assegnato" class="px-3 py-2">{{ $a->assigned_at->format('d/m/Y') }}</td>
|
||||
<td data-label="Rientrato" class="px-3 py-2">
|
||||
@if($a->returned_at)
|
||||
|
||||
@@ -111,8 +111,14 @@
|
||||
@else
|
||||
<td data-label="Nome" class="px-4 py-2 text-gray-900">{{ $user->name }}</td>
|
||||
<td data-label="Email" class="px-4 py-2 text-gray-700">
|
||||
@if(! $user->email)
|
||||
{{-- Sorvegliante di gruppo: entra con il nome utente, senza email --}}
|
||||
@if($user->username)<span class="text-gray-500">nome utente</span> <code>{{ $user->username }}</code>@else<span class="text-gray-400">—</span>@endif
|
||||
@else
|
||||
{{ $user->email }}
|
||||
@if($user->hasVerifiedEmail())
|
||||
@endif
|
||||
@if(! $user->email)
|
||||
@elseif($user->hasVerifiedEmail())
|
||||
<span class="ml-1 inline-flex items-center rounded-full bg-green-50 px-2 py-0.5 text-xs font-medium text-green-700">confermata</span>
|
||||
@else
|
||||
<span class="ml-1 inline-flex items-center rounded-full bg-amber-50 px-2 py-0.5 text-xs font-medium text-amber-800"
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
<tbody class="divide-y divide-gray-100">
|
||||
@foreach($assegnazioni as $assegnazione)
|
||||
<tr>
|
||||
<td data-label="Proclamatore" class="px-3 py-2">{{ $assegnazione->proclamatore?->nome_completo ?? 'N/A' }}@if($assegnazione->gruppo)<span class="ml-1 inline-flex rounded-full bg-purple-50 px-2 py-0.5 text-xs text-purple-700">via gruppo {{ $assegnazione->gruppo->nome }}</span>@endif</td>
|
||||
<td data-label="Proclamatore" class="px-3 py-2">{{ $assegnazione->proclamatore?->nome_completo ?? 'N/A' }}@if($assegnazione->gruppo_nome)<span class="ml-1 inline-flex rounded-full bg-purple-50 px-2 py-0.5 text-xs text-purple-700">via gruppo {{ $assegnazione->gruppo_nome }}</span>@endif</td>
|
||||
<td data-label="Assegnato" class="px-3 py-2">{{ $assegnazione->assigned_at->format('d/m/Y') }}</td>
|
||||
<td data-label="Rientrato" class="px-3 py-2">
|
||||
@if($assegnazione->returned_at)
|
||||
|
||||
Reference in New Issue
Block a user