netgescon-day0/resources/views/filament/pages/supporto/ticket-gestione.blade.php

375 lines
28 KiB
PHP

<x-filament-panels::page>
<div class="space-y-4">
<div class="rounded-xl border bg-white p-4">
<div class="flex flex-wrap items-center gap-2">
<a href="{{ $this->getTicketInserimentoUrl() }}" class="inline-flex items-center rounded-md bg-indigo-700 px-3 py-1.5 text-xs font-medium text-white hover:bg-indigo-600">Vai a Inserimento Ticket</a>
</div>
<div class="mt-3 grid grid-cols-2 gap-2 sm:grid-cols-4">
<div class="rounded-lg border bg-gray-50 px-3 py-2 text-xs">Aperti: <span class="font-semibold">{{ $ticketCounters['open'] ?? 0 }}</span></div>
<div class="rounded-lg border bg-gray-50 px-3 py-2 text-xs">Urgenti: <span class="font-semibold">{{ $ticketCounters['urgent'] ?? 0 }}</span></div>
<div class="rounded-lg border bg-gray-50 px-3 py-2 text-xs">Chiusi: <span class="font-semibold">{{ $ticketCounters['closed'] ?? 0 }}</span></div>
<div class="rounded-lg border bg-gray-50 px-3 py-2 text-xs">Totali: <span class="font-semibold">{{ $ticketCounters['all'] ?? 0 }}</span></div>
</div>
</div>
<div class="rounded-xl border bg-white p-4">
<div class="flex flex-wrap items-center justify-between gap-3">
<div class="flex flex-wrap items-center gap-2">
<button type="button" wire:click="apriElenco" class="inline-flex items-center rounded-md px-3 py-1.5 text-xs font-medium {{ $activeTab === 'elenco' ? 'bg-slate-800 text-white' : 'bg-slate-100 text-slate-700 hover:bg-slate-200' }}">
Tab 1 - Elenco (stile excel)
</button>
<button type="button" wire:click="$set('activeTab', 'scheda')" class="inline-flex items-center rounded-md px-3 py-1.5 text-xs font-medium {{ $activeTab === 'scheda' ? 'bg-slate-800 text-white' : 'bg-slate-100 text-slate-700 hover:bg-slate-200' }}">
Tab 2 - Scheda ticket
</button>
<button type="button" wire:click="$set('activeTab', 'fornitori')" class="inline-flex items-center rounded-md px-3 py-1.5 text-xs font-medium {{ $activeTab === 'fornitori' ? 'bg-slate-800 text-white' : 'bg-slate-100 text-slate-700 hover:bg-slate-200' }}">
Tab 3 - Fornitori attivi
</button>
</div>
@if($activeTab === 'elenco')
<select wire:model.live="status" class="rounded-lg border-gray-300 text-sm">
<option value="open">Aperti</option>
<option value="urgent">Urgenti</option>
<option value="closed">Chiusi</option>
<option value="all">Tutti</option>
</select>
@endif
</div>
@if($activeTab === 'elenco')
<div class="mt-3 rounded-lg border bg-slate-50 p-3">
<div class="mb-2 text-xs font-semibold text-slate-700">Categorie ticket</div>
<div class="grid gap-2 md:grid-cols-3">
<label class="block text-xs">
<span class="mb-1 block font-medium">Categoria esistente</span>
<select wire:model.live="selectedCategoriaId" class="w-full rounded-lg border-gray-300 text-sm">
<option value="">Seleziona categoria</option>
@foreach($categorieOptions as $cat)
<option value="{{ (int) $cat['id'] }}">{{ $cat['nome'] }}</option>
@endforeach
</select>
</label>
<label class="block text-xs">
<span class="mb-1 block font-medium">Nome categoria</span>
<input type="text" wire:model.defer="categoriaNome" class="w-full rounded-lg border-gray-300 text-sm" placeholder="Es. Ascensore" />
</label>
<label class="block text-xs">
<span class="mb-1 block font-medium">Descrizione</span>
<input type="text" wire:model.defer="categoriaDescrizione" class="w-full rounded-lg border-gray-300 text-sm" placeholder="Descrizione breve" />
</label>
</div>
<div class="mt-2 flex flex-wrap items-center gap-2">
<x-filament::button size="sm" color="success" wire:click="creaCategoriaTicket">Aggiungi categoria</x-filament::button>
<x-filament::button size="sm" color="warning" wire:click="aggiornaCategoriaTicket">Modifica categoria selezionata</x-filament::button>
</div>
</div>
<div class="mt-3 overflow-x-auto">
<table class="min-w-full border-collapse border text-xs">
<thead>
<tr class="bg-slate-100 text-slate-700">
<th class="border px-2 py-2 text-left">ID</th>
<th class="border px-2 py-2 text-left">Titolo</th>
<th class="border px-2 py-2 text-left">Categoria</th>
<th class="border px-2 py-2 text-left">Tipo intervento</th>
<th class="border px-2 py-2 text-left">Assegnato a</th>
<th class="border px-2 py-2 text-left">Priorita</th>
<th class="border px-2 py-2 text-left">Stato</th>
<th class="border px-2 py-2 text-left">Apertura</th>
<th class="border px-2 py-2 text-left">Azioni</th>
</tr>
</thead>
<tbody>
@forelse($tickets as $ticket)
<tr id="ticket-{{ (int) $ticket->id }}" class="hover:bg-slate-50">
<td class="border px-2 py-2">#{{ (int) $ticket->id }}</td>
<td class="border px-2 py-2">
<div class="flex items-center gap-1">
<span>{{ $ticket->titolo }}</span>
@if(((int) ($ticket->attachments_count ?? 0)) > 0)
<span title="Presenza allegati" class="inline-flex items-center rounded bg-emerald-100 px-1.5 py-0.5 text-[10px] font-semibold text-emerald-800">
Allegati {{ (int) $ticket->attachments_count }}
</span>
@endif
</div>
</td>
<td class="border px-2 py-2">{{ optional($ticket->categoriaTicket)->nome ?: '-' }}</td>
<td class="border px-2 py-2">{{ $this->getTipoInterventoLabel($ticket) }}</td>
<td class="border px-2 py-2">{{ optional($ticket->assegnatoAUser)->name ?: '-' }}</td>
<td class="border px-2 py-2">{{ $ticket->priorita }}</td>
<td class="border px-2 py-2">{{ $ticket->stato }}</td>
<td class="border px-2 py-2">{{ optional($ticket->data_apertura)->format('d/m/Y H:i') }}</td>
<td class="border px-2 py-2">
<div class="flex flex-wrap items-center gap-1">
<button type="button" wire:click="apriScheda({{ (int) $ticket->id }})" class="inline-flex items-center rounded-md bg-slate-700 px-2 py-1 text-[11px] font-medium text-white hover:bg-slate-600">Scheda</button>
@if((int) ($ticket->assegnato_a_fornitore_id ?? 0) > 0)
<button type="button" wire:click="apriScheda({{ (int) $ticket->id }})" class="inline-flex items-center rounded-md bg-fuchsia-700 px-2 py-1 text-[11px] font-medium text-white hover:bg-fuchsia-600">Assegnata</button>
@endif
@if(in_array($ticket->stato, ['Aperto'], true))
<button type="button" wire:click="prendiInCarico({{ (int) $ticket->id }})" class="inline-flex items-center rounded-md bg-blue-600 px-2 py-1 text-[11px] font-medium text-white hover:bg-blue-500">Carico</button>
@endif
@if(in_array($ticket->stato, ['Aperto', 'Preso in Carico'], true))
<button type="button" wire:click="avviaLavorazione({{ (int) $ticket->id }})" class="inline-flex items-center rounded-md bg-amber-600 px-2 py-1 text-[11px] font-medium text-white hover:bg-amber-500">Lavora</button>
@endif
@if(in_array($ticket->stato, ['Aperto', 'Preso in Carico', 'In Lavorazione', 'In Attesa Approvazione', 'In Attesa Ricambi'], true))
<button type="button" wire:click="risolviTicket({{ (int) $ticket->id }})" class="inline-flex items-center rounded-md bg-emerald-600 px-2 py-1 text-[11px] font-medium text-white hover:bg-emerald-500">Risolto</button>
@endif
@if(in_array($ticket->stato, ['Risolto'], true))
<button type="button" wire:click="chiudiTicket({{ (int) $ticket->id }})" class="inline-flex items-center rounded-md bg-gray-800 px-2 py-1 text-[11px] font-medium text-white hover:bg-gray-700">Chiudi</button>
@endif
</div>
</td>
</tr>
@empty
<tr>
<td colspan="9" class="border px-2 py-4 text-center text-gray-500">Nessun ticket per il filtro selezionato.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@elseif($activeTab === 'fornitori')
<div class="mt-4 rounded-xl border bg-white p-4">
<div class="text-sm font-semibold">Fornitori attivi su ticket aperti</div>
<div class="mt-1 text-xs text-gray-500">Mostra solo fornitori con ticket/interventi in corso, con stato operativo e ultimo aggiornamento.</div>
@if(filled($lastGeneratedPassword ?? null))
<div class="mt-3 rounded-md border border-amber-300 bg-amber-50 px-3 py-2 text-xs text-amber-900">
Ultima password temporanea generata: <span class="font-mono font-semibold">{{ $lastGeneratedPassword }}</span>
</div>
@endif
<div class="mt-3 overflow-x-auto">
<table class="min-w-full border-collapse border text-xs">
<thead>
<tr class="bg-slate-100 text-slate-700">
<th class="border px-2 py-2 text-left">Fornitore</th>
<th class="border px-2 py-2 text-left">Contatti</th>
<th class="border px-2 py-2 text-left">Ticket attivi</th>
<th class="border px-2 py-2 text-left">Interventi aperti</th>
<th class="border px-2 py-2 text-left">Come procede</th>
<th class="border px-2 py-2 text-left">Accesso fornitore</th>
<th class="border px-2 py-2 text-left">Azioni</th>
</tr>
</thead>
<tbody>
@forelse($fornitoriAttiviRows as $f)
<tr class="hover:bg-slate-50">
<td class="border px-2 py-2 font-medium">{{ $f['nome'] ?: ('Fornitore #' . $f['id']) }}</td>
<td class="border px-2 py-2">{{ $f['email'] ?: '-' }}<br>{{ $f['telefono'] ?: '-' }}</td>
<td class="border px-2 py-2">{{ (int) $f['ticket_attivi'] }}</td>
<td class="border px-2 py-2">{{ (int) $f['interventi_aperti'] }}</td>
<td class="border px-2 py-2">
<div class="space-y-1 text-[11px]">
<div><span class="font-medium">Stati intervento:</span> {{ $f['intervento_stati'] ?: 'N/D' }}</div>
<div><span class="font-medium">Ultimo aggiornamento:</span> {{ $f['ultimo_aggiornamento'] ?: '-' }}</div>
@if(!empty($f['ticket_focus']))
<div class="text-gray-600">{{ implode(', ', $f['ticket_focus']) }}</div>
@endif
</div>
</td>
<td class="border px-2 py-2 text-[11px]">
<div>Dipendenti: <span class="font-semibold">{{ (int) ($f['dipendenti_count'] ?? 0) }}</span></div>
@if((int) ($f['linked_user_id'] ?? 0) > 0)
<div class="text-emerald-700">Accesso attivo (utente #{{ (int) $f['linked_user_id'] }})</div>
@else
<div class="text-amber-700">Nessun accesso attivo</div>
@endif
</td>
<td class="border px-2 py-2">
<div class="flex flex-wrap gap-1">
<button type="button" wire:click="abilitaAccessoFornitoreDaTicket({{ (int) $f['id'] }})" class="inline-flex items-center rounded-md bg-emerald-700 px-2 py-1 text-[11px] font-medium text-white hover:bg-emerald-600">Abilita accesso</button>
@if((int) ($f['linked_user_id'] ?? 0) > 0)
<button type="button" wire:click="resetPasswordFornitoreUser({{ (int) $f['linked_user_id'] }})" class="inline-flex items-center rounded-md bg-amber-700 px-2 py-1 text-[11px] font-medium text-white hover:bg-amber-600">Reset password</button>
@endif
<a href="{{ $this->getFornitoreOperativoUrl((int) $f['id']) }}" class="inline-flex items-center rounded-md bg-indigo-700 px-2 py-1 text-[11px] font-medium text-white hover:bg-indigo-600">Scheda operativa</a>
<a href="{{ $this->getFornitoreAnagraficaUrl((int) $f['id']) }}" class="inline-flex items-center rounded-md bg-gray-700 px-2 py-1 text-[11px] font-medium text-white hover:bg-gray-600">Anagrafica</a>
</div>
</td>
</tr>
@empty
<tr>
<td colspan="7" class="border px-2 py-4 text-center text-gray-500">Nessun fornitore attivo su ticket aperti.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
@elseif($activeTab === 'scheda')
@php($ticket = $this->selectedTicket)
@if(! $ticket)
<div class="mt-3 rounded-lg border border-amber-300 bg-amber-50 p-3 text-sm text-amber-800">
Nessun ticket selezionato. Vai nella TAB Elenco e premi "Scheda" sulla riga del ticket.
</div>
@else
<div class="mt-3 rounded-lg border p-3">
<div class="flex flex-wrap items-center justify-between gap-2">
<div>
<div class="text-sm font-semibold">#{{ $ticket->id }} - {{ $ticket->titolo }}</div>
<div class="text-xs text-gray-600">Stato: {{ $ticket->stato }} · Priorita: {{ $ticket->priorita }} · Categoria: {{ optional($ticket->categoriaTicket)->nome ?: '-' }}</div>
</div>
<button type="button" wire:click="apriElenco" class="inline-flex items-center rounded-md bg-gray-700 px-3 py-1.5 text-xs font-medium text-white hover:bg-gray-600">Torna all'elenco</button>
</div>
<div class="mt-3 whitespace-pre-wrap text-sm text-gray-700">{{ $ticket->descrizione }}</div>
</div>
<div class="mt-3 grid gap-4 lg:grid-cols-2">
<div class="rounded-xl border bg-white p-4">
<div class="text-sm font-semibold">Assegnazione fornitore</div>
<label class="mt-3 block text-sm">
<span class="mb-1 block font-medium">Fornitore</span>
<select wire:model.defer="fornitoreId" class="w-full rounded-lg border-gray-300">
<option value="">Seleziona fornitore</option>
@foreach($fornitoriOptions as $f)
<option value="{{ (int) $f['id'] }}">{{ $f['nome'] }}</option>
@endforeach
</select>
</label>
<label class="mt-3 block text-sm">
<span class="mb-1 block font-medium">Note assegnazione/intervento</span>
<textarea rows="3" wire:model.defer="noteAssegnazione" class="w-full rounded-lg border-gray-300" placeholder="Istruzioni operative"></textarea>
</label>
<div class="mt-3">
<x-filament::button wire:click="assegnaFornitore">Assegna fornitore</x-filament::button>
@if((int) ($fornitoreId ?? 0) > 0)
<a href="{{ $this->getFornitoreOperativoUrl((int) $fornitoreId) }}" class="ml-2 inline-flex items-center rounded-md bg-purple-700 px-3 py-1.5 text-xs font-medium text-white hover:bg-purple-600">Vedi gestione fornitore</a>
@endif
</div>
</div>
<div class="rounded-xl border bg-white p-4">
<div class="text-sm font-semibold">Nota interna</div>
<div class="mt-1 text-xs text-gray-500">Puoi aggiungere piu note: ogni nota viene salvata con data/ora automatica.</div>
<label class="mt-3 block text-sm">
<span class="mb-1 block font-medium">Nuova nota</span>
<textarea rows="4" wire:model.defer="notaInterna" class="w-full rounded-lg border-gray-300" placeholder="Aggiungi aggiornamento interno"></textarea>
</label>
<div class="mt-3">
<x-filament::button color="gray" wire:click="aggiungiNotaInterna">Aggiungi nota</x-filament::button>
</div>
</div>
</div>
<div class="mt-4 grid gap-4 lg:grid-cols-2">
<div class="rounded-xl border bg-white p-4">
<div class="text-sm font-semibold">Foto e documenti</div>
<label class="mt-3 block text-sm">
<span class="mb-1 block font-medium">Scatta foto (camera)</span>
<input type="file" wire:model="nuoveFoto" multiple accept="image/*" capture="environment" class="w-full rounded-lg border-gray-300 text-sm" />
</label>
<label class="mt-3 block text-sm">
<span class="mb-1 block font-medium">Allega file</span>
<input type="file" wire:model="nuoviAllegati" multiple accept="image/*,.pdf,.doc,.docx,.xls,.xlsx,.txt" class="w-full rounded-lg border-gray-300 text-sm" />
</label>
<label class="mt-3 block text-sm">
<span class="mb-1 block font-medium">Descrizione allegati</span>
<input type="text" wire:model.defer="descrizioneAllegati" class="w-full rounded-lg border-gray-300" placeholder="Es. foto danno balcone" />
</label>
<div class="mt-3">
<x-filament::button color="success" wire:click="caricaAllegati">Carica allegati</x-filament::button>
</div>
<div class="mt-4 grid gap-3 sm:grid-cols-2">
@forelse($ticket->attachments as $a)
<div class="rounded-xl border bg-white p-3 text-xs shadow-sm">
<div class="aspect-[4/3] rounded-lg border bg-gray-50 p-2">
@if($a->isImage())
<img src="{{ $this->getAttachmentPublicUrl($a) }}" alt="{{ $a->original_file_name }}" class="h-full w-full rounded object-cover" />
@else
<div class="flex h-full items-center justify-center text-center text-gray-500">
<div>
<div class="text-sm font-semibold">{{ strtoupper(pathinfo((string) $a->original_file_name, PATHINFO_EXTENSION) ?: ($a->isPdf() ? 'PDF' : 'FILE')) }}</div>
<div class="mt-1 text-[11px]">Anteprima disponibile in modal</div>
</div>
</div>
@endif
</div>
<div class="mt-2 font-medium">{{ $a->original_file_name }}</div>
<div class="mt-1 text-gray-600">{{ $a->description ?: 'Nessuna descrizione' }}</div>
<div class="mt-2 text-[11px] text-gray-500">{{ optional($a->created_at)->format('d/m/Y H:i') }}</div>
<button type="button" wire:click="openAttachmentPreview({{ (int) $a->id }})" class="mt-2 inline-flex items-center rounded-md bg-indigo-600 px-2 py-1 text-[11px] font-medium text-white hover:bg-indigo-500">Visualizza in modal</button>
</div>
@empty
<div class="text-xs text-gray-500">Nessun allegato.</div>
@endforelse
</div>
</div>
<div class="rounded-xl border bg-white p-4">
<div class="text-sm font-semibold">Storico interventi</div>
<div class="mt-3 space-y-2">
@forelse($ticket->interventi as $it)
<div class="rounded-md border p-2 text-xs">
<div class="font-medium">Stato: {{ $it->stato }}</div>
<div>
Fornitore:
{{ optional($it->fornitore)->ragione_sociale ?: trim((optional($it->fornitore)->nome ?? '') . ' ' . (optional($it->fornitore)->cognome ?? '')) ?: 'N/D' }}
</div>
@if($it->note_amministratore)
<div class="mt-1 whitespace-pre-wrap text-gray-600">{{ $it->note_amministratore }}</div>
@endif
</div>
@empty
<div class="text-xs text-gray-500">Nessun intervento registrato.</div>
@endforelse
</div>
</div>
</div>
<div class="mt-4 rounded-xl border bg-white p-4">
<div class="text-sm font-semibold">Storico note/messaggi</div>
<div class="mt-3 space-y-2">
@forelse($ticket->messages as $msg)
<div class="rounded-md border p-2 text-xs">
<div class="font-medium">{{ optional($msg->user)->name ?: 'Sistema' }}</div>
<div class="mt-1 whitespace-pre-wrap text-gray-700">{{ $msg->messaggio }}</div>
<div class="mt-1 text-gray-500">{{ optional($msg->created_at)->format('d/m/Y H:i') }}</div>
</div>
@empty
<div class="text-xs text-gray-500">Nessuna nota registrata.</div>
@endforelse
</div>
</div>
@endif
@endif
</div>
</div>
@if($attachmentPreview)
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4">
<div class="h-[92vh] w-full max-w-[96vw] rounded-xl bg-white shadow-2xl">
<div class="flex items-center justify-between border-b px-4 py-3">
<div>
<div class="text-sm font-semibold">{{ $attachmentPreview['name'] ?? 'Allegato' }}</div>
@if(!empty($attachmentPreview['description']))
<div class="text-xs text-gray-500">{{ $attachmentPreview['description'] }}</div>
@endif
</div>
<div class="flex items-center gap-2">
<a href="{{ $attachmentPreview['url'] }}" target="_blank" class="rounded-md bg-slate-100 px-2 py-1 text-xs hover:bg-slate-200">Apri in nuova scheda</a>
<button type="button" wire:click="closeAttachmentPreview" class="rounded-md bg-gray-100 px-2 py-1 text-xs hover:bg-gray-200">Chiudi</button>
</div>
</div>
<div class="h-[calc(92vh-64px)] overflow-auto p-4">
@if($attachmentPreview['is_image'] ?? false)
<img src="{{ $attachmentPreview['url'] }}" alt="Anteprima allegato" class="mx-auto max-h-[84vh] w-auto rounded border" />
@elseif($attachmentPreview['is_pdf'] ?? false)
<iframe src="{{ $attachmentPreview['url'] }}" class="h-[84vh] w-full rounded border"></iframe>
@else
<div class="rounded-md border bg-gray-50 p-4 text-sm text-gray-700">
Anteprima non disponibile per questo formato. Scarica o apri il file:
<a href="{{ $attachmentPreview['url'] }}" class="ml-1 text-primary-600 hover:underline">Apri file</a>
</div>
@endif
</div>
</div>
</div>
@endif
</x-filament-panels::page>