Skip to content

Commit

Permalink
Merge pull request #9 from devaslanphp/dev
Browse files Browse the repository at this point in the history
Kanban Board
  • Loading branch information
heloufir authored Sep 17, 2022
2 parents cd6a131 + 8ac4b2e commit c165840
Show file tree
Hide file tree
Showing 17 changed files with 357 additions and 59 deletions.
148 changes: 148 additions & 0 deletions app/Http/Livewire/Kanban.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<?php

namespace App\Http\Livewire;

use App\Jobs\TicketUpdatedJob;
use App\Models\Ticket;
use Filament\Notifications\Notification;
use Illuminate\Support\Collection;
use Illuminate\Support\HtmlString;
use Illuminate\Support\Str;
use InvadersXX\FilamentKanbanBoard\Pages\FilamentKanbanBoard;

class Kanban extends FilamentKanbanBoard
{
protected static ?string $title = '';
public bool $sortable = true;
public bool $sortableBetweenStatuses = true;
public bool $recordClickEnabled = true;

/**
* Statuses list Definition
*
* @return Collection
*/
protected function statuses(): Collection
{
return collect(statuses_list_for_kanban());
}

/**
* Records list definitino
*
* @return Collection
*/
protected function records(): Collection
{
$query = Ticket::query();
$query->withCount('comments');
if (has_all_permissions(auth()->user(), 'view-own-tickets') && !has_all_permissions(auth()->user(), 'view-all-tickets')) {
$query->where(function ($query) {
$query->where('owner_id', auth()->user()->id)
->orWhere('responsible_id', auth()->user()->id);
});
}
return $query->get()
->map(function (Ticket $ticket) {
$priority = config('system.priorities.' . $ticket->priority);
$type = config('system.types.' . $ticket->type);
return [
'id' => $ticket->id,
'title' => new HtmlString('
<div class="w-full flex flex-col space-y-3">
<div class="w-full flex items-center gap-2">
<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'] . '">
<i class="fa ' . $type['icon'] . '"></i>
</div>
<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'] . '">
<i class="fa ' . $priority['icon'] . '"></i>
</div>
<span class="text-sm font-normal" title="' . $ticket->title . '">' . Str::limit($ticket->title, 15) . '</span>
</div>
<div class="w-full text-xs font-light">
' . Str::limit(htmlspecialchars(strip_tags($ticket->content))) . '
</div>
<div class="w-full flex items-center space-x-4">
<div class="flex items-center gap-1">
'.
($ticket->responsible ? '
<img src="' . $ticket->responsible->avatar_url . '" alt="' . $ticket->responsible->name . '" class="rounded-full shadow" style="width: 20px; height: 20px;" />
<span class="font-light text-xs">' . $ticket->responsible->name . '</span>
' : '<span class="text-xs font-normal text-gray-400">' . __('Not assigned yet!') . '</span>')
.'
</div>
<div class="flex items-center gap-1 text-xs text-gray-500">
' . $ticket->comments_count . '
<i class="fa fa-comment-o"></i>
</div>
</div>
</div>
'),
'status' => $ticket->status,
];
});
}

/**
* Customizing kanban board styles
*
* @return string[]
*/
protected function styles(): array
{
return [
'wrapper' => 'w-full h-full flex space-x-4 overflow-x-auto',
'kanbanWrapper' => 'h-full flex-1',
'kanban' => 'border border-gray-150 flex flex-col h-full rounded',
'kanbanHeader' => 'px-3 py-3 font-bold text-xs w-full border-b border-gray-150',
'kanbanFooter' => '',
'kanbanRecords' => 'space-y-4 p-3 flex-1 overflow-y-auto w-64',
'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',
'recordContent' => 'w-full',
];
}

/**
* Event launched when the record status is changed
*
* @param $recordId
* @param $statusId
* @param $fromOrderedIds
* @param $toOrderedIds
* @return void
*/
public function onStatusChanged($recordId, $statusId, $fromOrderedIds, $toOrderedIds): void
{
$ticket = Ticket::find($recordId);
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')) {
$before = __(config('system.statuses.' . $ticket->status . '.title')) ?? '-';
$ticket->status = $statusId;
$ticket->save();
Notification::make()
->success()
->title(__('Status updated'))
->body(__('The ticket status has been successfully updated'))
->send();
TicketUpdatedJob::dispatch($ticket, __('Status'), $before, __(config('system.statuses.' . $ticket->status . '.title') ?? '-'));
} else {
Notification::make()
->success()
->title(__('Oops!'))
->body(__("You don't have permissions to change this ticket status"))
->send();
}
}

/**
* Event launched when the record is clicked
*
* @param $recordId
* @return void
*/
public function onRecordClick($recordId): void
{
$ticket = Ticket::find($recordId);
$url = route('tickets.details', ['ticket' => $ticket, 'slug' => Str::slug($ticket->title)]);
$this->dispatchBrowserEvent('open-ticket', ['url' => $url]);
}
}
4 changes: 2 additions & 2 deletions app/Http/Livewire/TicketDetails/Priority.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public function update(): void
public function save(): void
{
$data = $this->form->getState();
$before = config('system.priorities.' . $this->ticket->priority . '.title') ?? '-';
$before = __(config('system.priorities.' . $this->ticket->priority . '.title')) ?? '-';
$this->ticket->priority = $data['priority'];
$this->ticket->save();
Notification::make()
Expand All @@ -79,6 +79,6 @@ public function save(): void
]);
$this->updating = false;
$this->emit('ticketSaved');
TicketUpdatedJob::dispatch($this->ticket, __('Priority'), $before, (config('system.priorities.' . $this->ticket->priority . '.title') ?? '-'));
TicketUpdatedJob::dispatch($this->ticket, __('Priority'), $before, __(config('system.priorities.' . $this->ticket->priority . '.title') ?? '-'));
}
}
4 changes: 2 additions & 2 deletions app/Http/Livewire/TicketDetails/Status.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public function update(): void
public function save(): void
{
$data = $this->form->getState();
$before = config('system.statuses.' . $this->ticket->status . '.title') ?? '-';
$before = __(config('system.statuses.' . $this->ticket->status . '.title')) ?? '-';
$this->ticket->status = $data['status'];
$this->ticket->save();
Notification::make()
Expand All @@ -78,6 +78,6 @@ public function save(): void
]);
$this->updating = false;
$this->emit('ticketSaved');
TicketUpdatedJob::dispatch($this->ticket, __('Status'), $before, (config('system.statuses.' . $this->ticket->status . '.title') ?? '-'));
TicketUpdatedJob::dispatch($this->ticket, __('Status'), $before, __(config('system.statuses.' . $this->ticket->status . '.title') ?? '-'));
}
}
4 changes: 2 additions & 2 deletions app/Http/Livewire/TicketDetails/Type.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public function update(): void
public function save(): void
{
$data = $this->form->getState();
$before = config('system.types.' . $this->ticket->type . '.title') ?? '-';
$before = __(config('system.types.' . $this->ticket->type . '.title')) ?? '-';
$this->ticket->type = $data['type'];
$this->ticket->save();
Notification::make()
Expand All @@ -78,6 +78,6 @@ public function save(): void
]);
$this->updating = false;
$this->emit('ticketSaved');
TicketUpdatedJob::dispatch($this->ticket, __('Type'), $before, (config('system.types.' . $this->ticket->type . '.title') ?? '-'));
TicketUpdatedJob::dispatch($this->ticket, __('Type'), $before, __(config('system.types.' . $this->ticket->type . '.title') ?? '-'));
}
}
6 changes: 6 additions & 0 deletions app/View/Components/MainMenu.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ public function __construct()
'always_shown' => false,
'show_notification_indicator' => false
],
'kanban' => [
'title' => 'Kanban Board',
'icon' => 'fa-clipboard-check',
'always_shown' => false,
'show_notification_indicator' => false
],
'administration' => [
'title' => 'Administration',
'icon' => 'fa-cogs',
Expand Down
21 changes: 21 additions & 0 deletions app/helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,27 @@ function statuses_list(): array
}
}

if (!function_exists('statuses_list_for_kanban')) {
/**
* Return statuses list as an array for kanban board
*
* @return array
*/
function statuses_list_for_kanban(): array
{
$statuses = [];
foreach (config('system.statuses') as $key => $value) {
$statuses[] = [
'id' => $key,
'title' => __($value['title']),
'text-color' => $value['text-color'],
'bg-color' => $value['bg-color'],
];
}
return $statuses;
}
}

if (!function_exists('priorities_list')) {
/**
* Return priorities list as an array of KEY (priority id) => VALUE (priority title)
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"filament/forms": "^2.15",
"filament/notifications": "^2.15",
"guzzlehttp/guzzle": "^7.2",
"invaders-xx/filament-kanban-board": "^0.2.6",
"laravel/framework": "^9.19",
"laravel/sanctum": "^3.0",
"laravel/tinker": "^2.7",
Expand Down
Loading

0 comments on commit c165840

Please sign in to comment.