++ gruppi di servizio: sorvegliante con utenza limitata, pacchetto di territori, assegnazione ai membri

Il gruppo ha un sorvegliante (proclamatore con utenza: email e password
temporanea, senza conferma dell'email) e dei membri; l'amministratore
mette in blocco dei territori nel pacchetto del gruppo. Il pacchetto non
e' un'assegnazione e non tocca le statistiche; quando il sorvegliante da'
un territorio a un membro nasce un'assegnazione normale con
gruppo_servizio_id. Al rientro il territorio torna in reparto. Sciogliere
il gruppo libera pacchetto e membri e disattiva l'utenza.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Francesco Picone
2026-10-19 17:51:37 +02:00
parent 5d0ae06eca
commit 96084499f5
41 changed files with 2298 additions and 224 deletions

View File

@@ -0,0 +1,72 @@
{{-- Finestra di invio del link dopo un'assegnazione. Logica nel trait
App\Livewire\Concerns\InviaLink; la includono Assegna e Il mio gruppo. --}}
{{-- Invio del link (InviaLink::apriInvio): blocca la pagina finché non si
risponde "inviato / non ancora". Se si chiude la scheda prima,
l'assegnazione resta segnalata con "link ancora da inviare". --}}
@if($invio)
@php
$link = $invio->shortPdfUrl();
$messaggio = $invio->messaggioLink($link);
@endphp
<div class="fixed inset-0 z-50 flex items-start justify-center overflow-y-auto bg-gray-900/50 p-4 sm:items-center"
role="dialog" aria-modal="true" aria-labelledby="invio-titolo" wire:key="invio-{{ $invio->id }}">
<section class="tm-da-inviare tm-da-inviare-finestra">
<h2 id="invio-titolo" class="tm-da-inviare-titolo">
Territorio N° {{ $invio->territorio?->numero }} assegnato a {{ $invio->proclamatore?->nome_completo }}
</h2>
@if($link)
<p class="text-sm text-gray-700 mb-2">Come vuoi mandare il link della piantina? Il destinatario lo scegli tu, tra i tuoi contatti.</p>
<div class="tm-da-inviare-link">
<code id="invio-link" x-data x-on:click="window.getSelection().selectAllChildren($el)">{{ $link }}</code>
</div>
{{-- Il messaggio sta in data-messaggio: dentro <x-btn> le direttive
Blade (@js) non si compilano, quindi i pulsanti lo leggono da qui. --}}
<div class="tm-da-inviare-azioni" x-data="{ copiato: false, condivisibile: !! navigator.share }"
data-messaggio="{{ $messaggio }}" data-titolo="Territorio N° {{ $invio->territorio?->numero }}">
<x-btn :variante="$canaleUsato === 'copia' ? 'primary' : 'secondary'"
x-on:click="navigator.clipboard?.writeText(document.getElementById('invio-link').textContent.trim()).then(() => { copiato = true; setTimeout(() => copiato = false, 2000) }).catch(() => {}); $wire.canale('copia')">
<span x-show="! copiato">Copia link</span>
<span x-show="copiato" x-cloak>Copiato</span>
</x-btn>
{{-- Condividi: il menu di condivisione del telefono (WhatsApp,
Telegram, SMS, posta…), da cui si sceglie app e contatto. Solo
dove il browser lo offre. Il canale si annota a condivisione
fatta, non se la si annulla. --}}
<x-btn :variante="$canaleUsato === 'condividi' ? 'primary' : 'secondary'" x-show="condivisibile" x-cloak
x-on:click="const d = $el.closest('[data-messaggio]').dataset; navigator.share({ title: d.titolo, text: d.messaggio }).then(() => $wire.canale('condividi')).catch(() => {})">
Condividi…
</x-btn>
</div>
@if($canaleUsato)
<p class="mt-2 text-sm text-gray-700">Canale scelto: {{ \App\Models\Assegnazione::CANALI_LINK[$canaleUsato] }}.</p>
@endif
@if($erroreInvio)
<p class="mt-2 text-sm text-red-600" role="alert">{{ $erroreInvio }}</p>
@endif
<div class="tm-da-inviare-scelta">
<p>Hai inviato il link?</p>
<div>
<x-btn variante="primary" wire:click="concludiInvio(true)" :disabled="$canaleUsato === null"
:title="$canaleUsato === null ? 'Scegli prima come mandare il link' : null">Sì, inviato</x-btn>
<x-btn variante="secondary" wire:click="concludiInvio(false)">No, non ancora</x-btn>
</div>
</div>
@else
<p class="text-sm text-gray-600">
Il territorio non ha un PDF: non c'è un link da mandare. Caricalo dalla scheda del territorio.
</p>
<div class="tm-da-inviare-scelta">
<div>
<x-btn variante="secondary" wire:click="concludiInvio(false)">Ho capito</x-btn>
</div>
</div>
@endif
</section>
</div>
@endif

View File

@@ -8,76 +8,8 @@
<p class="text-sm text-gray-500 mt-1">Questa funzione consente un'assegnazione arbitraria, indipendente dalle tre schede della Home.</p>
</div>
{{-- Invio del link (Assegna::apriInvio): blocca la pagina finché non si
risponde "inviato / non ancora". Se si chiude la scheda prima,
l'assegnazione resta segnalata con "link ancora da inviare". --}}
@if($invio)
@php
$link = $invio->shortPdfUrl();
$messaggio = $invio->messaggioLink($link);
@endphp
<div class="fixed inset-0 z-50 flex items-start justify-center overflow-y-auto bg-gray-900/50 p-4 sm:items-center"
role="dialog" aria-modal="true" aria-labelledby="invio-titolo" wire:key="invio-{{ $invio->id }}">
<section class="tm-da-inviare tm-da-inviare-finestra">
<h2 id="invio-titolo" class="tm-da-inviare-titolo">
Territorio N° {{ $invio->territorio?->numero }} assegnato a {{ $invio->proclamatore?->nome_completo }}
</h2>
@include('livewire.assegnazioni._invio-link')
@if($link)
<p class="text-sm text-gray-700 mb-2">Come vuoi mandare il link della piantina? Il destinatario lo scegli tu, tra i tuoi contatti.</p>
<div class="tm-da-inviare-link">
<code id="invio-link" x-data x-on:click="window.getSelection().selectAllChildren($el)">{{ $link }}</code>
</div>
{{-- Il messaggio sta in data-messaggio: dentro <x-btn> le direttive
Blade (@js) non si compilano, quindi i pulsanti lo leggono da qui. --}}
<div class="tm-da-inviare-azioni" x-data="{ copiato: false, condivisibile: !! navigator.share }"
data-messaggio="{{ $messaggio }}" data-titolo="Territorio N° {{ $invio->territorio?->numero }}">
<x-btn :variante="$canaleUsato === 'copia' ? 'primary' : 'secondary'"
x-on:click="navigator.clipboard?.writeText(document.getElementById('invio-link').textContent.trim()).then(() => { copiato = true; setTimeout(() => copiato = false, 2000) }).catch(() => {}); $wire.canale('copia')">
<span x-show="! copiato">Copia link</span>
<span x-show="copiato" x-cloak>Copiato</span>
</x-btn>
{{-- Condividi: il menu di condivisione del telefono (WhatsApp,
Telegram, SMS, posta…), da cui si sceglie app e contatto. Solo
dove il browser lo offre. Il canale si annota a condivisione
fatta, non se la si annulla. --}}
<x-btn :variante="$canaleUsato === 'condividi' ? 'primary' : 'secondary'" x-show="condivisibile" x-cloak
x-on:click="const d = $el.closest('[data-messaggio]').dataset; navigator.share({ title: d.titolo, text: d.messaggio }).then(() => $wire.canale('condividi')).catch(() => {})">
Condividi…
</x-btn>
</div>
@if($canaleUsato)
<p class="mt-2 text-sm text-gray-700">Canale scelto: {{ \App\Models\Assegnazione::CANALI_LINK[$canaleUsato] }}.</p>
@endif
@if($erroreInvio)
<p class="mt-2 text-sm text-red-600" role="alert">{{ $erroreInvio }}</p>
@endif
<div class="tm-da-inviare-scelta">
<p>Hai inviato il link?</p>
<div>
<x-btn variante="primary" wire:click="concludiInvio(true)" :disabled="$canaleUsato === null"
:title="$canaleUsato === null ? 'Scegli prima come mandare il link' : null">Sì, inviato</x-btn>
<x-btn variante="secondary" wire:click="concludiInvio(false)">No, non ancora</x-btn>
</div>
</div>
@else
<p class="text-sm text-gray-600">
Il territorio non ha un PDF: non c'è un link da mandare. Caricalo dalla scheda del territorio.
</p>
<div class="tm-da-inviare-scelta">
<div>
<x-btn variante="secondary" wire:click="concludiInvio(false)">Ho capito</x-btn>
</div>
</div>
@endif
</section>
</div>
@endif
<div x-data="{ formOpen: true }">

View File

@@ -1,8 +1,8 @@
<div>
<div class="mb-6">
<a href="{{ $ritorno ?? route('territori.show', $assegnazione->territorio) }}" class="inline-flex items-center gap-1 text-sm text-gray-500 hover:text-indigo-600 transition-colors mb-1">
<a href="{{ $ritorno ?? $this->paginaPredefinita() }}" class="inline-flex items-center gap-1 text-sm text-gray-500 hover:text-indigo-600 transition-colors mb-1">
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/></svg>
{{ $ritorno ? 'Torna indietro' : 'Torna al territorio' }}
{{ $ritorno ? 'Torna indietro' : (auth()->user()->can('territori.assign') ? 'Torna al territorio' : 'Torna al mio gruppo') }}
</a>
<h1 class="text-2xl font-bold text-gray-900">Rientro Territorio</h1>
</div>
@@ -62,7 +62,7 @@
<div class="flex flex-wrap items-center gap-3 pt-4">
<x-btn variante="primary" type="submit">Registra rientro</x-btn>
<x-btn variante="secondary" :href="$ritorno ?? route('territori.show', $assegnazione->territorio)">Annulla</x-btn>
<x-btn variante="secondary" :href="$ritorno ?? $this->paginaPredefinita()">Annulla</x-btn>
</div>
</form>
</div>