From c8408658c92424d7a8f95f7b18636c9586767e57 Mon Sep 17 00:00:00 2001 From: Mark Gregory Date: Thu, 27 Aug 2026 17:28:02 +0100 Subject: [PATCH] dark mode supoport and new design now with delet esupport --- .../Helpdesk/Livewire/ArchivedTicketIndex.php | 165 ++++++++++++++++++ Modules/Helpdesk/Livewire/TicketIndex.php | 51 +++--- Modules/Helpdesk/Routes/web.php | 2 + .../components/helpdesk/layouts/app.blade.php | 3 +- .../views/components/layouts/app.blade.php | 3 +- .../backend/views/layouts/app.blade.php | 3 +- .../livewire/archived-ticket-index.blade.php | 131 ++++++++++++++ .../helpdesk/livewire/ticket-index.blade.php | 66 +++---- 8 files changed, 365 insertions(+), 59 deletions(-) create mode 100644 Modules/Helpdesk/Livewire/ArchivedTicketIndex.php create mode 100644 resources/themes/backend/views/modules/helpdesk/livewire/archived-ticket-index.blade.php diff --git a/Modules/Helpdesk/Livewire/ArchivedTicketIndex.php b/Modules/Helpdesk/Livewire/ArchivedTicketIndex.php new file mode 100644 index 0000000..04ec3d2 --- /dev/null +++ b/Modules/Helpdesk/Livewire/ArchivedTicketIndex.php @@ -0,0 +1,165 @@ +resetPage(); + } + + public function restoreTicket(int $ticketId): void + { + $ticket = $this->archivedTicket($ticketId); + $this->authorize('delete', $ticket); + + $reference = $ticket->reference; + + $ticket->restore(); + $ticket->forceFill(['archived_at' => null])->save(); + + $this->resetPage(); + + $this->dispatch( + 'thredary:toast', + type: 'success', + title: 'Ticket restored', + message: "Ticket {$reference} was restored to the active ticket list.", + ); + } + + public function askToDeletePermanently(int $ticketId): void + { + $ticket = $this->archivedTicket($ticketId); + $this->authorize('delete', $ticket); + + $this->pendingDeleteTicketId = $ticket->id; + $this->pendingDeleteTicketReference = $ticket->reference; + $this->pendingDeleteTicketSubject = $ticket->subject; + $this->deleteModalOpen = true; + } + + public function cancelPermanentDelete(): void + { + $this->resetDeleteState(); + } + + public function deletePermanently(): void + { + if ($this->pendingDeleteTicketId === null) { + $this->resetDeleteState(); + return; + } + + $ticket = $this->archivedTicket($this->pendingDeleteTicketId); + $this->authorize('delete', $ticket); + $reference = $ticket->reference; + + DB::transaction(static function () use ($ticket): void { + $attachments = $ticket->attachments()->get(['id', 'disk', 'path']); + + foreach ($attachments as $attachment) { + if (filled($attachment->disk) && filled($attachment->path)) { + Storage::disk($attachment->disk)->delete($attachment->path); + } + } + + $ticket->forceDelete(); + }); + + $this->resetDeleteState(); + $this->resetPage(); + + $this->dispatch( + 'thredary:toast', + type: 'success', + title: 'Ticket permanently deleted', + message: "Ticket {$reference} and its archived data were permanently deleted.", + ); + } + + public function render(): View + { + return view('modules.helpdesk.livewire.archived-ticket-index', [ + 'tickets' => $this->tickets(), + ])->layout('layouts.app'); + } + + private function archivedTicket(int $ticketId): Ticket + { + return Ticket::query() + ->onlyTrashed() + ->visibleTo(Auth::user()) + ->findOrFail($ticketId); + } + + /** @return LengthAwarePaginator */ + private function tickets(): LengthAwarePaginator + { + $user = Auth::user(); + $search = trim($this->search); + + return Ticket::query() + ->onlyTrashed() + ->without('user') + ->select('helpdesk_tickets.*') + ->addSelect([ + 'requester_name' => User::query() + ->select('name') + ->whereColumn('users.id', 'helpdesk_tickets.user_id') + ->limit(1), + 'agent_name' => User::query() + ->select('name') + ->whereColumn('users.id', 'helpdesk_tickets.agent_id') + ->limit(1), + ]) + ->with(['status', 'priority', 'category', 'project', 'team']) + ->withCount('attachments') + ->visibleTo($user) + ->when($search !== '', static function (Builder $query) use ($search): Builder { + return $query->where(static function (Builder $subQuery) use ($search): void { + $subQuery->where('reference', 'like', '%'.$search.'%') + ->orWhere('subject', 'like', '%'.$search.'%') + ->orWhere('body', 'like', '%'.$search.'%'); + }); + }) + ->orderByDesc('archived_at') + ->orderByDesc('deleted_at') + ->paginate(15); + } + + private function resetDeleteState(): void + { + $this->deleteModalOpen = false; + $this->pendingDeleteTicketId = null; + $this->pendingDeleteTicketReference = null; + $this->pendingDeleteTicketSubject = null; + } +} diff --git a/Modules/Helpdesk/Livewire/TicketIndex.php b/Modules/Helpdesk/Livewire/TicketIndex.php index d4b30a4..e64f5cd 100644 --- a/Modules/Helpdesk/Livewire/TicketIndex.php +++ b/Modules/Helpdesk/Livewire/TicketIndex.php @@ -22,13 +22,13 @@ final class TicketIndex extends Component use AuthorizesRequests; use WithPagination; - public bool $deleteModalOpen = false; + public bool $archiveModalOpen = false; - public ?int $pendingDeleteTicketId = null; + public ?int $pendingArchiveTicketId = null; - public ?string $pendingDeleteTicketReference = null; + public ?string $pendingArchiveTicketReference = null; - public ?string $pendingDeleteTicketSubject = null; + public ?string $pendingArchiveTicketSubject = null; #[Url] public string $search = ''; @@ -48,54 +48,55 @@ final class TicketIndex extends Component } /** - * Open the delete confirmation modal for a visible ticket. + * Open the archive confirmation modal for a visible ticket. */ - public function askToDeleteTicket(int $ticketId): void + public function askToArchiveTicket(int $ticketId): void { $ticket = Ticket::query() ->visibleTo(Auth::user()) ->findOrFail($ticketId); - $this->pendingDeleteTicketId = $ticket->id; - $this->pendingDeleteTicketReference = $ticket->reference; - $this->pendingDeleteTicketSubject = $ticket->subject; - $this->deleteModalOpen = true; + $this->pendingArchiveTicketId = $ticket->id; + $this->pendingArchiveTicketReference = $ticket->reference; + $this->pendingArchiveTicketSubject = $ticket->subject; + $this->archiveModalOpen = true; } - public function cancelTicketDelete(): void + public function cancelTicketArchive(): void { - $this->resetTicketDeletionState(); + $this->resetTicketArchiveState(); } /** - * Delete the confirmed ticket. + * Archive the confirmed ticket using Laravel soft deletes. */ - public function confirmTicketDelete(): void + public function confirmTicketArchive(): void { - if ($this->pendingDeleteTicketId === null) { - $this->resetTicketDeletionState(); + if ($this->pendingArchiveTicketId === null) { + $this->resetTicketArchiveState(); return; } $ticket = Ticket::query() ->visibleTo(Auth::user()) - ->findOrFail($this->pendingDeleteTicketId); + ->findOrFail($this->pendingArchiveTicketId); $this->authorize('delete', $ticket); $reference = $ticket->reference; + $ticket->forceFill(['archived_at' => now()])->save(); $ticket->delete(); - $this->resetTicketDeletionState(); + $this->resetTicketArchiveState(); $this->resetPage(); $this->dispatch( 'thredary:toast', type: 'success', - title: 'Ticket deleted', - message: "Ticket {$reference} was deleted successfully.", + title: 'Ticket archived', + message: "Ticket {$reference} was moved to the archive.", ); } @@ -108,12 +109,12 @@ final class TicketIndex extends Component ])->layout('layouts.app'); } - private function resetTicketDeletionState(): void + private function resetTicketArchiveState(): void { - $this->deleteModalOpen = false; - $this->pendingDeleteTicketId = null; - $this->pendingDeleteTicketReference = null; - $this->pendingDeleteTicketSubject = null; + $this->archiveModalOpen = false; + $this->pendingArchiveTicketId = null; + $this->pendingArchiveTicketReference = null; + $this->pendingArchiveTicketSubject = null; } /** diff --git a/Modules/Helpdesk/Routes/web.php b/Modules/Helpdesk/Routes/web.php index 353f833..ebd6a17 100644 --- a/Modules/Helpdesk/Routes/web.php +++ b/Modules/Helpdesk/Routes/web.php @@ -13,6 +13,7 @@ use Modules\Helpdesk\Http\Controllers\TicketControlsController; use Modules\Helpdesk\Http\Controllers\TicketStoreController; use Modules\Helpdesk\Http\Controllers\TicketTimeLogController; use Modules\Helpdesk\Http\Controllers\WorkflowOpenController; +use Modules\Helpdesk\Livewire\ArchivedTicketIndex; use Modules\Helpdesk\Livewire\KanbanBoard; use Modules\Helpdesk\Livewire\SettingsManager; use Modules\Helpdesk\Livewire\TicketCreate; @@ -28,6 +29,7 @@ Route::get('/settings', SettingsManager::class)->name('settings'); Route::get('/kanban', KanbanBoard::class)->name('kanban'); Route::get('/tickets', TicketIndex::class)->name('tickets.index'); +Route::get('/tickets/archived', ArchivedTicketIndex::class)->name('tickets.archived'); Route::post('/tickets', TicketStoreController::class)->name('tickets.store'); Route::get('/tickets/create', TicketCreate::class)->name('tickets.create'); Route::get('/tickets/{ticket}/edit', TicketEdit::class)->name('tickets.edit'); diff --git a/resources/themes/backend/views/components/helpdesk/layouts/app.blade.php b/resources/themes/backend/views/components/helpdesk/layouts/app.blade.php index ad2c8d0..baeadb6 100644 --- a/resources/themes/backend/views/components/helpdesk/layouts/app.blade.php +++ b/resources/themes/backend/views/components/helpdesk/layouts/app.blade.php @@ -138,7 +138,8 @@
Helpdesk
- @if(Route::has('helpdesk.tickets.index'))Tickets@endif + @if(Route::has('helpdesk.tickets.index'))Tickets@endif + @if(Route::has('helpdesk.tickets.archived'))Archive@endif @if(Route::has('helpdesk.kanban'))Kanban@endif @if(Route::has('helpdesk.settings'))Settings@endif
diff --git a/resources/themes/backend/views/components/layouts/app.blade.php b/resources/themes/backend/views/components/layouts/app.blade.php index ad2c8d0..baeadb6 100644 --- a/resources/themes/backend/views/components/layouts/app.blade.php +++ b/resources/themes/backend/views/components/layouts/app.blade.php @@ -138,7 +138,8 @@
Helpdesk
- @if(Route::has('helpdesk.tickets.index'))Tickets@endif + @if(Route::has('helpdesk.tickets.index'))Tickets@endif + @if(Route::has('helpdesk.tickets.archived'))Archive@endif @if(Route::has('helpdesk.kanban'))Kanban@endif @if(Route::has('helpdesk.settings'))Settings@endif
diff --git a/resources/themes/backend/views/layouts/app.blade.php b/resources/themes/backend/views/layouts/app.blade.php index b2e53cf..9aa6dfe 100644 --- a/resources/themes/backend/views/layouts/app.blade.php +++ b/resources/themes/backend/views/layouts/app.blade.php @@ -138,7 +138,8 @@
Helpdesk
- @if(Route::has('helpdesk.tickets.index'))Tickets@endif + @if(Route::has('helpdesk.tickets.index'))Tickets@endif + @if(Route::has('helpdesk.tickets.archived'))Archive@endif @if(Route::has('helpdesk.kanban'))Kanban@endif @if(Route::has('helpdesk.settings'))Settings@endif
diff --git a/resources/themes/backend/views/modules/helpdesk/livewire/archived-ticket-index.blade.php b/resources/themes/backend/views/modules/helpdesk/livewire/archived-ticket-index.blade.php new file mode 100644 index 0000000..612e39d --- /dev/null +++ b/resources/themes/backend/views/modules/helpdesk/livewire/archived-ticket-index.blade.php @@ -0,0 +1,131 @@ +
+
+
+
+
+

