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; } }