diff --git a/resources/js/Pages/Ticketing/Settings.vue b/resources/js/Pages/Ticketing/Settings.vue index f0d90e0..6191488 100644 --- a/resources/js/Pages/Ticketing/Settings.vue +++ b/resources/js/Pages/Ticketing/Settings.vue @@ -21,6 +21,10 @@ {{ $page.props.errors.priority }} +
+ {{ $page.props.errors.project }} +
+
+ +
+
+

Projects

+ +
+ +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+ +
+
No projects defined yet.
+
+
+

{{ project.name }}

+

{{ groups.find(g => g.id === project.group_id)?.name || 'Unknown Group' }} ยท {{ project.status }}

+

{{ project.description }}

+
+
+ + +
+
+
+ +
+

Edit Project: {{ editingProject.name }}

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
@@ -286,6 +379,19 @@
+ +
+
+

Delete project?

+

+ Delete {{ pendingProjectDelete?.name }}? This cannot be undone. +

+
+ + +
+
+
diff --git a/src/Http/Controllers/TicketingSettingsController.php b/src/Http/Controllers/TicketingSettingsController.php index 27cf16a..2516743 100644 --- a/src/Http/Controllers/TicketingSettingsController.php +++ b/src/Http/Controllers/TicketingSettingsController.php @@ -5,6 +5,7 @@ namespace Dashboard\Ticketing\Http\Controllers; use Dashboard\Ticketing\Models\PriorityLevel; use Dashboard\Ticketing\Models\TicketingAgentAccess; use Dashboard\Ticketing\Models\TicketingGroup; +use Dashboard\Ticketing\Models\TicketingProject; use Illuminate\Validation\Rule; use Illuminate\Http\Request; use Illuminate\Routing\Controller; @@ -87,10 +88,17 @@ class TicketingSettingsController extends Controller : PriorityLevel::where(fn($q) => $q->whereNull('group_id')->orWhereIn('group_id', $myGroupIds)) ->orderBy('sort_order')->get(); + $projects = $isBootstrap + ? collect() + : TicketingProject::whereIn('group_id', $myGroupIds) + ->orderBy('name') + ->get(); + return Inertia::render('Ticketing/Settings', [ 'groups' => $groups, 'agents' => $agents, 'priorities' => $priorities, + 'projects' => $projects, 'myGroupIds' => $myGroupIds, 'isBootstrap' => $isBootstrap, 'isSiteAdmin' => $this->isSiteAdmin(), @@ -261,4 +269,57 @@ class TicketingSettingsController extends Controller return back()->with('success', 'Priority level removed.'); } + + public function storeProject(Request $request) + { + $this->requireAgentAccess(); + + $validated = $request->validate([ + 'group_id' => 'required|exists:ticketing_groups,id', + 'name' => 'required|string|max:100', + 'description' => 'nullable|string', + 'status' => 'required|in:active,archived', + ]); + + $this->requireManagerAccess($validated['group_id']); + + TicketingProject::create([ + ...$validated, + 'created_by' => Auth::id(), + ]); + + return back()->with('success', 'Project created.'); + } + + public function updateProject(Request $request, TicketingProject $project) + { + $this->requireAgentAccess(); + $this->requireManagerAccess($project->group_id); + + $validated = $request->validate([ + 'name' => 'required|string|max:100', + 'description' => 'nullable|string', + 'status' => 'required|in:active,archived', + ]); + + $project->update($validated); + + return back()->with('success', 'Project updated.'); + } + + public function destroyProject(TicketingProject $project) + { + $this->requireAgentAccess(); + $this->requireManagerAccess($project->group_id); + + if ($project->tickets()->exists()) { + return back()->withErrors([ + 'project' => 'Cannot delete a project that is in use by tickets.', + ]); + } + + $project->delete(); + + return back()->with('success', 'Project removed.'); + } } diff --git a/src/routes/ticketing.php b/src/routes/ticketing.php index dc9cff4..63decdd 100644 --- a/src/routes/ticketing.php +++ b/src/routes/ticketing.php @@ -19,6 +19,9 @@ Route::middleware(['web', 'auth', 'app.access:ticketing'])->prefix('app/ticketin Route::post('/settings/priorities', [TicketingSettingsController::class, 'storePriority'])->name('settings.priorities.store'); Route::put('/settings/priorities/{priority}', [TicketingSettingsController::class, 'updatePriority'])->name('settings.priorities.update'); Route::delete('/settings/priorities/{priority}', [TicketingSettingsController::class, 'destroyPriority'])->name('settings.priorities.destroy'); + Route::post('/settings/projects', [TicketingSettingsController::class, 'storeProject'])->name('settings.projects.store'); + Route::put('/settings/projects/{project}', [TicketingSettingsController::class, 'updateProject'])->name('settings.projects.update'); + Route::delete('/settings/projects/{project}', [TicketingSettingsController::class, 'destroyProject'])->name('settings.projects.destroy'); // Ticket routes Route::get('/', [TicketController::class, 'index'])->name('index');