feat: full dashboard-ticketing scaffold with data model, controllers, Vue pages

This commit is contained in:
Joel Wedemire
2026-04-08 17:10:30 -07:00
parent 81d0d54f50
commit 391699220f
33 changed files with 1947 additions and 719 deletions

View File

@@ -0,0 +1,144 @@
<?php
namespace Dashboard\Ticketing\Http\Controllers;
use Dashboard\Ticketing\Models\PriorityLevel;
use Dashboard\Ticketing\Models\TicketingAgentAccess;
use Dashboard\Ticketing\Models\TicketingGroup;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Auth;
use Inertia\Inertia;
use Inertia\Response;
class TicketingSettingsController extends Controller
{
private function requireAgentAccess(): void
{
$hasAccess = TicketingAgentAccess::where('user_id', Auth::id())->exists();
if (!$hasAccess) {
abort(403);
}
}
private function requireManagerAccess(int $groupId): void
{
$isManager = TicketingAgentAccess::where('user_id', Auth::id())
->where('group_id', $groupId)
->where('role', 'manager')
->exists();
if (!$isManager) {
abort(403);
}
}
public function index(): Response
{
$this->requireAgentAccess();
$userId = Auth::id();
$myGroupIds = TicketingAgentAccess::where('user_id', $userId)->pluck('group_id');
$groups = TicketingGroup::whereIn('id', $myGroupIds)->get();
$agents = TicketingAgentAccess::whereIn('group_id', $myGroupIds)->get();
$agentUserIds = $agents->pluck('user_id')->unique();
$agentUsers = \DB::table('users')->whereIn('id', $agentUserIds)->get(['id', 'name', 'email'])->keyBy('id');
$agents->each(fn($a) => $a->user = $agentUsers[$a->user_id] ?? null);
$priorities = PriorityLevel::where(fn($q) => $q->whereNull('group_id')->orWhereIn('group_id', $myGroupIds))
->orderBy('sort_order')->get();
return Inertia::render('Ticketing/Settings', [
'groups' => $groups,
'agents' => $agents,
'priorities' => $priorities,
'myGroupIds' => $myGroupIds,
]);
}
public function storeGroup(Request $request)
{
$this->requireAgentAccess();
$validated = $request->validate([
'name' => 'required|string|max:100',
'email_address' => 'nullable|email',
'color' => 'required|string|regex:/^#[0-9a-fA-F]{6}$/',
'prefix' => 'required|string|max:10|alpha_num|unique:ticketing_groups,prefix',
]);
$group = TicketingGroup::create($validated);
// Auto-add creator as manager
TicketingAgentAccess::create([
'user_id' => Auth::id(),
'group_id' => $group->id,
'role' => 'manager',
]);
return back()->with('success', 'Group created.');
}
public function updateGroup(Request $request, TicketingGroup $group)
{
$this->requireManagerAccess($group->id);
$validated = $request->validate([
'name' => 'required|string|max:100',
'email_address' => 'nullable|email',
'color' => 'required|string|regex:/^#[0-9a-fA-F]{6}$/',
'prefix' => 'required|string|max:10|alpha_num|unique:ticketing_groups,prefix,' . $group->id,
]);
$group->update($validated);
return back()->with('success', 'Group updated.');
}
public function storeAgent(Request $request)
{
$this->requireAgentAccess();
$validated = $request->validate([
'user_id' => 'required|exists:users,id',
'group_id' => 'required|exists:ticketing_groups,id',
'role' => 'required|in:agent,manager',
]);
$this->requireManagerAccess($validated['group_id']);
TicketingAgentAccess::updateOrCreate(
['user_id' => $validated['user_id'], 'group_id' => $validated['group_id']],
['role' => $validated['role']]
);
return back()->with('success', 'Agent added.');
}
public function destroyAgent(TicketingAgentAccess $access)
{
$this->requireManagerAccess($access->group_id);
$access->delete();
return back()->with('success', 'Agent removed.');
}
public function storePriority(Request $request)
{
$this->requireAgentAccess();
$validated = $request->validate([
'name' => 'required|string|max:100',
'color' => 'required|string|regex:/^#[0-9a-fA-F]{6}$/',
'description' => 'nullable|string',
'sort_order' => 'integer|min:0',
'group_id' => 'nullable|exists:ticketing_groups,id',
]);
PriorityLevel::create($validated);
return back()->with('success', 'Priority level created.');
}
}