250 lines
13 KiB
PHP
250 lines
13 KiB
PHP
|
|
<style>
|
|
.hd-helpdesk-surface .hd-btn,
|
|
.hd-btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: .5rem;
|
|
border-radius: .85rem;
|
|
padding: .62rem 1.05rem;
|
|
font-size: .875rem;
|
|
line-height: 1.25rem;
|
|
font-weight: 800;
|
|
color: #ffffff !important;
|
|
text-decoration: none !important;
|
|
border: 1px solid rgba(255,255,255,.14);
|
|
box-shadow: 0 12px 28px rgba(0,0,0,.22);
|
|
transition: background-color .15s ease, transform .15s ease, box-shadow .15s ease;
|
|
}
|
|
.hd-helpdesk-surface .hd-btn:hover,
|
|
.hd-btn:hover {
|
|
transform: translateY(-1px);
|
|
box-shadow: 0 16px 34px rgba(0,0,0,.30);
|
|
}
|
|
.hd-helpdesk-surface .hd-btn-sm,
|
|
.hd-btn-sm {
|
|
border-radius: .65rem;
|
|
padding: .42rem .78rem;
|
|
font-size: .8125rem;
|
|
}
|
|
.hd-helpdesk-surface .hd-btn-blue,
|
|
.hd-btn-blue { background: #2563eb !important; }
|
|
.hd-helpdesk-surface .hd-btn-blue:hover,
|
|
.hd-btn-blue:hover { background: #1d4ed8 !important; }
|
|
.hd-helpdesk-surface .hd-btn-green,
|
|
.hd-btn-green { background: #16a34a !important; }
|
|
.hd-helpdesk-surface .hd-btn-green:hover,
|
|
.hd-btn-green:hover { background: #15803d !important; }
|
|
.hd-helpdesk-surface .hd-btn-amber,
|
|
.hd-btn-amber { background: #f59e0b !important; }
|
|
.hd-helpdesk-surface .hd-btn-amber:hover,
|
|
.hd-btn-amber:hover { background: #d97706 !important; }
|
|
.hd-helpdesk-surface .hd-btn-red,
|
|
.hd-btn-red { background: #dc2626 !important; }
|
|
.hd-helpdesk-surface .hd-btn-red:hover,
|
|
.hd-btn-red:hover { background: #b91c1c !important; }
|
|
.hd-helpdesk-surface .hd-btn-violet,
|
|
.hd-btn-violet { background: #7c3aed !important; }
|
|
.hd-helpdesk-surface .hd-btn-violet:hover,
|
|
.hd-btn-violet:hover { background: #6d28d9 !important; }
|
|
|
|
.hd-helpdesk-surface button[type="submit"],
|
|
.hd-helpdesk-surface button[data-flux-button][type="submit"] {
|
|
background: #16a34a !important;
|
|
color: #ffffff !important;
|
|
border-color: rgba(255,255,255,.14) !important;
|
|
}
|
|
.hd-helpdesk-surface button[wire\:click^="reset"],
|
|
.hd-helpdesk-surface button[wire\:target^="reset"] {
|
|
background: #f59e0b !important;
|
|
color: #ffffff !important;
|
|
border-color: rgba(255,255,255,.14) !important;
|
|
}
|
|
.hd-helpdesk-surface button[wire\:click^="edit"],
|
|
.hd-helpdesk-surface button[wire\:target^="edit"] {
|
|
background: #2563eb !important;
|
|
color: #ffffff !important;
|
|
border-color: rgba(255,255,255,.14) !important;
|
|
}
|
|
.hd-helpdesk-surface button[wire\:click^="delete"],
|
|
.hd-helpdesk-surface button[wire\:target^="delete"] {
|
|
background: #dc2626 !important;
|
|
color: #ffffff !important;
|
|
border-color: rgba(255,255,255,.14) !important;
|
|
}
|
|
|
|
.hd-select {
|
|
width: 100%;
|
|
min-height: 3.35rem;
|
|
border-radius: 1rem;
|
|
border: 1px solid #3f3f46 !important;
|
|
background: #09090b !important;
|
|
color: #f4f4f5 !important;
|
|
padding: .78rem 3rem .78rem 1rem;
|
|
font-weight: 800;
|
|
outline: none;
|
|
box-shadow: inset 0 1px 0 rgba(255,255,255,.05), 0 12px 26px rgba(0,0,0,.24);
|
|
}
|
|
.hd-select:focus {
|
|
border-color: #60a5fa !important;
|
|
box-shadow: 0 0 0 3px rgba(96,165,250,.38), inset 0 1px 0 rgba(255,255,255,.05);
|
|
}
|
|
|
|
.helpdesk-ticket-form,
|
|
.helpdesk-ticket-form * {
|
|
-webkit-tap-highlight-color: transparent;
|
|
}
|
|
.helpdesk-ticket-form input,
|
|
.helpdesk-ticket-form textarea,
|
|
.helpdesk-ticket-form select,
|
|
.helpdesk-ticket-form .select2-container--default .select2-selection--single,
|
|
.helpdesk-ticket-form .select2-container--default .select2-selection--multiple,
|
|
.helpdesk-ticket-form .select2-container--default .select2-selection__rendered,
|
|
.helpdesk-ticket-form .select2-container--default .select2-selection__choice {
|
|
background: #09090b !important;
|
|
background-color: #09090b !important;
|
|
color: #f4f4f5 !important;
|
|
border-color: #3f3f46 !important;
|
|
caret-color: #f4f4f5 !important;
|
|
opacity: 1 !important;
|
|
}
|
|
.helpdesk-ticket-form input:disabled,
|
|
.helpdesk-ticket-form textarea:disabled,
|
|
.helpdesk-ticket-form select:disabled,
|
|
.helpdesk-ticket-form .select2-container--disabled .select2-selection--single,
|
|
.helpdesk-ticket-form .select2-container--disabled .select2-selection--multiple,
|
|
.helpdesk-ticket-form [disabled],
|
|
.helpdesk-ticket-form [aria-disabled="true"] {
|
|
background: #09090b !important;
|
|
background-color: #09090b !important;
|
|
color: #a1a1aa !important;
|
|
opacity: 1 !important;
|
|
}
|
|
.helpdesk-ticket-form input:-webkit-autofill,
|
|
.helpdesk-ticket-form input:-webkit-autofill:hover,
|
|
.helpdesk-ticket-form input:-webkit-autofill:focus,
|
|
.helpdesk-ticket-form textarea:-webkit-autofill,
|
|
.helpdesk-ticket-form textarea:-webkit-autofill:hover,
|
|
.helpdesk-ticket-form textarea:-webkit-autofill:focus,
|
|
.helpdesk-ticket-form select:-webkit-autofill,
|
|
.helpdesk-ticket-form select:-webkit-autofill:hover,
|
|
.helpdesk-ticket-form select:-webkit-autofill:focus {
|
|
-webkit-text-fill-color: #f4f4f5 !important;
|
|
box-shadow: 0 0 0 1000px #09090b inset !important;
|
|
transition: background-color 9999s ease-in-out 0s;
|
|
}
|
|
</style>
|
|
|
|
<div class="hd-helpdesk-surface space-y-6" dusk="helpdesk-ticket-index">
|
|
<div class="overflow-hidden rounded-3xl border border-zinc-200 bg-white shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
|
|
<div class="bg-gradient-to-br from-slate-950 via-slate-900 to-blue-950 px-6 py-7 text-white">
|
|
<div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
|
|
<div>
|
|
<p class="text-xs font-semibold uppercase tracking-[0.28em] text-blue-200">Ticket management</p>
|
|
<h1 class="mt-2 text-3xl font-semibold tracking-tight">Active tickets</h1>
|
|
<p class="mt-2 max-w-3xl text-sm text-blue-100/90">Search, triage and manage support requests across companies, projects, teams, priorities and statuses.</p>
|
|
</div>
|
|
<div class="flex flex-wrap gap-2">
|
|
<a href="{{ route('helpdesk.index') }}" wire:navigate class="hd-btn hd-btn-blue">
|
|
<i class="fa-solid fa-chart-bar" aria-hidden="true"></i>
|
|
<span>Dashboard</span>
|
|
</a>
|
|
<a href="{{ route('helpdesk.tickets.create') }}" wire:navigate class="hd-btn hd-btn-green">
|
|
<i class="fa-solid fa-plus" aria-hidden="true"></i>
|
|
<span>+ New Ticket</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="rounded-2xl border border-zinc-200 bg-white p-4 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
|
|
<div class="grid gap-4 md:grid-cols-4">
|
|
<flux:input wire:model.live.debounce.350ms="search" icon="magnifying-glass" placeholder="Search reference, subject or body" />
|
|
|
|
<flux:select wire:model.live="scope">
|
|
<option value="open">Open tickets</option>
|
|
<option value="closed">Closed tickets</option>
|
|
<option value="all">All tickets</option>
|
|
</flux:select>
|
|
|
|
<flux:select wire:model.live="status">
|
|
<option value="">All statuses</option>
|
|
@foreach ($statuses as $status)
|
|
<option value="{{ $status->id }}">{{ $status->name }}</option>
|
|
@endforeach
|
|
</flux:select>
|
|
|
|
<flux:select wire:model.live="priority">
|
|
<option value="">All priorities</option>
|
|
@foreach ($priorities as $priority)
|
|
<option value="{{ $priority->id }}">{{ $priority->name }}</option>
|
|
@endforeach
|
|
</flux:select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
|
|
<div wire:loading.flex class="items-center gap-2 border-b border-zinc-200 bg-blue-50 px-4 py-3 text-sm text-blue-800 dark:border-zinc-700 dark:bg-blue-950 dark:text-blue-200">
|
|
<flux:icon.arrow-path class="size-4 animate-spin" /> Refreshing tickets...
|
|
</div>
|
|
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full divide-y divide-zinc-200 text-sm dark:divide-zinc-700">
|
|
<thead class="bg-zinc-50 text-left text-xs font-semibold uppercase tracking-wide text-zinc-500 dark:bg-zinc-800 dark:text-zinc-300">
|
|
<tr>
|
|
<th class="px-4 py-3">Reference</th>
|
|
<th class="px-4 py-3">Subject</th>
|
|
<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>
|
|
<tbody class="divide-y divide-zinc-100 dark:divide-zinc-800">
|
|
@forelse ($tickets as $ticket)
|
|
<tr class="hover:bg-zinc-50 dark:hover:bg-zinc-800/70">
|
|
<td class="whitespace-nowrap px-4 py-3 font-mono text-xs">
|
|
<a href="{{ route('helpdesk.tickets.show', $ticket) }}" wire:navigate class="font-semibold text-blue-700 hover:underline dark:text-blue-300">
|
|
{{ $ticket->reference }}
|
|
</a>
|
|
</td>
|
|
<td class="px-4 py-3">
|
|
<div class="font-medium text-zinc-900 dark:text-zinc-100">{{ $ticket->subject }}</div>
|
|
<div class="text-xs text-zinc-500">{{ $ticket->category?->name ?? 'No category' }} @if($ticket->project) · {{ $ticket->project->title }} @endif @if($ticket->team) · {{ $ticket->team->name }} @endif</div>
|
|
</td>
|
|
<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="7" class="px-4 py-12 text-center text-zinc-500">No tickets matched your filters.</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="border-t border-zinc-200 p-4 dark:border-zinc-700">
|
|
{{ $tickets->links() }}
|
|
</div>
|
|
</div>
|
|
</div>
|