154 lines
5.8 KiB
PHP
154 lines
5.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Modules\Helpdesk\Livewire;
|
|
|
|
use App\Models\User;
|
|
use Illuminate\Contracts\View\View;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use Livewire\Attributes\Validate;
|
|
use Livewire\Component;
|
|
use Modules\Helpdesk\Models\Category;
|
|
use Modules\Helpdesk\Models\KanbanBoard;
|
|
use Modules\Helpdesk\Models\Priority;
|
|
use Modules\Helpdesk\Models\Product;
|
|
use Modules\Helpdesk\Models\Project;
|
|
use Modules\Helpdesk\Models\Status;
|
|
use Modules\Helpdesk\Models\Tag;
|
|
use Modules\Helpdesk\Models\Team;
|
|
use Modules\Helpdesk\Models\Ticket;
|
|
use Modules\Helpdesk\Services\SlaService;
|
|
use Modules\Helpdesk\Services\WorkflowNotificationService;
|
|
|
|
final class TicketEdit extends Component
|
|
{
|
|
public Ticket $ticket;
|
|
|
|
#[Validate('nullable|integer')]
|
|
public ?int $company_id = null;
|
|
|
|
#[Validate('required|string|max:200')]
|
|
public string $subject = '';
|
|
|
|
#[Validate('required|string|min:10')]
|
|
public string $body = '';
|
|
|
|
#[Validate('required|integer|exists:helpdesk_statuses,id')]
|
|
public ?int $status_id = null;
|
|
|
|
#[Validate('nullable|integer|exists:helpdesk_kanban_boards,id')]
|
|
public ?int $board_id = null;
|
|
|
|
#[Validate('required|integer|exists:helpdesk_priorities,id')]
|
|
public ?int $priority_id = null;
|
|
|
|
#[Validate('nullable|integer|exists:helpdesk_categories,id')]
|
|
public ?int $category_id = null;
|
|
|
|
#[Validate('nullable|integer|exists:helpdesk_projects,id')]
|
|
public ?int $project_id = null;
|
|
|
|
#[Validate('nullable|integer|exists:helpdesk_products,id')]
|
|
public ?int $product_id = null;
|
|
|
|
#[Validate('nullable|integer|exists:helpdesk_teams,id')]
|
|
public ?int $team_id = null;
|
|
|
|
#[Validate('nullable|integer|exists:users,id')]
|
|
public ?int $agent_id = null;
|
|
|
|
#[Validate('nullable|date')]
|
|
public ?string $due_at = null;
|
|
|
|
|
|
/** @var array<int, int> */
|
|
#[Validate('array')]
|
|
public array $tag_ids = [];
|
|
|
|
public function mount(Ticket $ticket): void
|
|
{
|
|
$this->authorize('update', $ticket);
|
|
$this->ticket = $ticket->fresh(['status', 'priority', 'category', 'project', 'team', 'agent', 'tags']) ?? $ticket;
|
|
|
|
$this->company_id = $this->ticket->company_id;
|
|
$this->subject = $this->ticket->subject;
|
|
$this->body = $this->ticket->body;
|
|
$this->status_id = $this->ticket->status_id;
|
|
$this->board_id = $this->ticket->board_id;
|
|
$this->priority_id = $this->ticket->priority_id;
|
|
$this->category_id = $this->ticket->category_id;
|
|
$this->project_id = $this->ticket->project_id;
|
|
$this->product_id = $this->ticket->product_id;
|
|
$this->team_id = $this->ticket->team_id;
|
|
$this->agent_id = $this->ticket->agent_id;
|
|
$this->due_at = $this->ticket->due_at?->format('Y-m-d');
|
|
$this->tag_ids = $this->ticket->tags->pluck('id')->map(fn ($id): int => (int) $id)->all();
|
|
}
|
|
|
|
public function save(WorkflowNotificationService $workflow, SlaService $sla): mixed
|
|
{
|
|
$this->authorize('update', $this->ticket);
|
|
$this->validate();
|
|
|
|
$this->validate([
|
|
'tag_ids.*' => 'integer|exists:helpdesk_tags,id',
|
|
]);
|
|
|
|
$status = Status::query()->findOrFail($this->status_id);
|
|
|
|
$this->ticket->forceFill([
|
|
'company_id' => $this->company_id,
|
|
'subject' => $this->subject,
|
|
'body' => $this->body,
|
|
'status_id' => $status->id,
|
|
'board_id' => $this->board_id,
|
|
'priority_id' => $this->priority_id,
|
|
'category_id' => $this->category_id,
|
|
'project_id' => $this->project_id,
|
|
'product_id' => $this->product_id,
|
|
'team_id' => $this->team_id,
|
|
'agent_id' => $this->agent_id,
|
|
'due_at' => $this->due_at,
|
|
'completed_at' => $status->is_closed ? now() : null,
|
|
'last_activity_at' => now(),
|
|
])->save();
|
|
|
|
$this->ticket->tags()->sync(array_values(array_unique(array_map('intval', $this->tag_ids))));
|
|
|
|
if ($status->is_closed) {
|
|
$sla->recordClosure($this->ticket);
|
|
}
|
|
|
|
$fresh = $this->ticket->fresh(['owner', 'agent', 'status', 'priority', 'category', 'project', 'team', 'product', 'tags']) ?? $this->ticket;
|
|
$workflow->dispatch($fresh, $status->is_closed ? 'ticket.closed' : 'ticket.updated', Auth::user());
|
|
|
|
session()->flash('success', 'Ticket ' . $fresh->reference . ' has been updated.');
|
|
|
|
return redirect()->route('helpdesk.tickets.show', $fresh);
|
|
}
|
|
|
|
public function render(): View
|
|
{
|
|
return view('helpdesk::livewire.ticket-edit', [
|
|
'boards' => KanbanBoard::query()->with('owner:id,name,email')->orderByDesc('is_default')->orderBy('sort_order')->orderBy('name')->get(),
|
|
'statuses' => Status::query()->orderBy('sort_order')->orderBy('name')->get(),
|
|
'priorities' => Priority::query()->orderBy('sort_order')->orderBy('name')->get(),
|
|
'categories' => Category::query()->orderBy('name')->get(),
|
|
'companies' => Schema::hasTable('companies') ? DB::table('companies')->select(['id', 'name'])->orderBy('name')->get() : collect(),
|
|
'teams' => Team::query()->whereNull('archived_at')->orderBy('name')->get(),
|
|
'projects' => Project::query()->whereNull('archived_at')->orderBy('title')->get(),
|
|
'products' => Product::query()->where('is_active', true)->orderBy('name')->get(),
|
|
'tags' => Tag::query()->orderBy('name')->get(),
|
|
'agents' => User::query()
|
|
->where(static function ($query): void {
|
|
$query->where('helpdesk_agent', true)->orWhere('helpdesk_admin', true);
|
|
})
|
|
->orderBy('name')
|
|
->get(['id', 'name', 'email']),
|
|
])->layout('layouts.app');
|
|
}
|
|
}
|