- LimitaSorvegliante: la rotta delle azioni di Livewire 3.7 si chiama "default.livewire.update"; con 'livewire.*' ogni clic era un 403. - Territorio::ordinaPerPriorita(): la regola di "Da assegnare" della Home in un metodo solo, usato dalla Home, dall'aggiunta al pacchetto e da "Il mio gruppo". - Aggiunta al pacchetto: ricerca, zona, tipologia, solo prioritari, "Seleziona tutti quelli mostrati", badge e giorni di fermo. - Il mio gruppo: da dare in ordine di priorita' poi i gia' dati; filtri stato, zona, tipologia, solo prioritari; sotto il titolo nome e cognome del sorvegliante. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
161 lines
13 KiB
PHP
161 lines
13 KiB
PHP
<div>
|
|
{{-- Il mio gruppo (MioGruppo): la sola pagina del sorvegliante di gruppo.
|
|
Pensata prima per il telefono: schede una sotto l'altra, pulsanti
|
|
grandi. Copia, Condividi e ricerca vengono da elencoCercabile
|
|
(resources/js/app.js), l'invio del link dal partial _invio-link. --}}
|
|
@if(! $gruppo)
|
|
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6 text-sm text-gray-600">
|
|
Non sei il sorvegliante di un gruppo di servizio attivo.
|
|
</div>
|
|
@else
|
|
<div class="mb-5">
|
|
<h1 class="text-2xl font-bold text-gray-900">Gruppo {{ $gruppo->nome }}</h1>
|
|
@if($gruppo->sorvegliante)
|
|
<p class="text-sm text-gray-700 mt-0.5">Sorvegliante: <strong>{{ trim($gruppo->sorvegliante->nome . ' ' . $gruppo->sorvegliante->cognome) }}</strong></p>
|
|
@endif
|
|
{{-- In questa vista solo blocchi php…endphp: la forma in linea, se
|
|
viene prima di un blocco, confonde il compilatore di Blade. --}}
|
|
@php $daDare = $pacchetto->filter(fn ($t) => ! $t->assegnazioneCorrente)->count(); @endphp
|
|
<p class="text-sm text-gray-500 mt-1">
|
|
{{ $pacchetto->count() }} {{ $pacchetto->count() === 1 ? 'territorio' : 'territori' }} nel pacchetto ·
|
|
{{ $daDare }} da dare · {{ $membri->count() }} {{ $membri->count() === 1 ? 'membro' : 'membri' }}
|
|
</p>
|
|
</div>
|
|
|
|
@include('livewire.assegnazioni._invio-link')
|
|
|
|
<section class="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden" x-data="elencoCercabile" aria-labelledby="titolo-pacchetto">
|
|
<svg aria-hidden="true" style="position:absolute;width:0;height:0;overflow:hidden">
|
|
<symbol id="tm-i-copia" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"/></symbol>
|
|
<symbol id="tm-i-spunta" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></symbol>
|
|
<symbol id="tm-i-condividi" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z"/></symbol>
|
|
<symbol id="tm-i-avviso" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/></symbol>
|
|
</svg>
|
|
|
|
<div class="px-4 py-3 border-b border-gray-100 space-y-2">
|
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
|
<h2 id="titolo-pacchetto" class="text-sm font-semibold text-gray-800">Territori del pacchetto</h2>
|
|
@if($pacchetto->count() > 5)
|
|
<input x-model="q" type="search" inputmode="search" autocomplete="off" aria-label="Cerca nel pacchetto"
|
|
placeholder="Cerca numero, zona o nome…"
|
|
class="w-full sm:w-64 rounded-lg border-gray-300 text-base sm:text-sm focus:ring-indigo-500 focus:border-indigo-500">
|
|
@endif
|
|
</div>
|
|
{{-- Filtri; l'ordine è di priorità: prima i prioritari e quelli fermi da più tempo --}}
|
|
@if($pacchetto->isNotEmpty())
|
|
<div class="grid grid-cols-2 sm:grid-cols-4 gap-2">
|
|
<select wire:model.live="filtroStato" aria-label="Stato"
|
|
class="block w-full rounded-lg border-gray-300 text-base sm:text-sm focus:ring-indigo-500 focus:border-indigo-500">
|
|
<option value="">Tutti</option>
|
|
<option value="da_dare">Da dare</option>
|
|
<option value="dati">Già dati</option>
|
|
</select>
|
|
<select wire:model.live="filtroZona" aria-label="Zona"
|
|
class="block w-full rounded-lg border-gray-300 text-base sm:text-sm focus:ring-indigo-500 focus:border-indigo-500">
|
|
<option value="">Tutte le zone</option>
|
|
@foreach($zone as $id => $nome)
|
|
<option value="{{ $id }}">{{ $nome }}</option>
|
|
@endforeach
|
|
</select>
|
|
<select wire:model.live="filtroTipologia" aria-label="Tipologia"
|
|
class="block w-full rounded-lg border-gray-300 text-base sm:text-sm focus:ring-indigo-500 focus:border-indigo-500">
|
|
<option value="">Tutte le tipologie</option>
|
|
@foreach($tipologie as $id => $nome)
|
|
<option value="{{ $id }}">{{ $nome }}</option>
|
|
@endforeach
|
|
</select>
|
|
<label class="flex items-center gap-2 text-sm text-gray-700 px-1">
|
|
<input type="checkbox" wire:model.live="soloPrioritari" class="h-5 w-5 rounded border-gray-300 text-indigo-600">
|
|
Solo prioritari
|
|
</label>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="divide-y divide-gray-100">
|
|
@forelse($territori as $t)
|
|
@php
|
|
$a = $t->assegnazioneCorrente;
|
|
$pdfUrl = $a?->shortPdfUrl();
|
|
$cerca = \Illuminate\Support\Str::lower(\Illuminate\Support\Str::ascii(implode(' ', array_filter([$t->numero, $t->zona?->nome, $a?->proclamatore?->nome_completo]))));
|
|
@endphp
|
|
<div wire:key="pacchetto-{{ $t->id }}" data-cerca="{{ $cerca }}" x-show="corrisponde($el.dataset.cerca)" class="tm-assegnato">
|
|
<div class="tm-assegnato-testa">
|
|
<span><span class="tm-assegnato-numero">N° {{ $t->numero }}</span> @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($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
|
|
<span class="tm-assegnato-info"><b>Da dare</b>@if($t->tipologia?->nome) · {{ $t->tipologia->nome }}@endif @if($t->giacenza_giorni > 0) · fermo da {{ $t->giacenza_giorni }} gg @endif</span>
|
|
@endif
|
|
</div>
|
|
|
|
@if($a?->link_in_sospeso)
|
|
<div class="tm-assegnato-sospeso" role="status"><svg aria-hidden="true"><use href="#tm-i-avviso"/></svg> Link ancora da inviare <x-btn variante="secondary" tono="tenue" dimensione="sm" wire:click="apriInvio({{ $a->id }})">Invia link</x-btn></div>
|
|
@endif
|
|
|
|
@if($a)
|
|
{{-- Assegnato: rientro, link (copia / condividi), stato dell'invio --}}
|
|
<div class="tm-assegnato-link" @if($pdfUrl) data-link data-id="{{ $a->id }}" data-messaggio="{{ $a->messaggioLink($pdfUrl) }}" data-titolo="Territorio N° {{ $t->numero }}" @endif>
|
|
<x-btn data-ritorno variante="primary" dimensione="sm" :href="route('assegnazioni.rientra', $a)">Rientro</x-btn>
|
|
@if($pdfUrl)
|
|
<code x-on:click="window.getSelection().selectAllChildren($el)">{{ $pdfUrl }}</code>
|
|
<x-btn variante="secondary" tono="tenue" dimensione="sm" icona class="tm-copia" x-on:click="copia($el)" title="Copia link" aria-label="Copia il link della piantina"><svg aria-hidden="true"><use href="#tm-i-copia"/></svg><svg aria-hidden="true"><use href="#tm-i-spunta"/></svg></x-btn>
|
|
<x-btn variante="secondary" tono="tenue" dimensione="sm" icona x-show="condivisibile" x-cloak x-on:click="condividi($el)" title="Condividi il link" aria-label="Condividi il link della piantina"><svg aria-hidden="true"><use href="#tm-i-condividi"/></svg></x-btn>
|
|
<x-btn :variante="$a->link_sent ? 'primary' : 'secondary'" tono="tenue" dimensione="sm" wire:click="toggleLinkSent({{ $a->id }})" aria-pressed="{{ $a->link_sent ? 'true' : 'false' }}">{{ $a->link_sent ? 'Link inviato' : 'Non inviato' }}</x-btn>
|
|
@endif
|
|
</div>
|
|
@elseif($territorioDaAssegnare === $t->id)
|
|
{{-- Da dare: a chi e da quando --}}
|
|
<div class="mt-3 rounded-lg border border-indigo-100 bg-indigo-50/50 p-3 space-y-3">
|
|
<div>
|
|
<label for="membro-{{ $t->id }}" class="block text-sm font-medium text-gray-700 mb-1">A chi lo dai?</label>
|
|
<x-scelta id="membro-{{ $t->id }}" wire:model="membroId" :opzioni="$opzioniMembri" segnaposto="Cognome o nome" :vuoto="null" />
|
|
@error('membroId') <p class="text-red-500 text-xs mt-1">{{ $message }}</p> @enderror
|
|
</div>
|
|
<div>
|
|
<label for="data-{{ $t->id }}" class="block text-sm font-medium text-gray-700 mb-1">Data</label>
|
|
<input wire:model="dataAssegnazione" type="date" id="data-{{ $t->id }}" max="{{ now()->format('Y-m-d') }}"
|
|
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>
|
|
<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>
|
|
</div>
|
|
</div>
|
|
@else
|
|
<div class="tm-assegnato-link">
|
|
<x-btn variante="primary" dimensione="sm" wire:click="apriAssegnazione({{ $t->id }})">Assegna</x-btn>
|
|
@if($t->pdf_path)
|
|
<x-btn variante="secondary" tono="tenue" dimensione="sm" :href="route('mio-gruppo.pdf', $t)" target="_blank" rel="noopener">Piantina</x-btn>
|
|
@endif
|
|
<x-btn variante="secondary" tono="tenue" dimensione="sm" wire:click="rimanda({{ $t->id }})"
|
|
wire:confirm="Rimandare in reparto il territorio {{ $t->numero }}? Uscirà dal pacchetto del gruppo.">Rimanda in reparto</x-btn>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
@empty
|
|
<p class="px-4 py-8 text-center text-sm text-gray-500">
|
|
{{ $pacchetto->isEmpty() ? "Il pacchetto è vuoto: l'amministratore non ha ancora assegnato territori al gruppo." : 'Nessun territorio con questi filtri.' }}
|
|
</p>
|
|
@endforelse
|
|
<p x-show="nessuno" x-cloak class="px-4 py-8 text-center text-sm text-gray-400">Nessun risultato per «<span x-text="q"></span>».</p>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="mt-5 bg-white rounded-xl shadow-sm border border-gray-200 p-4" aria-labelledby="titolo-membri">
|
|
<h2 id="titolo-membri" class="text-sm font-semibold text-gray-800 mb-2">Membri del gruppo</h2>
|
|
<ul class="text-sm text-gray-700 space-y-1">
|
|
@foreach($membri as $m)
|
|
@php $quanti = $pacchetto->filter(fn ($t) => $t->assegnazioneCorrente?->proclamatore_id === $m->id)->count(); @endphp
|
|
<li class="flex justify-between gap-3">
|
|
<span>{{ $m->nome_completo }} @if($m->id === $gruppo->sorvegliante_id)<span class="text-xs text-gray-500">(sorvegliante)</span>@endif</span>
|
|
<span class="text-gray-500">{{ $quanti }} {{ $quanti === 1 ? 'territorio' : 'territori' }}</span>
|
|
</li>
|
|
@endforeach
|
|
</ul>
|
|
</section>
|
|
@endif
|
|
</div>
|