fixe duploads and attachments now with colors tab and enhancements

This commit is contained in:
Mark Gregory
2026-06-16 19:01:26 +01:00
parent c19497efc2
commit f8ae45d810
8 changed files with 289 additions and 108 deletions
@@ -381,6 +381,7 @@
Uploading attachments...
</div>
@if ($ticket->attachments->isNotEmpty())
<div class="mt-4 space-y-3">
<div class="flex flex-wrap items-center justify-between gap-3 rounded-xl border border-emerald-500/30 bg-emerald-500/10 px-4 py-3">
<h3 class="inline-flex items-center gap-2 text-sm font-extrabold text-emerald-200">
@@ -396,10 +397,10 @@
</span>
</div>
@forelse ($ticket->attachments as $attachment)
@foreach ($ticket->attachments as $attachment)
<div class="flex flex-col gap-3 rounded-xl border border-zinc-700 bg-zinc-900 p-3 text-sm sm:flex-row sm:items-center sm:justify-between">
<a
href="{{ method_exists($attachment, 'url') ? $attachment->url() : Storage::disk($attachment->disk ?? 'public')->url($attachment->path ?? $attachment->file_path) }}"
href="{{ route('helpdesk.attachments.download', $attachment->id) }}"
target="_blank"
class="min-w-0 font-medium text-blue-300 hover:text-blue-200"
>
@@ -416,12 +417,9 @@
Remove
</button>
</div>
@empty
<div class="rounded-xl border border-dashed border-zinc-700 bg-zinc-900 px-4 py-3 text-sm text-zinc-400">
No ticket-level attachments are currently saved.
</div>
@endforelse
@endforeach
</div>
@endif
@if ($attachments !== [])
<div class="mt-4 rounded-xl border border-blue-500/30 bg-blue-500/10 px-4 py-3 text-sm text-blue-100">
@@ -198,6 +198,7 @@
<th class="px-4 py-3">Status</th>
<th class="px-4 py-3">Priority</th>
<th class="px-4 py-3">Agent</th>
<th class="px-4 py-3 text-center">Files</th>
<th class="px-4 py-3">Last activity</th>
</tr>
</thead>
@@ -216,11 +217,25 @@
<td class="px-4 py-3"><flux:badge color="{{ $ticket->status->color }}">{{ $ticket->status->name }}</flux:badge></td>
<td class="px-4 py-3"><flux:badge color="{{ $ticket->priority->color }}">{{ $ticket->priority->name }}</flux:badge></td>
<td class="px-4 py-3 text-zinc-600 dark:text-zinc-300">{{ $ticket->agent?->name ?? 'Unassigned' }}</td>
<td class="whitespace-nowrap px-4 py-3 text-center">
@if (($ticket->attachments_count ?? 0) > 0)
<span class="inline-flex items-center justify-center gap-1 rounded-full border border-blue-200 bg-blue-50 px-2.5 py-1 text-xs font-black text-blue-700 dark:border-blue-800 dark:bg-blue-950 dark:text-blue-200" title="{{ $ticket->attachments_count }} attachment{{ $ticket->attachments_count === 1 ? '' : 's' }}">
<i class="fa-solid fa-paperclip" aria-hidden="true"></i>
<span>{{ $ticket->attachments_count }}</span>
<span class="sr-only">attachment{{ $ticket->attachments_count === 1 ? '' : 's' }}</span>
</span>
@else
<span class="inline-flex items-center justify-center rounded-full border border-zinc-200 bg-zinc-50 px-2.5 py-1 text-xs font-bold text-zinc-400 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-500" title="No attachments">
<i class="fa-regular fa-circle" aria-hidden="true"></i>
<span class="sr-only">No attachments</span>
</span>
@endif
</td>
<td class="whitespace-nowrap px-4 py-3 text-zinc-500">{{ $ticket->last_activity_at?->diffForHumans() ?? $ticket->created_at->diffForHumans() }}</td>
</tr>
@empty
<tr>
<td colspan="6" class="px-4 py-12 text-center text-zinc-500">No tickets matched your filters.</td>
<td colspan="7" class="px-4 py-12 text-center text-zinc-500">No tickets matched your filters.</td>
</tr>
@endforelse
</tbody>
@@ -37,6 +37,7 @@
</div>
</article>
@if ($ticket->attachments->isNotEmpty())
<div class="overflow-hidden rounded-2xl border border-blue-200 bg-white shadow-sm dark:border-blue-900/60 dark:bg-zinc-900">
<div class="bg-gradient-to-r from-blue-700 via-sky-600 to-emerald-600 px-6 py-4 text-white">
<div class="flex items-center justify-between gap-4">
@@ -59,18 +60,15 @@
</div>
<div class="grid gap-3 p-6 sm:grid-cols-2">
@forelse ($ticket->attachments as $attachment)
<a href="{{ method_exists($attachment, 'url') ? $attachment->url() : Storage::disk($attachment->disk ?? 'public')->url($attachment->path ?? $attachment->file_path) }}" target="_blank" class="rounded-xl border border-zinc-200 p-3 text-sm hover:bg-zinc-50 dark:border-zinc-700 dark:hover:bg-zinc-800">
@foreach ($ticket->attachments as $attachment)
<a href="{{ route('helpdesk.attachments.download', $attachment->id) }}" target="_blank" class="rounded-xl border border-zinc-200 p-3 text-sm hover:bg-zinc-50 dark:border-zinc-700 dark:hover:bg-zinc-800">
<div class="font-medium text-zinc-900 dark:text-zinc-100">{{ $attachment->original_name ?? $attachment->original_filename ?? $attachment->filename ?? $attachment->file_name ?? basename($attachment->path ?? $attachment->file_path ?? '') }}</div>
<div class="text-xs text-zinc-500">{{ Number::fileSize($attachment->size ?? $attachment->size_bytes ?? 0) }}</div>
</a>
@empty
<div class="rounded-xl border border-dashed border-zinc-300 p-4 text-sm text-zinc-500 dark:border-zinc-700">
No ticket-level attachments are currently saved.
</div>
@endforelse
@endforeach
</div>
</div>
@endif
<section class="space-y-4">
<h2 class="text-lg font-semibold text-zinc-900 dark:text-white">Conversation</h2>
@@ -204,37 +202,65 @@
@can('update', $ticket)
<div class="rounded-2xl border border-zinc-200 bg-white p-5 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
<h2 class="mb-4 text-base font-semibold text-zinc-900 dark:text-white">Agent actions</h2>
<label class="mb-2 block text-sm font-medium text-zinc-700 dark:text-zinc-200" for="show_agent_id">Assigned agent</label>
<select
id="show_agent_id"
wire:model.live="agent_id"
class="block w-full rounded-lg border border-zinc-300 bg-white p-2 text-sm dark:border-zinc-700 dark:bg-zinc-950"
data-dusk="ticket-show-agent"
>
<option value="">Unassigned</option>
@forelse ($agents as $agent)
<option value="{{ $agent->id }}">{{ $agent->name }} · {{ $agent->email }}</option>
@empty
<option value="" disabled>No users available for assignment</option>
@endforelse
</select>
<flux:button dusk="update-agent" wire:click="updateAgent" class="mt-4 mb-5 w-full !bg-emerald-600 !text-white hover:!bg-emerald-700 focus:!ring-emerald-400/60" variant="primary" icon="user">Update assigned agent</flux:button>
<div class="mb-5 rounded-2xl bg-gradient-to-r from-blue-700 via-indigo-700 to-violet-700 px-4 py-4 text-white shadow-sm">
<p class="text-xs font-black uppercase tracking-[0.24em] text-blue-100">Ticket controls</p>
<h2 class="mt-1 text-lg font-black tracking-tight">Assignment, status and priority</h2>
<p class="mt-1 text-sm font-semibold text-blue-100/90">Use the explicit update buttons below to save each change.</p>
</div>
<flux:select wire:model="status_id" label="Status">
@foreach ($statuses as $status)
<option value="{{ $status->id }}">{{ $status->name }}</option>
@endforeach
</flux:select>
<flux:button dusk="update-status" wire:click="updateStatus" class="mt-4 w-full !bg-blue-600 !text-white hover:!bg-blue-700 focus:!ring-blue-400/60" variant="primary" icon="check">Update status</flux:button>
<div class="mt-5">
<flux:select wire:model="priority_id" label="Priority">
@if (session('ticket-action-updated'))
<div class="mb-5 rounded-xl border border-emerald-200 bg-emerald-50 px-3 py-2 text-sm font-bold text-emerald-800 dark:border-emerald-800 dark:bg-emerald-950 dark:text-emerald-100">
{{ session('ticket-action-updated') }}
</div>
@endif
<form wire:submit.prevent="updateAgent" class="mb-6 space-y-3">
<label class="block text-sm font-bold text-zinc-700 dark:text-zinc-200" for="show_agent_id">Assigned agent</label>
<select id="show_agent_id" wire:model.live="agent_id" class="hd-select block w-full rounded-xl border border-zinc-300 bg-white p-3 text-sm font-bold text-zinc-900 shadow-sm focus:border-emerald-500 focus:ring-emerald-500 dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-100" data-dusk="ticket-show-agent">
<option value="">Unassigned</option>
@forelse ($agents as $agent)
<option value="{{ $agent->id }}">{{ $agent->name }} · {{ $agent->email }}</option>
@empty
<option value="" disabled>No users available for assignment</option>
@endforelse
</select>
@error('agent_id') <p class="text-sm font-bold text-red-600 dark:text-red-400">{{ $message }}</p> @enderror
<button type="submit" dusk="update-agent" class="inline-flex w-full items-center justify-center rounded-xl bg-emerald-600 px-4 py-2.5 text-sm font-black text-white shadow-sm transition hover:bg-emerald-700 focus:outline-none focus:ring-2 focus:ring-emerald-400/70 disabled:cursor-not-allowed disabled:opacity-70" wire:loading.attr="disabled" wire:target="updateAgent">
<i class="fa-solid fa-user-check mr-2" aria-hidden="true"></i>
<span wire:loading.remove wire:target="updateAgent">Assign agent</span>
<span wire:loading wire:target="updateAgent">Assigning...</span>
</button>
</form>
<form wire:submit.prevent="updateStatus" class="mb-6 space-y-3">
<label class="block text-sm font-bold text-zinc-700 dark:text-zinc-200" for="show_status_id">Status</label>
<select id="show_status_id" wire:model.live="status_id" class="hd-select block w-full rounded-xl border border-zinc-300 bg-white p-3 text-sm font-bold text-zinc-900 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-100" data-dusk="ticket-show-status">
@foreach ($statuses as $status)
<option value="{{ $status->id }}">{{ $status->name }}</option>
@endforeach
</select>
@error('status_id') <p class="text-sm font-bold text-red-600 dark:text-red-400">{{ $message }}</p> @enderror
<button type="submit" dusk="update-status" class="inline-flex w-full items-center justify-center rounded-xl bg-blue-600 px-4 py-2.5 text-sm font-black text-white shadow-sm transition hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400/70 disabled:cursor-not-allowed disabled:opacity-70" wire:loading.attr="disabled" wire:target="updateStatus">
<i class="fa-solid fa-circle-check mr-2" aria-hidden="true"></i>
<span wire:loading.remove wire:target="updateStatus">Update status</span>
<span wire:loading wire:target="updateStatus">Updating...</span>
</button>
</form>
<form wire:submit.prevent="updatePriority" class="space-y-3">
<label class="block text-sm font-bold text-zinc-700 dark:text-zinc-200" for="show_priority_id">Priority</label>
<select id="show_priority_id" wire:model.live="priority_id" class="hd-select block w-full rounded-xl border border-zinc-300 bg-white p-3 text-sm font-bold text-zinc-900 shadow-sm focus:border-amber-500 focus:ring-amber-500 dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-100" data-dusk="ticket-show-priority">
@foreach ($priorities as $priority)
<option value="{{ $priority->id }}">{{ $priority->name }}</option>
@endforeach
</flux:select>
<flux:button dusk="update-priority" wire:click="updatePriority" class="mt-4 w-full !bg-amber-500 !text-white hover:!bg-amber-600 focus:!ring-amber-300/60" variant="ghost" icon="flag">Update priority</flux:button>
</div>
</select>
@error('priority_id') <p class="text-sm font-bold text-red-600 dark:text-red-400">{{ $message }}</p> @enderror
<button type="submit" dusk="update-priority" class="inline-flex w-full items-center justify-center rounded-xl bg-amber-500 px-4 py-2.5 text-sm font-black text-white shadow-sm transition hover:bg-amber-600 focus:outline-none focus:ring-2 focus:ring-amber-300/70 disabled:cursor-not-allowed disabled:opacity-70" wire:loading.attr="disabled" wire:target="updatePriority">
<i class="fa-solid fa-flag mr-2" aria-hidden="true"></i>
<span wire:loading.remove wire:target="updatePriority">Update priority</span>
<span wire:loading wire:target="updatePriority">Updating...</span>
</button>
</form>
</div>
@endcan
</aside>