From 66b24b65d4186d7dae4a053b89ded6cbd390a81b Mon Sep 17 00:00:00 2001 From: Mark Gregory Date: Thu, 18 Jun 2026 14:07:50 +0100 Subject: [PATCH] intial ticket fix partial delete fix --- Modules/Helpdesk/Livewire/TicketIndex.php | 32 ++-- .../views/livewire/ticket-index.blade.php | 39 +++-- Modules/Helpdesk/app/Livewire/TicketIndex.php | 160 ++++++++++++++++++ 3 files changed, 203 insertions(+), 28 deletions(-) create mode 100644 Modules/Helpdesk/app/Livewire/TicketIndex.php diff --git a/Modules/Helpdesk/Livewire/TicketIndex.php b/Modules/Helpdesk/Livewire/TicketIndex.php index b297ec8c..27298b10 100644 --- a/Modules/Helpdesk/Livewire/TicketIndex.php +++ b/Modules/Helpdesk/Livewire/TicketIndex.php @@ -21,11 +21,13 @@ final class TicketIndex extends Component use AuthorizesRequests; use WithPagination; - public bool $confirmingTicketDeletion = false; + public bool $deleteModalOpen = false; - public ?int $ticketDeletionId = null; + public ?int $pendingDeleteTicketId = null; - public ?string $ticketDeletionReference = null; + public ?string $pendingDeleteTicketReference = null; + + public ?string $pendingDeleteTicketSubject = null; #[Url] public string $search = ''; @@ -47,18 +49,19 @@ final class TicketIndex extends Component /** * Open the delete confirmation modal for a visible ticket. */ - public function confirmDeleteTicket(int $ticketId): void + public function askToDeleteTicket(int $ticketId): void { $ticket = Ticket::query() ->visibleTo(Auth::user()) ->findOrFail($ticketId); - $this->ticketDeletionId = $ticket->id; - $this->ticketDeletionReference = $ticket->reference; - $this->confirmingTicketDeletion = true; + $this->pendingDeleteTicketId = $ticket->id; + $this->pendingDeleteTicketReference = $ticket->reference; + $this->pendingDeleteTicketSubject = $ticket->subject; + $this->deleteModalOpen = true; } - public function cancelDeleteTicket(): void + public function cancelTicketDelete(): void { $this->resetTicketDeletionState(); } @@ -66,9 +69,9 @@ final class TicketIndex extends Component /** * Delete the confirmed ticket. */ - public function deleteConfirmedTicket(): void + public function confirmTicketDelete(): void { - if ($this->ticketDeletionId === null) { + if ($this->pendingDeleteTicketId === null) { $this->resetTicketDeletionState(); return; @@ -76,7 +79,7 @@ final class TicketIndex extends Component $ticket = Ticket::query() ->visibleTo(Auth::user()) - ->findOrFail($this->ticketDeletionId); + ->findOrFail($this->pendingDeleteTicketId); $this->authorize('delete', $ticket); @@ -106,9 +109,10 @@ final class TicketIndex extends Component private function resetTicketDeletionState(): void { - $this->confirmingTicketDeletion = false; - $this->ticketDeletionId = null; - $this->ticketDeletionReference = null; + $this->deleteModalOpen = false; + $this->pendingDeleteTicketId = null; + $this->pendingDeleteTicketReference = null; + $this->pendingDeleteTicketSubject = null; } /** diff --git a/Modules/Helpdesk/Resources/views/livewire/ticket-index.blade.php b/Modules/Helpdesk/Resources/views/livewire/ticket-index.blade.php index 6b8e3043..39379e86 100644 --- a/Modules/Helpdesk/Resources/views/livewire/ticket-index.blade.php +++ b/Modules/Helpdesk/Resources/views/livewire/ticket-index.blade.php @@ -1,4 +1,4 @@ - +
-
@@ -158,6 +157,7 @@
+
@@ -237,8 +237,10 @@ @can('delete', $ticket)
- @if ($confirmingTicketDeletion) + + @if ($deleteModalOpen)
-
+
+ @if ($pendingDeleteTicketSubject) +
+

Ticket subject

+

{{ $pendingDeleteTicketSubject }}

+
+ @endif +

- Confirm only if this ticket was created in error or is no longer required. Related ticket data may also be removed depending on the model relationships. + Confirm only if this ticket was created in error or is no longer required.

diff --git a/Modules/Helpdesk/app/Livewire/TicketIndex.php b/Modules/Helpdesk/app/Livewire/TicketIndex.php new file mode 100644 index 00000000..5a511261 --- /dev/null +++ b/Modules/Helpdesk/app/Livewire/TicketIndex.php @@ -0,0 +1,160 @@ +resetPage(); + } + } + + /** + * Open the delete confirmation modal for the selected visible ticket. + */ + public function askToDeleteTicket(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; + } + + /** + * Close the delete confirmation modal without deleting anything. + */ + public function cancelTicketDelete(): void + { + $this->resetDeleteModal(); + } + + /** + * Delete the selected ticket after explicit modal confirmation. + */ + public function confirmTicketDelete(): void + { + if ($this->pendingDeleteTicketId === null) { + $this->resetDeleteModal(); + + return; + } + + $ticket = Ticket::query() + ->visibleTo(Auth::user()) + ->findOrFail($this->pendingDeleteTicketId); + + $this->authorize('delete', $ticket); + + $reference = $ticket->reference; + + $ticket->delete(); + + $this->resetDeleteModal(); + $this->resetPage(); + + $this->dispatch( + 'wms:toast', + type: 'success', + title: 'Ticket deleted', + message: "Ticket {$reference} was deleted successfully.", + ); + } + + /** + * Render the ticket list. + */ + public function render(): View + { + return view('helpdesk::livewire.ticket-index', [ + 'tickets' => $this->tickets(), + 'statuses' => Status::query()->orderBy('sort_order')->get(), + 'priorities' => Priority::query()->orderBy('sort_order')->get(), + ])->layout('layouts.app'); + } + + /** + * Reset delete modal state. + */ + private function resetDeleteModal(): void + { + $this->deleteModalOpen = false; + $this->pendingDeleteTicketId = null; + $this->pendingDeleteTicketReference = null; + $this->pendingDeleteTicketSubject = null; + } + + /** + * Build paginated ticket results. + * + * @return LengthAwarePaginator + */ + private function tickets(): LengthAwarePaginator + { + $user = Auth::user(); + $search = trim($this->search); + + return Ticket::query() + ->with(['owner', 'agent', 'status', 'priority', 'category', 'project', 'team']) + ->withCount('attachments') + ->visibleTo($user) + ->when($this->scope === 'open', static fn (Builder $query): Builder => $query->whereNull('completed_at')) + ->when($this->scope === 'closed', static fn (Builder $query): Builder => $query->whereNotNull('completed_at')) + ->when($this->status !== '', fn (Builder $query): Builder => $query->where('status_id', (int) $this->status)) + ->when($this->priority !== '', fn (Builder $query): Builder => $query->where('priority_id', (int) $this->priority)) + ->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.'%'); + }); + }) + ->latest('last_activity_at') + ->paginate(15); + } +}