From a3ac5161385f5ec68294f633d6c56f20f08c7555 Mon Sep 17 00:00:00 2001 From: Mark Gregory Date: Wed, 17 Jun 2026 13:23:52 +0100 Subject: [PATCH] ui updates for ticket layout now with multipel attachments --- .../TicketAttachmentStoreController.php | 49 +++++ Modules/Helpdesk/Livewire/KanbanBoard.php | 22 ++- Modules/Helpdesk/Livewire/TicketEdit.php | 10 +- .../views/livewire/kanban-board.blade.php | 16 +- .../views/livewire/ticket-edit.blade.php | 7 +- .../views/livewire/ticket-show.blade.php | 173 ++++++++++-------- Modules/Helpdesk/Routes/web.php | 2 + Modules/Helpdesk/changelog.yaml | 10 +- 8 files changed, 187 insertions(+), 102 deletions(-) create mode 100644 Modules/Helpdesk/Http/Controllers/TicketAttachmentStoreController.php diff --git a/Modules/Helpdesk/Http/Controllers/TicketAttachmentStoreController.php b/Modules/Helpdesk/Http/Controllers/TicketAttachmentStoreController.php new file mode 100644 index 00000000..60d2d092 --- /dev/null +++ b/Modules/Helpdesk/Http/Controllers/TicketAttachmentStoreController.php @@ -0,0 +1,49 @@ +validate([ + 'attachments' => ['required', 'array', 'min:1'], + 'attachments.*' => ['required', 'file', 'max:'.$maxUploadKilobytes, 'mimes:'.implode(',', $allowedMimes)], + ], [ + 'attachments.required' => 'Choose at least one supporting file.', + 'attachments.*.file' => 'Each supporting file must be a valid uploaded file.', + ]); + + $user = Auth::user(); + abort_if($user === null, 403); + + $uploadedFiles = $request->file('attachments', []); + $uploadedFiles = is_array($uploadedFiles) ? array_values($uploadedFiles) : [$uploadedFiles]; + + $attachments->storeMany($ticket, $uploadedFiles, (int) $user->id); + + $ticket->forceFill(['last_activity_at' => now()])->save(); + + return redirect() + ->route('helpdesk.tickets.show', $ticket) + ->with('ticket-attachments-added', count($uploadedFiles).' supporting file'.(count($uploadedFiles) === 1 ? '' : 's').' attached.'); + } +} diff --git a/Modules/Helpdesk/Livewire/KanbanBoard.php b/Modules/Helpdesk/Livewire/KanbanBoard.php index 9326c1a3..c3273667 100644 --- a/Modules/Helpdesk/Livewire/KanbanBoard.php +++ b/Modules/Helpdesk/Livewire/KanbanBoard.php @@ -8,6 +8,7 @@ use Illuminate\Contracts\View\View; use Illuminate\Database\Eloquent\Collection; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; +use Livewire\Attributes\On; use Livewire\Component; use Modules\Helpdesk\Models\KanbanBoard as KanbanBoardModel; use Modules\Helpdesk\Models\Status; @@ -55,12 +56,13 @@ final class KanbanBoard extends Component Auth::user() ); - $this->board_id = $board?->id; + $this->skipRender(); $message = 'Ticket '.$ticket->reference.' moved from '.$oldStatusName.' to '.$status->name.'.'; session()->flash('success', $message); $this->dispatch('wms:toast', type: 'success', title: 'Ticket moved', message: $message); - $this->dispatch('helpdesk-kanban-ticket-moved', ticketId: (int) $ticket->id, statusId: (int) $status->id); + $this->dispatch('helpdesk-kanban-refresh'); + $this->dispatch('helpdesk-kanban-ticket-moved', ticketId: $ticket->id, statusId: $status->id); } /** @@ -95,10 +97,13 @@ final class KanbanBoard extends Component $fresh = $ticket->fresh(['status', 'priority', 'category', 'project', 'team', 'board']) ?? $ticket; $workflow->dispatch($fresh, 'ticket.updated', Auth::user()); + $this->skipRender(); + $message = 'Ticket '.$fresh->reference.' moved from '.$oldBoardName.' to '.$board->name.'.'; session()->flash('success', $message); $this->dispatch('wms:toast', type: 'success', title: 'Board changed', message: $message); - $this->dispatch('helpdesk-kanban-ticket-moved', ticketId: (int) $fresh->id, statusId: (int) $fresh->status_id); + $this->dispatch('helpdesk-kanban-refresh'); + $this->dispatch('helpdesk-kanban-ticket-moved', ticketId: $fresh->id, boardId: $board->id); } /** @@ -109,6 +114,17 @@ final class KanbanBoard extends Component $this->board_id = is_numeric($value) ? (int) $value : null; } + /** + * Refresh the board after a drag/drop move, board change or external ticket update. + */ + #[On('helpdesk-kanban-refresh')] + #[On('ticket-updated')] + #[On('ticket-moved')] + public function refreshBoard(): void + { + // Livewire will re-run render(), which reloads all board columns from the database. + } + /** * Render the Kanban board. */ diff --git a/Modules/Helpdesk/Livewire/TicketEdit.php b/Modules/Helpdesk/Livewire/TicketEdit.php index b6c3180a..d4ccaf7a 100644 --- a/Modules/Helpdesk/Livewire/TicketEdit.php +++ b/Modules/Helpdesk/Livewire/TicketEdit.php @@ -108,6 +108,7 @@ final class TicketEdit extends Component $this->validate(); $this->validate([ + 'attachments' => 'array', 'attachments.*' => 'file|max:'.config('helpdesk.max_upload_kb', 10240).'|mimes:'.implode(',', config('helpdesk.allowed_mimes', ['jpg', 'jpeg', 'png', 'pdf', 'txt', 'log', 'zip'])), 'tag_ids.*' => 'integer|exists:helpdesk_tags,id', ]); @@ -274,8 +275,9 @@ final class TicketEdit extends Component continue; } - $path = $upload->store('helpdesk/tickets/'.$this->ticket->id, 'public'); - $this->ticket->attachments()->create($this->attachmentPayload($upload, $path)); + $disk = (string) config('helpdesk.disk', 'local'); + $path = $upload->store('tickets/'.$this->ticket->id, $disk); + $this->ticket->attachments()->create($this->attachmentPayload($upload, $path, $disk)); } $this->attachments = []; @@ -287,14 +289,14 @@ final class TicketEdit extends Component * * @return array */ - private function attachmentPayload(TemporaryUploadedFile $upload, string $path): array + private function attachmentPayload(TemporaryUploadedFile $upload, string $path, string $disk): array { $table = 'helpdesk_attachments'; $payload = []; $columns = [ 'user_id' => Auth::id(), 'uploaded_by_id' => Auth::id(), - 'disk' => 'public', + 'disk' => $disk, 'path' => $path, 'file_path' => $path, 'filename' => basename($path), diff --git a/Modules/Helpdesk/Resources/views/livewire/kanban-board.blade.php b/Modules/Helpdesk/Resources/views/livewire/kanban-board.blade.php index 21fc396f..3ca0edce 100644 --- a/Modules/Helpdesk/Resources/views/livewire/kanban-board.blade.php +++ b/Modules/Helpdesk/Resources/views/livewire/kanban-board.blade.php @@ -199,7 +199,7 @@ } -
+
@@ -254,11 +254,11 @@ This board is being initialised with the default workflow statuses. Refresh the page if the columns do not appear immediately.
@else -
+
@foreach ($statuses as $status) @php($tickets = $ticketsByStatus[$status->id] ?? collect()) -
+
@@ -276,12 +276,12 @@ > @forelse ($tickets as $ticket)
@@ -411,7 +411,7 @@ if (!ticketId || !statusId) return; $wire.moveTicket(ticketId, statusId).then(function () { - initialiseHelpdeskKanban(); + $wire.dispatch('helpdesk-kanban-refresh'); }); }); }); @@ -420,8 +420,10 @@ initialiseHelpdeskKanban(); document.addEventListener('livewire:navigated', initialiseHelpdeskKanban); document.addEventListener('livewire:updated', initialiseHelpdeskKanban); - document.addEventListener('livewire:update', initialiseHelpdeskKanban); - document.addEventListener('helpdesk-kanban-ticket-moved', initialiseHelpdeskKanban); + document.addEventListener('helpdesk-kanban-ticket-moved', function () { + $wire.dispatch('helpdesk-kanban-refresh'); + setTimeout(initialiseHelpdeskKanban, 150); + }); @endscript
diff --git a/Modules/Helpdesk/Resources/views/livewire/ticket-edit.blade.php b/Modules/Helpdesk/Resources/views/livewire/ticket-edit.blade.php index c95f722a..73b20c67 100644 --- a/Modules/Helpdesk/Resources/views/livewire/ticket-edit.blade.php +++ b/Modules/Helpdesk/Resources/views/livewire/ticket-edit.blade.php @@ -3,18 +3,13 @@ 'resources/css/app.css', 'resources/js/app.js', ]) - @vite([ - 'Resources/assets/css/app.css', - 'Resources/assets/js/app.js', - ], 'build/helpdesk') - @include('helpdesk::partials.page-header', [ 'eyebrow' => 'Helpdesk', 'title' => 'Edit Ticket', 'subtitle' => 'Update ownership, assignment, workflow status, product/service, project, team, category, priority and ticket details.', ]) -
+
diff --git a/Modules/Helpdesk/Resources/views/livewire/ticket-show.blade.php b/Modules/Helpdesk/Resources/views/livewire/ticket-show.blade.php index b223fa5c..1ca2b5a2 100644 --- a/Modules/Helpdesk/Resources/views/livewire/ticket-show.blade.php +++ b/Modules/Helpdesk/Resources/views/livewire/ticket-show.blade.php @@ -307,106 +307,80 @@
-
-
-
-
- - - -
-