Ticket archive

+

Archived tickets

+

+ Restore tickets to active work or permanently remove tickets that are no longer required. +

+
+ + Active tickets + +
+
+
+ +
+
+ + +
+
+ +
+
+ + + + + + + + + + + @forelse ($tickets as $ticket) + + + + + + + + + + @empty + + + + @endforelse + +
ReferenceSubjectStatusRequesterArchivedFilesActions
{{ $ticket->reference }} +
{{ $ticket->subject }}
+
+ {{ $ticket->category?->name ?? 'No category' }} + @if ($ticket->project) · {{ $ticket->project->title }} @endif + @if ($ticket->team) · {{ $ticket->team->name }} @endif +
+
+ + {{ $ticket->status?->name ?? 'No status' }} + + {{ $ticket->requester_name ?? 'Unknown' }} +
{{ ($ticket->archived_at ?? $ticket->deleted_at)?->format('d M Y H:i') }}
+
{{ ($ticket->archived_at ?? $ticket->deleted_at)?->diffForHumans() }}
+
+ + {{ $ticket->attachments_count ?? 0 }} + + +
+ + @can('delete', $ticket) + + @endcan +
+
+ + + +

Archive is empty

+

Tickets that you archive will appear here and can be restored later.

+
+
+
+
{{ $tickets->total() }} archived ticket{{ $tickets->total() === 1 ? '' : 's' }}
+
@if ($tickets->hasPages()) {{ $tickets->onEachSide(1)->links() }} @endif
+
+
+ + @if ($deleteModalOpen) + + @endif +
diff --git a/resources/themes/backend/views/modules/helpdesk/livewire/ticket-index.blade.php b/resources/themes/backend/views/modules/helpdesk/livewire/ticket-index.blade.php index 5fc0a67..3c7331b 100644 --- a/resources/themes/backend/views/modules/helpdesk/livewire/ticket-index.blade.php +++ b/resources/themes/backend/views/modules/helpdesk/livewire/ticket-index.blade.php @@ -18,6 +18,10 @@ New Ticket + + + Archived + @@ -144,12 +148,12 @@ @can('delete', $ticket) - @endcan @@ -184,62 +188,62 @@ - @if ($deleteModalOpen) + @if ($archiveModalOpen)