|
| 1 | +<?php |
| 2 | + |
| 3 | +namespace App\Http\Livewire; |
| 4 | + |
| 5 | +use App\Jobs\TicketUpdatedJob; |
| 6 | +use App\Models\Ticket; |
| 7 | +use Filament\Notifications\Notification; |
| 8 | +use Illuminate\Support\Collection; |
| 9 | +use Illuminate\Support\HtmlString; |
| 10 | +use Illuminate\Support\Str; |
| 11 | +use InvadersXX\FilamentKanbanBoard\Pages\FilamentKanbanBoard; |
| 12 | + |
| 13 | +class Kanban extends FilamentKanbanBoard |
| 14 | +{ |
| 15 | + protected static ?string $title = ''; |
| 16 | + public bool $sortable = true; |
| 17 | + public bool $sortableBetweenStatuses = true; |
| 18 | + public bool $recordClickEnabled = true; |
| 19 | + |
| 20 | + /** |
| 21 | + * Statuses list Definition |
| 22 | + * |
| 23 | + * @return Collection |
| 24 | + */ |
| 25 | + protected function statuses(): Collection |
| 26 | + { |
| 27 | + return collect(statuses_list_for_kanban()); |
| 28 | + } |
| 29 | + |
| 30 | + /** |
| 31 | + * Records list definitino |
| 32 | + * |
| 33 | + * @return Collection |
| 34 | + */ |
| 35 | + protected function records(): Collection |
| 36 | + { |
| 37 | + return Ticket::all() |
| 38 | + ->map(function (Ticket $ticket) { |
| 39 | + $priority = config('system.priorities.' . $ticket->priority); |
| 40 | + $type = config('system.types.' . $ticket->type); |
| 41 | + return [ |
| 42 | + 'id' => $ticket->id, |
| 43 | + 'title' => new HtmlString(' |
| 44 | + <div class="w-full flex flex-col space-y-3"> |
| 45 | + <div class="w-full flex items-center gap-2"> |
| 46 | + <div title="' . $type['title'] . '" class="text-xs rounded-full w-6 h-6 flex items-center justify-center text-center ' . $type['text-color'] . ' ' . $type['bg-color'] . '"> |
| 47 | + <i class="fa ' . $type['icon'] . '"></i> |
| 48 | + </div> |
| 49 | + <div title="' . $priority['title'] . '" class="text-xs rounded-full w-6 h-6 flex items-center justify-center text-center ' . $priority['text-color'] . ' ' . $priority['bg-color'] . '"> |
| 50 | + <i class="fa ' . $priority['icon'] . '"></i> |
| 51 | + </div> |
| 52 | + <span class="text-sm font-normal" title="' . $ticket->title . '">' . Str::limit($ticket->title, 15) . '</span> |
| 53 | + </div> |
| 54 | + <div class="w-full text-xs font-light"> |
| 55 | + ' . Str::limit(htmlspecialchars(strip_tags($ticket->content))) . ' |
| 56 | + </div> |
| 57 | + <div class="w-full flex items-center gap-1"> |
| 58 | + '. |
| 59 | + ($ticket->responsible ? ' |
| 60 | + <img src="' . $ticket->responsible->avatar_url . '" alt="' . $ticket->responsible->name . '" class="rounded-full shadow" style="width: 20px; height: 20px;" /> |
| 61 | + <span class="font-light text-xs">' . $ticket->responsible->name . '</span> |
| 62 | + ' : '<span class="text-xs font-normal text-gray-400">' . __('Not assigned yet!') . '</span>') |
| 63 | + .' |
| 64 | + </div> |
| 65 | + </div> |
| 66 | + '), |
| 67 | + 'status' => $ticket->status, |
| 68 | + ]; |
| 69 | + }); |
| 70 | + } |
| 71 | + |
| 72 | + /** |
| 73 | + * Customizing kanban board styles |
| 74 | + * |
| 75 | + * @return string[] |
| 76 | + */ |
| 77 | + protected function styles(): array |
| 78 | + { |
| 79 | + return [ |
| 80 | + 'wrapper' => 'w-full h-full flex space-x-4 overflow-x-auto', |
| 81 | + 'kanbanWrapper' => 'h-full flex-1', |
| 82 | + 'kanban' => 'border border-gray-150 flex flex-col h-full rounded', |
| 83 | + 'kanbanHeader' => 'px-3 py-3 font-bold text-xs w-full border-b border-gray-150', |
| 84 | + 'kanbanFooter' => '', |
| 85 | + 'kanbanRecords' => 'space-y-4 p-3 flex-1 overflow-y-auto w-64', |
| 86 | + 'record' => 'bg-white dark:bg-gray-800 p-4 border border-gray-150 rounded cursor-pointer w-62 hover:bg-gray-50 hover:shadow-lg', |
| 87 | + 'recordContent' => 'w-full', |
| 88 | + ]; |
| 89 | + } |
| 90 | + |
| 91 | + /** |
| 92 | + * Event launched when the record status is changed |
| 93 | + * |
| 94 | + * @param $recordId |
| 95 | + * @param $statusId |
| 96 | + * @param $fromOrderedIds |
| 97 | + * @param $toOrderedIds |
| 98 | + * @return void |
| 99 | + */ |
| 100 | + public function onStatusChanged($recordId, $statusId, $fromOrderedIds, $toOrderedIds): void |
| 101 | + { |
| 102 | + $ticket = Ticket::find($recordId); |
| 103 | + if ((has_all_permissions(auth()->user(), 'update-all-tickets') || (has_all_permissions(auth()->user(), 'update-own-tickets') && ($ticket->owner_id === auth()->user() || $ticket->responsible_id === auth()->user()->id))) && has_all_permissions(auth()->user(), 'change-status-tickets')) { |
| 104 | + $before = __(config('system.statuses.' . $ticket->status . '.title')) ?? '-'; |
| 105 | + $ticket->status = $statusId; |
| 106 | + $ticket->save(); |
| 107 | + Notification::make() |
| 108 | + ->success() |
| 109 | + ->title(__('Status updated')) |
| 110 | + ->body(__('The ticket status has been successfully updated')) |
| 111 | + ->send(); |
| 112 | + TicketUpdatedJob::dispatch($ticket, __('Status'), $before, __(config('system.statuses.' . $ticket->status . '.title') ?? '-')); |
| 113 | + } else { |
| 114 | + Notification::make() |
| 115 | + ->success() |
| 116 | + ->title(__('Oops!')) |
| 117 | + ->body(__("You don't have permissions to change this ticket status")) |
| 118 | + ->send(); |
| 119 | + } |
| 120 | + } |
| 121 | + |
| 122 | + /** |
| 123 | + * Event launched when the record is clicked |
| 124 | + * |
| 125 | + * @param $recordId |
| 126 | + * @return void |
| 127 | + */ |
| 128 | + public function onRecordClick($recordId): void |
| 129 | + { |
| 130 | + $ticket = Ticket::find($recordId); |
| 131 | + $url = route('tickets.details', ['ticket' => $ticket, 'slug' => Str::slug($ticket->title)]); |
| 132 | + $this->dispatchBrowserEvent('open-ticket', ['url' => $url]); |
| 133 | + } |
| 134 | +} |
0 commit comments