621 lines
41 KiB
PHP
621 lines
41 KiB
PHP
<x-filament-panels::page>
|
|
<div class="space-y-4" x-data="{ mobileMenuOpen: false }">
|
|
{{-- Top Bar / Search & Quick Actions --}}
|
|
<div class="flex flex-col md:flex-row items-stretch md:items-center justify-between gap-3 bg-white dark:bg-gray-800 p-3 rounded-2xl shadow-sm border border-gray-200 dark:border-gray-700">
|
|
<div class="flex items-center gap-3 flex-1">
|
|
{{-- Gmail Search Box --}}
|
|
<div class="relative flex-1 max-w-2xl">
|
|
<div class="absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none text-gray-400">
|
|
<x-heroicon-o-magnifying-glass class="w-5 h-5" />
|
|
</div>
|
|
<input
|
|
type="text"
|
|
wire:model.live.debounce.300ms="searchQuery"
|
|
placeholder="Cerca nella posta {{ $tipoCasella === 'pec' ? 'PEC' : 'Ordinaria' }} (mittente, oggetto, testo)..."
|
|
class="w-full pl-10 pr-10 py-2.5 bg-gray-100 dark:bg-gray-900 border-none rounded-full text-sm text-gray-900 dark:text-gray-100 placeholder-gray-500 focus:ring-2 focus:ring-primary-500 transition"
|
|
>
|
|
@if($searchQuery)
|
|
<button
|
|
wire:click="$set('searchQuery', '')"
|
|
class="absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-gray-600"
|
|
>
|
|
<x-heroicon-m-x-mark class="w-5 h-5" />
|
|
</button>
|
|
@endif
|
|
</div>
|
|
|
|
{{-- Stabile Filter Dropdown --}}
|
|
<div class="w-64 hidden sm:block">
|
|
<select
|
|
wire:model.live="selectedStabileId"
|
|
class="w-full py-2 px-3 text-xs rounded-xl bg-gray-50 dark:bg-gray-900 border border-gray-300 dark:border-gray-700 text-gray-800 dark:text-gray-200 focus:ring-primary-500 focus:border-primary-500"
|
|
>
|
|
<option value="">-- Tutti gli Stabili Accessibili --</option>
|
|
@foreach($this->stabiliOptions as $stabileId => $stabileLabel)
|
|
<option value="{{ $stabileId }}">{{ $stabileLabel }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-center gap-2 justify-end">
|
|
<a
|
|
href="{{ $this->configMailboxUrl }}"
|
|
class="inline-flex items-center gap-1.5 px-3 py-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-700 dark:text-gray-200 text-xs font-semibold rounded-xl shadow-xs transition"
|
|
title="Configura parametri IMAP e credenziali della casella"
|
|
>
|
|
<x-heroicon-m-cog-6-tooth class="w-4 h-4 text-gray-500 dark:text-gray-300" />
|
|
<span>Configura IMAP</span>
|
|
</a>
|
|
|
|
<button
|
|
wire:click="syncNow"
|
|
wire:loading.attr="disabled"
|
|
type="button"
|
|
class="inline-flex items-center gap-2 px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-white text-xs font-semibold rounded-xl shadow-sm transition disabled:opacity-50"
|
|
>
|
|
<span wire:loading.remove wire:target="syncNow">
|
|
<x-heroicon-m-arrow-path class="w-4 h-4" />
|
|
</span>
|
|
<span wire:loading wire:target="syncNow" class="animate-spin">
|
|
<x-heroicon-m-arrow-path class="w-4 h-4" />
|
|
</span>
|
|
<span>Sincronizza IMAP (.EML)</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Main Layout: Sidebar + Message List / Detail --}}
|
|
<div class="grid grid-cols-1 md:grid-cols-12 gap-4 items-start">
|
|
{{-- Left Navigation Sidebar --}}
|
|
<div class="md:col-span-3 lg:col-span-2 space-y-3">
|
|
{{-- Compose Button --}}
|
|
<button
|
|
wire:click="openCompose"
|
|
type="button"
|
|
class="w-full flex items-center justify-center gap-3 px-6 py-3.5 bg-primary-600 hover:bg-primary-700 text-white rounded-2xl font-semibold shadow-md hover:shadow-lg transition-all transform active:scale-95"
|
|
>
|
|
<x-heroicon-m-pencil-square class="w-5 h-5" />
|
|
<span class="tracking-wide">Scrivi</span>
|
|
</button>
|
|
|
|
{{-- Folder Navigation --}}
|
|
<div class="bg-white dark:bg-gray-800 rounded-2xl p-2 shadow-sm border border-gray-200 dark:border-gray-700 space-y-1">
|
|
@php
|
|
$counts = $this->folderCounts;
|
|
@endphp
|
|
|
|
<button
|
|
wire:click="selectFolder('inbox')"
|
|
class="w-full flex items-center justify-between px-3 py-2 text-sm rounded-xl font-medium transition {{ $currentFolder === 'inbox' ? 'bg-primary-50 dark:bg-primary-950/50 text-primary-700 dark:text-primary-300 font-bold' : 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700/50' }}"
|
|
>
|
|
<div class="flex items-center gap-2.5">
|
|
<x-heroicon-o-inbox class="w-4 h-4" />
|
|
<span>In arrivo</span>
|
|
</div>
|
|
@if(($counts['unread'] ?? 0) > 0)
|
|
<span class="px-2 py-0.5 text-xs font-bold rounded-full bg-primary-600 text-white">
|
|
{{ $counts['unread'] }}
|
|
</span>
|
|
@else
|
|
<span class="text-xs text-gray-400">{{ $counts['inbox'] ?? 0 }}</span>
|
|
@endif
|
|
</button>
|
|
|
|
<button
|
|
wire:click="selectFolder('starred')"
|
|
class="w-full flex items-center justify-between px-3 py-2 text-sm rounded-xl font-medium transition {{ $currentFolder === 'starred' ? 'bg-amber-50 dark:bg-amber-950/50 text-amber-700 dark:text-amber-300 font-bold' : 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700/50' }}"
|
|
>
|
|
<div class="flex items-center gap-2.5">
|
|
<x-heroicon-o-star class="w-4 h-4 text-amber-500" />
|
|
<span>Speciali</span>
|
|
</div>
|
|
<span class="text-xs text-gray-400">{{ $counts['starred'] ?? 0 }}</span>
|
|
</button>
|
|
|
|
<button
|
|
wire:click="selectFolder('sent')"
|
|
class="w-full flex items-center justify-between px-3 py-2 text-sm rounded-xl font-medium transition {{ $currentFolder === 'sent' ? 'bg-blue-50 dark:bg-blue-950/50 text-blue-700 dark:text-blue-300 font-bold' : 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700/50' }}"
|
|
>
|
|
<div class="flex items-center gap-2.5">
|
|
<x-heroicon-o-paper-airplane class="w-4 h-4" />
|
|
<span>Inviati</span>
|
|
</div>
|
|
<span class="text-xs text-gray-400">{{ $counts['sent'] ?? 0 }}</span>
|
|
</button>
|
|
|
|
<button
|
|
wire:click="selectFolder('attachments')"
|
|
class="w-full flex items-center justify-between px-3 py-2 text-sm rounded-xl font-medium transition {{ $currentFolder === 'attachments' ? 'bg-purple-50 dark:bg-purple-950/50 text-purple-700 dark:text-purple-300 font-bold' : 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700/50' }}"
|
|
>
|
|
<div class="flex items-center gap-2.5">
|
|
<x-heroicon-o-paper-clip class="w-4 h-4 text-purple-500" />
|
|
<span>Con Allegati</span>
|
|
</div>
|
|
<span class="text-xs text-gray-400">{{ $counts['attachments'] ?? 0 }}</span>
|
|
</button>
|
|
</div>
|
|
|
|
{{-- Type indicator Card --}}
|
|
<div class="bg-gray-50 dark:bg-gray-800/60 rounded-2xl p-3 border border-gray-200 dark:border-gray-700 text-xs text-gray-600 dark:text-gray-400 space-y-1.5">
|
|
<div class="flex items-center gap-2 font-semibold text-gray-900 dark:text-gray-200">
|
|
@if($tipoCasella === 'pec')
|
|
<x-heroicon-m-shield-check class="w-4 h-4 text-emerald-500" />
|
|
<span>Canale PEC Certificato</span>
|
|
@else
|
|
<x-heroicon-m-envelope class="w-4 h-4 text-blue-500" />
|
|
<span>Posta Ordinaria / Gmail</span>
|
|
@endif
|
|
</div>
|
|
<p class="text-[11px] leading-relaxed">
|
|
I messaggi scaricati vengono salvati integralmente come file <code class="bg-gray-200 dark:bg-gray-900 px-1 py-0.5 rounded text-primary-600">.EML</code> nello storage dello stabile.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Main Message Center --}}
|
|
<div class="md:col-span-9 lg:col-span-10">
|
|
@if($this->selectedMessage)
|
|
{{-- MESSAGE DETAIL READER VIEW --}}
|
|
@php
|
|
$msg = $this->selectedMessage;
|
|
$meta = is_array($msg->metadata) ? $msg->metadata : [];
|
|
$attachments = is_array($msg->attachments) ? $msg->attachments : [];
|
|
$isStarred = $meta['is_starred'] ?? false;
|
|
@endphp
|
|
|
|
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden">
|
|
{{-- Top Action Toolbar --}}
|
|
<div class="flex items-center justify-between px-4 py-3 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900/50">
|
|
<div class="flex items-center gap-2">
|
|
<button
|
|
wire:click="closeMessage"
|
|
type="button"
|
|
class="inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-semibold rounded-lg bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-200 hover:bg-gray-300 dark:hover:bg-gray-600 transition"
|
|
>
|
|
<x-heroicon-m-arrow-left class="w-4 h-4" />
|
|
<span>Torna all'elenco</span>
|
|
</button>
|
|
|
|
<button
|
|
wire:click="toggleStar({{ $msg->id }})"
|
|
type="button"
|
|
class="p-1.5 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 text-gray-400 hover:text-amber-500 transition"
|
|
>
|
|
<x-heroicon-m-star class="w-5 h-5 {{ $isStarred ? 'text-amber-400 fill-current' : '' }}" />
|
|
</button>
|
|
</div>
|
|
|
|
<div class="flex items-center gap-2">
|
|
@if(! $msg->ticket_id)
|
|
<button
|
|
wire:click="createTicketFromMessage({{ $msg->id }})"
|
|
type="button"
|
|
class="inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-semibold rounded-lg bg-amber-500 hover:bg-amber-600 text-white shadow-sm transition"
|
|
>
|
|
<x-heroicon-m-ticket class="w-4 h-4" />
|
|
<span>Apri Ticket Stabile</span>
|
|
</button>
|
|
@else
|
|
<span class="inline-flex items-center gap-1 px-2.5 py-1 text-xs font-semibold rounded-lg bg-emerald-100 text-emerald-800 dark:bg-emerald-900/50 dark:text-emerald-300">
|
|
<x-heroicon-m-ticket class="w-4 h-4" />
|
|
<span>Ticket #{{ $msg->ticket_id }} Collegato</span>
|
|
</span>
|
|
@endif
|
|
|
|
<button
|
|
wire:click="deleteMessage({{ $msg->id }})"
|
|
onclick="return confirm('Vuoi davvero eliminare questo messaggio?')"
|
|
type="button"
|
|
class="p-1.5 rounded-lg text-gray-400 hover:text-rose-600 hover:bg-rose-50 dark:hover:bg-rose-950/50 transition"
|
|
>
|
|
<x-heroicon-o-trash class="w-5 h-5" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Message Header --}}
|
|
<div class="p-6 space-y-4 border-b border-gray-100 dark:border-gray-700/70">
|
|
<div class="flex items-start justify-between gap-4">
|
|
<h1 class="text-xl font-bold text-gray-900 dark:text-gray-100 leading-snug">
|
|
{{ $meta['subject'] ?? '(Nessun Oggetto)' }}
|
|
</h1>
|
|
|
|
@if($msg->stabile)
|
|
<span class="shrink-0 inline-flex items-center gap-1 px-2.5 py-1 text-xs font-semibold rounded-md bg-blue-50 text-blue-700 dark:bg-blue-950 dark:text-blue-300 border border-blue-200 dark:border-blue-800">
|
|
{{ $msg->stabile->codice_stabile }} - {{ $msg->stabile->denominazione }}
|
|
</span>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="flex items-center justify-between text-xs text-gray-500 dark:text-gray-400">
|
|
<div class="flex items-center gap-3">
|
|
<div class="w-9 h-9 rounded-full bg-primary-100 dark:bg-primary-900/60 text-primary-700 dark:text-primary-300 flex items-center justify-center font-bold text-sm">
|
|
{{ strtoupper(substr($msg->sender_name ?: 'A', 0, 1)) }}
|
|
</div>
|
|
<div>
|
|
<div class="font-bold text-gray-900 dark:text-gray-100 text-sm">
|
|
{{ $msg->sender_name ?: ($meta['sender_email'] ?? 'Mittente Sconosciuto') }}
|
|
</div>
|
|
<div>
|
|
A: <span class="font-medium text-gray-700 dark:text-gray-300">{{ $meta['recipient_email'] ?? 'Amministrazione' }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="text-right">
|
|
<div class="font-medium text-gray-700 dark:text-gray-300">
|
|
{{ $msg->received_at ? \Illuminate\Support\Carbon::parse($msg->received_at)->translatedFormat('d F Y, H:i') : '' }}
|
|
</div>
|
|
<div class="text-[11px] text-gray-400">
|
|
Canale: <span class="uppercase font-semibold">{{ $msg->channel }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Message Body Content --}}
|
|
<div class="p-6 bg-white dark:bg-gray-800 text-gray-800 dark:text-gray-200 text-sm leading-relaxed prose dark:prose-invert max-w-none">
|
|
@if(!empty($meta['body_html']))
|
|
<div class="border border-gray-100 dark:border-gray-700/50 p-4 rounded-xl bg-gray-50/50 dark:bg-gray-900/30 overflow-x-auto">
|
|
{!! $meta['body_html'] !!}
|
|
</div>
|
|
@else
|
|
<div class="whitespace-pre-wrap font-sans">
|
|
{{ $msg->message_text }}
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
{{-- Attachments Section --}}
|
|
@if(!empty($attachments))
|
|
<div class="p-6 bg-gray-50 dark:bg-gray-900/40 border-t border-gray-200 dark:border-gray-700">
|
|
<h3 class="text-xs font-bold uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-3 flex items-center gap-1.5">
|
|
<x-heroicon-m-paper-clip class="w-4 h-4 text-purple-500" />
|
|
<span>Allegati del messaggio ({{ count($attachments) }})</span>
|
|
</h3>
|
|
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
|
|
@foreach($attachments as $att)
|
|
@php
|
|
$fname = $att['filename'] ?? 'allegato';
|
|
$fsize = $att['size'] ?? 0;
|
|
$fpath = $att['path'] ?? '';
|
|
$ftype = $att['content_type'] ?? 'application/octet-stream';
|
|
$isImg = str_starts_with($ftype, 'image/');
|
|
$isPdf = str_contains($ftype, 'pdf') || str_ends_with(strtolower($fname), '.pdf');
|
|
@endphp
|
|
<div class="flex items-center justify-between p-3 rounded-xl bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 shadow-sm hover:border-primary-500 transition">
|
|
<div class="flex items-center gap-2.5 truncate">
|
|
@if($isImg)
|
|
<span class="text-rose-500">🖼️</span>
|
|
@elseif($isPdf)
|
|
<span class="text-red-500 font-bold">📄</span>
|
|
@else
|
|
<span class="text-blue-500">📎</span>
|
|
@endif
|
|
<div class="truncate">
|
|
<div class="text-xs font-semibold text-gray-800 dark:text-gray-200 truncate" title="{{ $fname }}">
|
|
{{ $fname }}
|
|
</div>
|
|
<div class="text-[10px] text-gray-400">
|
|
{{ number_format($fsize / 1024, 1) }} KB
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<button
|
|
wire:click="previewAttachment('{{ addslashes($fname) }}', '{{ addslashes($fpath) }}', '{{ addslashes($ftype) }}')"
|
|
type="button"
|
|
class="shrink-0 p-1.5 text-xs text-primary-600 hover:text-primary-800 font-semibold rounded-lg hover:bg-primary-50 dark:hover:bg-primary-950/50"
|
|
title="Visualizza allegato"
|
|
>
|
|
<x-heroicon-m-eye class="w-4 h-4" />
|
|
</button>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
@else
|
|
{{-- MESSAGES LIST VIEW (GMAIL STYLE) --}}
|
|
@php
|
|
$messages = $this->messages;
|
|
@endphp
|
|
|
|
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden">
|
|
{{-- Action Bar --}}
|
|
<div class="flex items-center justify-between px-4 py-2.5 bg-gray-50 dark:bg-gray-900/50 border-b border-gray-200 dark:border-gray-700 text-xs text-gray-500">
|
|
<div class="flex items-center gap-3">
|
|
<span class="font-semibold text-gray-700 dark:text-gray-300 capitalize">
|
|
{{ $currentFolder === 'inbox' ? 'Posta in arrivo' : ($currentFolder === 'sent' ? 'Messaggi inviati' : ($currentFolder === 'starred' ? 'Messaggi speciali' : 'Con allegati')) }}
|
|
</span>
|
|
@if($selectedStabileId)
|
|
<span class="px-2 py-0.5 rounded-full bg-blue-100 text-blue-800 dark:bg-blue-900/50 dark:text-blue-300 text-[11px]">
|
|
Filtro Stabile attivo
|
|
</span>
|
|
@endif
|
|
</div>
|
|
|
|
<div>
|
|
{{ $messages->total() }} messaggi totali
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Rows Table --}}
|
|
<div class="divide-y divide-gray-100 dark:divide-gray-700/60">
|
|
@forelse($messages as $msg)
|
|
@php
|
|
$meta = is_array($msg->metadata) ? $msg->metadata : [];
|
|
$attachments = is_array($msg->attachments) ? $msg->attachments : [];
|
|
$isUnread = $msg->status === 'received' && $msg->direction === 'inbound';
|
|
$isStarred = $meta['is_starred'] ?? false;
|
|
$dateStr = $msg->received_at ? \Illuminate\Support\Carbon::parse($msg->received_at)->diffForHumans() : '';
|
|
if ($msg->received_at) {
|
|
$dt = \Illuminate\Support\Carbon::parse($msg->received_at);
|
|
$dateFormatted = $dt->isToday() ? $dt->format('H:i') : ($dt->isCurrentYear() ? $dt->translatedFormat('j M') : $dt->format('d/m/Y'));
|
|
} else {
|
|
$dateFormatted = '';
|
|
}
|
|
@endphp
|
|
|
|
<div
|
|
wire:click="selectMessage({{ $msg->id }})"
|
|
class="group flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2 px-4 py-3 hover:bg-gray-50 dark:hover:bg-gray-700/40 cursor-pointer transition {{ $isUnread ? 'bg-primary-50/20 dark:bg-primary-950/20 font-semibold' : '' }}"
|
|
>
|
|
{{-- Left: Checkbox + Star + Sender --}}
|
|
<div class="flex items-center gap-3 w-full sm:w-1/4 shrink-0">
|
|
<button
|
|
wire:click.stop="toggleStar({{ $msg->id }})"
|
|
type="button"
|
|
class="text-gray-400 hover:text-amber-500 transition"
|
|
>
|
|
<x-heroicon-m-star class="w-5 h-5 {{ $isStarred ? 'text-amber-400 fill-current' : 'text-gray-300 dark:text-gray-600' }}" />
|
|
</button>
|
|
|
|
<div class="truncate">
|
|
<span class="text-sm {{ $isUnread ? 'font-bold text-gray-950 dark:text-white' : 'text-gray-700 dark:text-gray-300' }}">
|
|
{{ $msg->sender_name ?: ($meta['sender_email'] ?? 'Sconosciuto') }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Middle: Stabile Pill + Subject + Snippet + Attachment Pills --}}
|
|
<div class="flex-1 min-w-0 flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-2">
|
|
@if($msg->stabile)
|
|
<span class="shrink-0 px-2 py-0.5 text-[10px] font-bold rounded-md bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300 border border-gray-200 dark:border-gray-600">
|
|
{{ $msg->stabile->codice_stabile }}
|
|
</span>
|
|
@endif
|
|
|
|
<div class="truncate flex items-center gap-1.5 text-sm">
|
|
<span class="{{ $isUnread ? 'font-bold text-gray-900 dark:text-gray-100' : 'text-gray-800 dark:text-gray-200' }}">
|
|
{{ $meta['subject'] ?? '(Nessun oggetto)' }}
|
|
</span>
|
|
<span class="text-gray-400 font-normal truncate">
|
|
- {{ Str::limit(strip_tags($msg->message_text), 70) }}
|
|
</span>
|
|
</div>
|
|
|
|
{{-- Attachment Chips (Like Gmail) --}}
|
|
@if(!empty($attachments))
|
|
<div class="flex items-center gap-1 shrink-0 mt-1 sm:mt-0">
|
|
@foreach(array_slice($attachments, 0, 2) as $att)
|
|
@php
|
|
$fname = $att['filename'] ?? 'allegato';
|
|
$isPdf = str_ends_with(strtolower($fname), '.pdf');
|
|
$isImg = preg_match('/\.(jpg|jpeg|png|webp|gif)$/i', $fname);
|
|
@endphp
|
|
<span class="inline-flex items-center gap-1 px-2 py-0.5 text-[11px] rounded-full border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 shadow-2xs">
|
|
@if($isPdf)
|
|
<span class="text-red-500 font-bold text-[9px]">PDF</span>
|
|
@elseif($isImg)
|
|
<span class="text-amber-500 text-[9px]">IMG</span>
|
|
@else
|
|
<span class="text-blue-500 text-[9px]">📎</span>
|
|
@endif
|
|
<span class="truncate max-w-[90px]">{{ $fname }}</span>
|
|
</span>
|
|
@endforeach
|
|
@if(count($attachments) > 2)
|
|
<span class="text-[10px] text-gray-400 font-medium">+{{ count($attachments) - 2 }}</span>
|
|
@endif
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
{{-- Right: Date & Quick Actions on Hover --}}
|
|
<div class="flex items-center justify-end gap-2 shrink-0 text-xs text-gray-500 dark:text-gray-400 w-full sm:w-auto">
|
|
@if($msg->ticket_id)
|
|
<span class="px-1.5 py-0.5 text-[10px] font-bold rounded bg-amber-100 text-amber-800 dark:bg-amber-900/50 dark:text-amber-300" title="Ticket #{{ $msg->ticket_id }}">
|
|
🎟️ #{{ $msg->ticket_id }}
|
|
</span>
|
|
@endif
|
|
<span class="font-medium whitespace-nowrap">{{ $dateFormatted }}</span>
|
|
</div>
|
|
</div>
|
|
@empty
|
|
<div class="p-12 text-center text-gray-500 dark:text-gray-400 space-y-3">
|
|
<x-heroicon-o-envelope-open class="w-12 h-12 mx-auto text-gray-300 dark:text-gray-600" />
|
|
<div class="font-medium text-base text-gray-800 dark:text-gray-200">Nessun messaggio presente in questa cartella</div>
|
|
<p class="text-xs text-gray-400 max-w-md mx-auto">
|
|
Se non hai ancora configurato la casella IMAP o PEC, puoi inserire parametri e credenziali per abilitare lo scaricamento e la visualizzazione automatica.
|
|
</p>
|
|
<div class="flex flex-wrap items-center justify-center gap-2 pt-2">
|
|
<a
|
|
href="{{ $this->configMailboxUrl }}"
|
|
class="inline-flex items-center gap-1.5 px-3.5 py-2 bg-primary-600 hover:bg-primary-700 text-white text-xs font-semibold rounded-xl shadow-sm transition"
|
|
>
|
|
<x-heroicon-m-cog-6-tooth class="w-4 h-4" />
|
|
<span>Configura Casella Stabile</span>
|
|
</a>
|
|
<a
|
|
href="{{ url('/admin-filament/impostazioni/scheda-amministratore?tab=posta-operativita') }}"
|
|
class="inline-flex items-center gap-1.5 px-3.5 py-2 bg-gray-100 hover:bg-gray-200 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-800 dark:text-gray-200 text-xs font-semibold rounded-xl shadow-xs transition"
|
|
>
|
|
<x-heroicon-m-building-office-2 class="w-4 h-4" />
|
|
<span>Configura Caselle Studio</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
@endforelse
|
|
</div>
|
|
|
|
{{-- Pagination Footer --}}
|
|
@if($messages->hasPages())
|
|
<div class="p-3 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900/40">
|
|
{{ $messages->links() }}
|
|
</div>
|
|
@endif
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Compose Modal --}}
|
|
@if($isComposing)
|
|
<div class="fixed inset-0 z-50 overflow-y-auto bg-gray-900/50 backdrop-blur-xs flex items-center justify-center p-4">
|
|
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-2xl border border-gray-200 dark:border-gray-700 w-full max-w-2xl overflow-hidden animate-in fade-in zoom-in-95 duration-150">
|
|
<div class="flex items-center justify-between px-4 py-3 bg-gray-900 text-white">
|
|
<div class="font-bold text-sm flex items-center gap-2">
|
|
<x-heroicon-m-pencil-square class="w-4 h-4 text-primary-400" />
|
|
<span>Nuovo Messaggio ({{ strtoupper($tipoCasella) }})</span>
|
|
</div>
|
|
<button wire:click="closeCompose" type="button" class="text-gray-400 hover:text-white">
|
|
<x-heroicon-m-x-mark class="w-5 h-5" />
|
|
</button>
|
|
</div>
|
|
|
|
<form wire:submit="sendMessage" class="p-4 space-y-3">
|
|
<div>
|
|
<label class="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-1">Stabile di Riferimento</label>
|
|
<select
|
|
wire:model="composeStabileId"
|
|
class="w-full py-2 px-3 text-xs rounded-xl bg-gray-50 dark:bg-gray-900 border border-gray-300 dark:border-gray-700 text-gray-800 dark:text-gray-200"
|
|
>
|
|
<option value="">-- Seleziona Stabile --</option>
|
|
@foreach($this->stabiliOptions as $stabileId => $stabileLabel)
|
|
<option value="{{ $stabileId }}">{{ $stabileLabel }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
|
|
<div>
|
|
<input
|
|
type="text"
|
|
wire:model="composeTo"
|
|
placeholder="A: (destinatario@email.it)"
|
|
class="w-full py-2 px-3 text-sm rounded-xl bg-gray-50 dark:bg-gray-900 border border-gray-300 dark:border-gray-700 text-gray-800 dark:text-gray-200 focus:ring-primary-500"
|
|
>
|
|
</div>
|
|
|
|
<div>
|
|
<input
|
|
type="text"
|
|
wire:model="composeCc"
|
|
placeholder="Cc: (opzionale)"
|
|
class="w-full py-2 px-3 text-sm rounded-xl bg-gray-50 dark:bg-gray-900 border border-gray-300 dark:border-gray-700 text-gray-800 dark:text-gray-200 focus:ring-primary-500"
|
|
>
|
|
</div>
|
|
|
|
<div>
|
|
<input
|
|
type="text"
|
|
wire:model="composeSubject"
|
|
placeholder="Oggetto del messaggio"
|
|
class="w-full py-2 px-3 text-sm rounded-xl bg-gray-50 dark:bg-gray-900 border border-gray-300 dark:border-gray-700 text-gray-800 dark:text-gray-200 font-semibold focus:ring-primary-500"
|
|
>
|
|
</div>
|
|
|
|
<div>
|
|
<textarea
|
|
wire:model="composeBody"
|
|
rows="8"
|
|
placeholder="Scrivi il corpo della comunicazione..."
|
|
class="w-full py-2 px-3 text-sm rounded-xl bg-gray-50 dark:bg-gray-900 border border-gray-300 dark:border-gray-700 text-gray-800 dark:text-gray-200 focus:ring-primary-500"
|
|
></textarea>
|
|
</div>
|
|
|
|
<div class="flex items-center justify-end gap-2 pt-2 border-t border-gray-200 dark:border-gray-700">
|
|
<button
|
|
wire:click="closeCompose"
|
|
type="button"
|
|
class="px-4 py-2 text-xs font-semibold text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-xl transition"
|
|
>
|
|
Annulla
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
class="px-5 py-2 text-xs font-semibold bg-primary-600 hover:bg-primary-700 text-white rounded-xl shadow-md transition"
|
|
>
|
|
Invia Messaggio
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
{{-- Attachment Preview Modal --}}
|
|
@if($showAttachmentModal && $activeAttachment)
|
|
<div class="fixed inset-0 z-50 overflow-y-auto bg-gray-900/60 backdrop-blur-xs flex items-center justify-center p-4">
|
|
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-2xl border border-gray-200 dark:border-gray-700 w-full max-w-3xl overflow-hidden">
|
|
<div class="flex items-center justify-between px-4 py-3 bg-gray-100 dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700">
|
|
<div class="font-bold text-sm text-gray-800 dark:text-gray-200 truncate flex items-center gap-2">
|
|
<x-heroicon-m-paper-clip class="w-4 h-4 text-purple-500" />
|
|
<span>{{ $activeAttachment['filename'] }}</span>
|
|
</div>
|
|
<button wire:click="closeAttachmentModal" type="button" class="text-gray-400 hover:text-gray-700 dark:hover:text-gray-200">
|
|
<x-heroicon-m-x-mark class="w-5 h-5" />
|
|
</button>
|
|
</div>
|
|
|
|
<div class="p-4 max-h-[70vh] overflow-y-auto flex items-center justify-center bg-gray-50 dark:bg-gray-950">
|
|
@php
|
|
$fname = $activeAttachment['filename'];
|
|
$ftype = $activeAttachment['content_type'];
|
|
$fpath = $activeAttachment['path'];
|
|
$exists = $activeAttachment['exists'];
|
|
$isImg = str_starts_with($ftype, 'image/') || preg_match('/\.(jpg|jpeg|png|webp|gif)$/i', $fname);
|
|
$isPdf = str_contains($ftype, 'pdf') || str_ends_with(strtolower($fname), '.pdf');
|
|
@endphp
|
|
|
|
@if(! $exists)
|
|
<div class="text-center text-sm text-amber-600 p-6">
|
|
Il file dell'allegato non è al momento presente nel filesystem locale.
|
|
</div>
|
|
@elseif($isImg)
|
|
@php
|
|
$b64 = base64_encode(file_get_contents($fpath));
|
|
@endphp
|
|
<img src="data:{{ $ftype }};base64,{{ $b64 }}" alt="{{ $fname }}" class="max-h-[60vh] max-w-full rounded-lg object-contain shadow" />
|
|
@elseif($isPdf)
|
|
@php
|
|
$b64 = base64_encode(file_get_contents($fpath));
|
|
@endphp
|
|
<iframe src="data:application/pdf;base64,{{ $b64 }}" class="w-full h-[60vh] rounded-lg border border-gray-300 dark:border-gray-700"></iframe>
|
|
@else
|
|
<div class="text-center space-y-3 p-8">
|
|
<x-heroicon-o-document class="w-16 h-16 mx-auto text-gray-400" />
|
|
<div class="text-sm font-semibold text-gray-800 dark:text-gray-200">{{ $fname }}</div>
|
|
<div class="text-xs text-gray-400">Tipo: {{ $ftype }}</div>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="flex items-center justify-end gap-2 p-3 bg-gray-50 dark:bg-gray-900 border-t border-gray-200 dark:border-gray-700">
|
|
<button
|
|
wire:click="closeAttachmentModal"
|
|
type="button"
|
|
class="px-4 py-1.5 text-xs font-semibold text-gray-600 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 rounded-lg transition"
|
|
>
|
|
Chiudi
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</x-filament-panels::page>
|