diff --git a/api/assign_ticket.php b/api/assign_ticket.php new file mode 100644 index 0000000..a142ed4 --- /dev/null +++ b/api/assign_ticket.php @@ -0,0 +1,42 @@ + false, 'error' => 'Not authenticated']); + exit; +} + +// Get request data +$data = json_decode(file_get_contents('php://input'), true); +$ticketId = $data['ticket_id'] ?? null; +$assignedTo = $data['assigned_to'] ?? null; + +if (!$ticketId) { + echo json_encode(['success' => false, 'error' => 'Ticket ID required']); + exit; +} + +$ticketModel = new TicketModel($conn); +$auditLogModel = new AuditLogModel($conn); + +if ($assignedTo === null || $assignedTo === '') { + // Unassign ticket + $success = $ticketModel->unassignTicket($ticketId, $_SESSION['user_id']); + if ($success) { + $auditLogModel->log($_SESSION['user_id'], 'unassign', 'ticket', $ticketId); + } +} else { + // Assign ticket + $success = $ticketModel->assignTicket($ticketId, $assignedTo, $_SESSION['user_id']); + if ($success) { + $auditLogModel->log($_SESSION['user_id'], 'assign', 'ticket', $ticketId, ['assigned_to' => $assignedTo]); + } +} + +echo json_encode(['success' => $success]); diff --git a/assets/js/ticket.js b/assets/js/ticket.js index 30720c7..cc18353 100644 --- a/assets/js/ticket.js +++ b/assets/js/ticket.js @@ -213,7 +213,7 @@ function toggleMarkdownMode() { document.addEventListener('DOMContentLoaded', function() { // Show description tab by default showTab('description'); - + // Auto-resize the description textarea to fit content const descriptionTextarea = document.querySelector('textarea[data-field="description"]'); if (descriptionTextarea) { @@ -223,15 +223,50 @@ document.addEventListener('DOMContentLoaded', function() { // Set the height to match the scrollHeight descriptionTextarea.style.height = descriptionTextarea.scrollHeight + 'px'; } - + // Initial resize autoResizeTextarea(); - + // Resize on input when in edit mode descriptionTextarea.addEventListener('input', autoResizeTextarea); } + + // Initialize assignment handling + handleAssignmentChange(); }); +/** + * Handle ticket assignment dropdown changes + */ +function handleAssignmentChange() { + const assignedToSelect = document.getElementById('assignedToSelect'); + if (!assignedToSelect) return; + + assignedToSelect.addEventListener('change', function() { + const ticketId = window.ticketData.id; + const assignedTo = this.value || null; + + fetch('/api/assign_ticket.php', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ ticket_id: ticketId, assigned_to: assignedTo }) + }) + .then(response => response.json()) + .then(data => { + if (!data.success) { + alert('Error updating assignment'); + console.error(data.error); + } else { + console.log('Assignment updated successfully'); + } + }) + .catch(error => { + console.error('Error updating assignment:', error); + alert('Error updating assignment: ' + error.message); + }); + }); +} + function showTab(tabName) { // Hide all tab contents const descriptionTab = document.getElementById('description-tab'); diff --git a/controllers/TicketController.php b/controllers/TicketController.php index 33b35e9..f503bdd 100644 --- a/controllers/TicketController.php +++ b/controllers/TicketController.php @@ -3,17 +3,20 @@ require_once dirname(__DIR__) . '/models/TicketModel.php'; require_once dirname(__DIR__) . '/models/CommentModel.php'; require_once dirname(__DIR__) . '/models/AuditLogModel.php'; +require_once dirname(__DIR__) . '/models/UserModel.php'; class TicketController { private $ticketModel; private $commentModel; private $auditLogModel; + private $userModel; private $envVars; public function __construct($conn) { $this->ticketModel = new TicketModel($conn); $this->commentModel = new CommentModel($conn); $this->auditLogModel = new AuditLogModel($conn); + $this->userModel = new UserModel($conn); // Load environment variables for Discord webhook $envPath = dirname(__DIR__) . '/.env'; @@ -61,6 +64,9 @@ class TicketController { // Get timeline for this ticket $timeline = $this->auditLogModel->getTicketTimeline($id); + // Get all users for assignment dropdown + $allUsers = $this->userModel->getAllUsers(); + // Load the view include dirname(__DIR__) . '/views/TicketView.php'; } diff --git a/models/TicketModel.php b/models/TicketModel.php index 94916ae..c253844 100644 --- a/models/TicketModel.php +++ b/models/TicketModel.php @@ -11,10 +11,13 @@ class TicketModel { u_created.username as creator_username, u_created.display_name as creator_display_name, u_updated.username as updater_username, - u_updated.display_name as updater_display_name + u_updated.display_name as updater_display_name, + u_assigned.username as assigned_username, + u_assigned.display_name as assigned_display_name FROM tickets t LEFT JOIN users u_created ON t.created_by = u_created.user_id LEFT JOIN users u_updated ON t.updated_by = u_updated.user_id + LEFT JOIN users u_assigned ON t.assigned_to = u_assigned.user_id WHERE t.ticket_id = ?"; $stmt = $this->conn->prepare($sql); $stmt->bind_param("i", $id); @@ -283,4 +286,37 @@ class TicketModel { ]; } } + + /** + * Assign ticket to a user + * + * @param int $ticketId Ticket ID + * @param int $userId User ID to assign to + * @param int $assignedBy User ID performing the assignment + * @return bool Success status + */ + public function assignTicket($ticketId, $userId, $assignedBy) { + $sql = "UPDATE tickets SET assigned_to = ?, updated_by = ?, updated_at = NOW() WHERE ticket_id = ?"; + $stmt = $this->conn->prepare($sql); + $stmt->bind_param("iii", $userId, $assignedBy, $ticketId); + $result = $stmt->execute(); + $stmt->close(); + return $result; + } + + /** + * Unassign ticket (set assigned_to to NULL) + * + * @param int $ticketId Ticket ID + * @param int $updatedBy User ID performing the unassignment + * @return bool Success status + */ + public function unassignTicket($ticketId, $updatedBy) { + $sql = "UPDATE tickets SET assigned_to = NULL, updated_by = ?, updated_at = NOW() WHERE ticket_id = ?"; + $stmt = $this->conn->prepare($sql); + $stmt->bind_param("ii", $updatedBy, $ticketId); + $result = $stmt->execute(); + $stmt->close(); + return $result; + } } \ No newline at end of file diff --git a/views/TicketView.php b/views/TicketView.php index d79e84f..0fc5467 100644 --- a/views/TicketView.php +++ b/views/TicketView.php @@ -167,6 +167,18 @@ function formatDetails($details, $actionType) { } ?> +