Ticket attachments

-

Supporting files

-

Attach multiple screenshots, documents, logs and evidence directly to this existing ticket.

-
-
- - - - {{ $ticket->attachments->count() }} file{{ $ticket->attachments->count() === 1 ? '' : 's' }} +
+ +
+ + +
+

Ticket attachments

+

Supporting files

+

Attach screenshots, documents, logs and evidence directly to this existing ticket.

+
-
-
- @if (session('ticket-supporting-files-added')) -
- {{ session('ticket-supporting-files-added') }} + + + {{ $ticket->attachments->count() }} file{{ $ticket->attachments->count() === 1 ? '' : 's' }} + + + + +
+ @if (session('ticket-attachments-added')) +
+ {{ session('ticket-attachments-added') }}
@endif - @can('comment', $ticket) -
-
+ @can('update', $ticket) + + @csrf +
- - + + Attach supporting evidence - - {{ count($supportingFiles) === 0 ? 'No files selected' : count($supportingFiles).' file'.(count($supportingFiles) === 1 ? '' : 's').' selected' }} - + No files selected
-
-
-
- Preparing selected files… -
- - @if (count($supportingFiles) > 0) -
-

Ready to attach

-
    - @foreach ($supportingFiles as $file) -
  • - {{ $file->getClientOriginalName() }} - {{ Number::fileSize((int) $file->getSize()) }} -
  • - @endforeach -
-
- @endif - - @error('supportingFiles')
{{ $message }}
@enderror - @error('supportingFiles.*')
{{ $message }}
@enderror -
+ @error('attachments')
{{ $message }}
@enderror + @error('attachments.*')
{{ $message }}
@enderror + @endcan @if ($ticket->attachments->isEmpty()) - -
+
@@ -577,6 +551,50 @@ @endif @endcan +
+ + + + + + + Attachments + Supporting files + Pin screenshots, logs and supporting documents. + + + + 0 files + + + + +
+
+
+
+ + + + + Attach supporting evidence + No files attached + +
+ +
+ +
+
+
+ @error('attachments.*')
{{ $message }}
@enderror +
+
+