diff --git a/resources/js/Pages/Ticketing/Index.vue b/resources/js/Pages/Ticketing/Index.vue index 885a9ed..410c355 100644 --- a/resources/js/Pages/Ticketing/Index.vue +++ b/resources/js/Pages/Ticketing/Index.vue @@ -1,183 +1,419 @@ + + diff --git a/src/Http/Controllers/TicketController.php b/src/Http/Controllers/TicketController.php index 1836f25..6f585dd 100644 --- a/src/Http/Controllers/TicketController.php +++ b/src/Http/Controllers/TicketController.php @@ -10,6 +10,7 @@ use Dashboard\Ticketing\Models\TicketingProject; use Illuminate\Http\Request; use Illuminate\Routing\Controller; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\DB; use Inertia\Inertia; use Inertia\Response; @@ -45,12 +46,35 @@ class TicketController extends Controller $agentGroupIds = $this->agentGroupIds(); $isAgent = count($agentGroupIds) > 0; + $baseQuery = Ticket::query(); + + if ($isAgent) { + $baseQuery->whereIn('group_id', $agentGroupIds); + } else { + $baseQuery->where('submitter_id', $user->id); + } + + $viewCounts = $isAgent + ? [ + 'all' => (clone $baseQuery)->whereNotIn('status', ['resolved', 'closed'])->count(), + 'mine' => (clone $baseQuery)->where('assigned_to', $user->id)->whereNotIn('status', ['resolved', 'closed'])->count(), + 'unassigned' => (clone $baseQuery)->whereNull('assigned_to')->whereNotIn('status', ['resolved', 'closed'])->count(), + 'pending' => (clone $baseQuery)->where('status', 'pending')->count(), + 'resolved' => (clone $baseQuery)->whereIn('status', ['resolved', 'closed'])->count(), + ] + : [ + 'all' => (clone $baseQuery)->count(), + 'mine' => 0, + 'unassigned' => 0, + 'pending' => (clone $baseQuery)->where('status', 'pending')->count(), + 'resolved' => (clone $baseQuery)->whereIn('status', ['resolved', 'closed'])->count(), + ]; + $query = Ticket::with(['group', 'priority', 'project']); if ($isAgent) { $query->whereIn('group_id', $agentGroupIds); - // Filters if ($request->filled('group_id')) { $query->where('group_id', $request->group_id); } @@ -60,24 +84,36 @@ class TicketController extends Controller if ($request->filled('priority_id')) { $query->where('priority_id', $request->priority_id); } + if ($request->filled('project_id')) { + $query->where('project_id', $request->project_id); + } if ($request->filter === 'mine') { - $query->where('assigned_to', $user->id); + $query->where('assigned_to', $user->id)->whereNotIn('status', ['resolved', 'closed']); } elseif ($request->filter === 'unassigned') { - $query->whereNull('assigned_to'); + $query->whereNull('assigned_to')->whereNotIn('status', ['resolved', 'closed']); } elseif ($request->filter === 'pending') { $query->where('status', 'pending'); + } elseif ($request->filter === 'resolved') { + $query->whereIn('status', ['resolved', 'closed']); } elseif (!$request->filled('status')) { $query->whereNotIn('status', ['resolved', 'closed']); } } else { $query->where('submitter_id', $user->id); + if ($request->filled('project_id')) { + $query->where('project_id', $request->project_id); + } + if ($request->filter === 'pending') { + $query->where('status', 'pending'); + } elseif ($request->filter === 'resolved') { + $query->whereIn('status', ['resolved', 'closed']); + } } $tickets = $query->latest()->paginate(30)->withQueryString(); - // Enrich with submitter name $userIds = $tickets->pluck('submitter_id')->merge($tickets->pluck('assigned_to'))->filter()->unique(); - $users = \DB::table('users')->whereIn('id', $userIds)->get(['id', 'name', 'email'])->keyBy('id'); + $users = DB::table('users')->whereIn('id', $userIds)->get(['id', 'name', 'email'])->keyBy('id'); $tickets->getCollection()->transform(function ($ticket) use ($users) { $ticket->submitter = $users[$ticket->submitter_id] ?? null; @@ -85,22 +121,76 @@ class TicketController extends Controller return $ticket; }); - $groups = TicketingGroup::when($isAgent, fn($q) => $q->whereIn('id', $agentGroupIds))->get(); + $groups = TicketingGroup::when($isAgent, fn ($q) => $q->whereIn('id', $agentGroupIds))->get(); $priorities = PriorityLevel::whereNull('group_id') - ->orWhereIn('group_id', $agentGroupIds ?? []) + ->orWhereIn('group_id', $agentGroupIds ?: [0]) ->orderBy('sort_order') ->get(); - $projects = TicketingProject::when($isAgent, fn($q) => $q->whereIn('group_id', $agentGroupIds)) + $projects = TicketingProject::when($isAgent, fn ($q) => $q->whereIn('group_id', $agentGroupIds)) ->where('status', 'active') ->get(); + $projectCounts = (clone $baseQuery) + ->select('project_id', DB::raw('count(*) as aggregate')) + ->whereNotNull('project_id') + ->groupBy('project_id') + ->pluck('aggregate', 'project_id'); + + $projects->transform(function ($project) use ($projectCounts) { + $project->ticket_count = (int) ($projectCounts[$project->id] ?? 0); + return $project; + }); + + $ticketDetail = null; + $detailAgents = []; + if ($request->filled('detail')) { + $detailQuery = Ticket::with([ + 'group', + 'priority', + 'project', + 'messages.attachments', + 'attachments', + ])->whereKey($request->detail); + + if ($isAgent) { + $detailQuery->whereIn('group_id', $agentGroupIds); + } else { + $detailQuery->where('submitter_id', $user->id); + } + + $dt = $detailQuery->first(); + + if ($dt) { + $detailUserIds = collect([$dt->submitter_id, $dt->assigned_to]) + ->merge($dt->messages->pluck('user_id')) + ->filter() + ->unique(); + $detailUsers = DB::table('users')->whereIn('id', $detailUserIds)->get(['id', 'name', 'email'])->keyBy('id'); + + $dt->submitter = $detailUsers[$dt->submitter_id] ?? null; + $dt->assignee = $dt->assigned_to ? ($detailUsers[$dt->assigned_to] ?? null) : null; + $dt->messages->each(function ($msg) use ($detailUsers) { + $msg->author = $msg->user_id ? ($detailUsers[$msg->user_id] ?? null) : null; + }); + $ticketDetail = $dt; + + if ($isAgent) { + $agentIds = TicketingAgentAccess::where('group_id', $dt->group_id)->pluck('user_id'); + $detailAgents = DB::table('users')->whereIn('id', $agentIds)->get(['id', 'name', 'email']); + } + } + } + return Inertia::render('Ticketing/Index', [ 'tickets' => $tickets, 'groups' => $groups, 'priorities' => $priorities, 'projects' => $projects, 'isAgent' => $isAgent, - 'filters' => $request->only(['group_id', 'status', 'priority_id', 'filter']), + 'filters' => $request->only(['group_id', 'status', 'priority_id', 'project_id', 'filter', 'detail']), + 'ticketDetail' => $ticketDetail, + 'detailAgents' => $detailAgents, + 'viewCounts' => $viewCounts, ]); } @@ -154,19 +244,17 @@ class TicketController extends Controller $ticket->load(['group', 'priority', 'project', 'messages', 'attachments']); - // Enrich messages with user data $userIds = $ticket->messages->pluck('user_id')->filter()->unique(); - $users = \DB::table('users')->whereIn('id', $userIds)->get(['id', 'name', 'email'])->keyBy('id'); + $users = DB::table('users')->whereIn('id', $userIds)->get(['id', 'name', 'email'])->keyBy('id'); $ticket->messages->each(function ($msg) use ($users) { $msg->author = $msg->user_id ? ($users[$msg->user_id] ?? null) : null; }); - // Agents for assignment picker $agents = []; if ($isAgent) { $agentIds = TicketingAgentAccess::where('group_id', $ticket->group_id)->pluck('user_id'); - $agents = \DB::table('users')->whereIn('id', $agentIds)->get(['id', 'name', 'email']); + $agents = DB::table('users')->whereIn('id', $agentIds)->get(['id', 'name', 'email']); } $priorities = PriorityLevel::where(fn($q) => $q->whereNull('group_id')->orWhere('group_id', $ticket->group_id)) @@ -191,7 +279,7 @@ class TicketController extends Controller $priorities = PriorityLevel::where(fn($q) => $q->whereNull('group_id')->orWhere('group_id', $ticket->group_id)) ->orderBy('sort_order')->get(); $agentIds = TicketingAgentAccess::where('group_id', $ticket->group_id)->pluck('user_id'); - $agents = \DB::table('users')->whereIn('id', $agentIds)->get(['id', 'name', 'email']); + $agents = DB::table('users')->whereIn('id', $agentIds)->get(['id', 'name', 'email']); $projects = TicketingProject::where('group_id', $ticket->group_id)->get(); return Inertia::render('Ticketing/Edit', [ @@ -217,7 +305,6 @@ class TicketController extends Controller 'project_id' => 'nullable|exists:ticketing_projects,id', ]; - // assigned_to only settable by agents if ($this->isAgent($ticket->group_id)) { $rules['assigned_to'] = 'nullable|exists:users,id'; }