diff --git a/resources/js/Pages/Ticketing/Settings.vue b/resources/js/Pages/Ticketing/Settings.vue index 87df2a9..f0d90e0 100644 --- a/resources/js/Pages/Ticketing/Settings.vue +++ b/resources/js/Pages/Ticketing/Settings.vue @@ -5,7 +5,6 @@

Ticketing Settings

-

🚀 First-Run Setup

@@ -14,12 +13,14 @@

-
{{ $page.props.flash.success }}
- +
+ {{ $page.props.errors.priority }} +
+
-

Groups

@@ -43,7 +43,6 @@
-

New Group

@@ -71,7 +70,6 @@
-
No groups yet.
-

Edit: {{ editingGroup.name }}

@@ -118,7 +115,6 @@
-

Agents

@@ -127,7 +123,6 @@
-
@@ -156,7 +151,6 @@
-
No agents configured yet.
{{ access.user?.name || 'User #' + access.user_id }}

{{ access.user?.email }} · {{ access.group?.name || 'Unknown Group' }} · {{ access.role }}

- +
-

Priority Levels

@@ -185,7 +175,6 @@
-
@@ -219,7 +208,6 @@
-
No priorities defined yet.
{{ p.description }}

{{ p.group_id ? 'Group-specific' : 'Global' }} +
+ + +
+ +
+

Edit Priority: {{ editingPriority.name }}

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+
+ +
+
+

Remove agent?

+

+ Remove {{ pendingAgentRemoval?.user?.name || ('User #' + pendingAgentRemoval?.user_id) }} + from {{ pendingAgentRemoval?.group?.name }}? +

+
+ + +
+
+
+ +
+
+

Delete priority?

+

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

+
+ + +
@@ -263,12 +312,17 @@ const showAddGroup = ref(false) const showAddAgent = ref(false) const showAddPriority = ref(false) const editingGroup = ref(null) +const editingPriority = ref(null) +const removeAgentModalOpen = ref(false) +const pendingAgentRemoval = ref(null) +const deletePriorityModalOpen = ref(false) +const pendingPriorityDelete = ref(null) -// Forms const groupForm = useForm({ name: '', email_address: '', color: '#6366f1', prefix: '' }) const editGroupForm = useForm({ name: '', email_address: '', color: '#6366f1', prefix: '' }) const agentForm = useForm({ user_id: '', group_id: '', role: 'agent' }) const priorityForm = useForm({ name: '', color: '#6b7280', description: '', sort_order: 0, group_id: null }) +const editPriorityForm = useForm({ name: '', color: '#6b7280', description: '', sort_order: 0, group_id: null }) function submitGroup() { groupForm.post(route('ticketing.settings.groups.store'), { @@ -296,10 +350,22 @@ function submitAgent() { }) } -function removeAgent(access) { - if (confirm('Remove this agent?')) { - router.delete(route('ticketing.settings.agents.destroy', { access: access.id })) - } +function openRemoveAgentModal(access) { + pendingAgentRemoval.value = access + removeAgentModalOpen.value = true +} + +function closeRemoveAgentModal() { + removeAgentModalOpen.value = false + pendingAgentRemoval.value = null +} + +function confirmRemoveAgent() { + if (!pendingAgentRemoval.value) return + + router.delete(route('ticketing.settings.agents.destroy', { access: pendingAgentRemoval.value.id }), { + onFinish: closeRemoveAgentModal, + }) } function submitPriority() { @@ -307,4 +373,37 @@ function submitPriority() { onSuccess: () => { showAddPriority.value = false; priorityForm.reset() } }) } + +function startEditPriority(priority) { + editingPriority.value = priority + editPriorityForm.name = priority.name + editPriorityForm.color = priority.color + editPriorityForm.description = priority.description || '' + editPriorityForm.sort_order = priority.sort_order + editPriorityForm.group_id = priority.group_id +} + +function submitEditPriority() { + editPriorityForm.put(route('ticketing.settings.priorities.update', { priority: editingPriority.value.id }), { + onSuccess: () => { editingPriority.value = null } + }) +} + +function openDeletePriorityModal(priority) { + pendingPriorityDelete.value = priority + deletePriorityModalOpen.value = true +} + +function closeDeletePriorityModal() { + deletePriorityModalOpen.value = false + pendingPriorityDelete.value = null +} + +function confirmDeletePriority() { + if (!pendingPriorityDelete.value) return + + router.delete(route('ticketing.settings.priorities.destroy', { priority: pendingPriorityDelete.value.id }), { + onFinish: closeDeletePriorityModal, + }) +} diff --git a/src/Http/Controllers/TicketingSettingsController.php b/src/Http/Controllers/TicketingSettingsController.php index a2ffe57..27cf16a 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 Illuminate\Validation\Rule; use Illuminate\Http\Request; use Illuminate\Routing\Controller; use Illuminate\Support\Facades\Auth; @@ -212,4 +213,52 @@ class TicketingSettingsController extends Controller return back()->with('success', 'Priority level created.'); } + + public function updatePriority(Request $request, PriorityLevel $priority) + { + $this->requireAgentAccess(); + + if ($priority->group_id) { + $this->requireManagerAccess($priority->group_id); + } + + $validated = $request->validate([ + 'name' => 'required|string|max:100', + 'color' => 'required|string|regex:/^#[0-9a-fA-F]{6}$/', + 'description' => 'nullable|string', + 'sort_order' => 'required|integer|min:0', + 'group_id' => [ + 'nullable', + 'exists:ticketing_groups,id', + Rule::in([$priority->group_id, null]), + ], + ]); + + if (!empty($validated['group_id'])) { + $this->requireManagerAccess($validated['group_id']); + } + + $priority->update($validated); + + return back()->with('success', 'Priority level updated.'); + } + + public function destroyPriority(PriorityLevel $priority) + { + $this->requireAgentAccess(); + + if ($priority->group_id) { + $this->requireManagerAccess($priority->group_id); + } + + if ($priority->tickets()->exists()) { + return back()->withErrors([ + 'priority' => 'Cannot delete a priority that is in use by tickets.', + ]); + } + + $priority->delete(); + + return back()->with('success', 'Priority level removed.'); + } } diff --git a/src/routes/ticketing.php b/src/routes/ticketing.php index a3252f3..dc9cff4 100644 --- a/src/routes/ticketing.php +++ b/src/routes/ticketing.php @@ -17,6 +17,8 @@ Route::middleware(['web', 'auth', 'app.access:ticketing'])->prefix('app/ticketin Route::post('/settings/agents', [TicketingSettingsController::class, 'storeAgent'])->name('settings.agents.store'); Route::delete('/settings/agents/{access}', [TicketingSettingsController::class, 'destroyAgent'])->name('settings.agents.destroy'); 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'); // Ticket routes Route::get('/', [TicketController::class, 'index'])->name('index');