<?php
$pageTitle = "View Support Ticket";
// Get ticket ID and validate before including header
$ticket_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
// Start session if not already started
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
if (!isset($_SESSION['user_id']) || !isset($_SESSION['role']) || ($_SESSION['role'] != 'admin' && $_SESSION['role'] != 'director')) {
header('Location: login.php');
exit;
}
// Now include the header since no redirects will be needed before output
include_once('includes/header.php');
// Check admin login status - if session doesn't contain admin_id, try to get one
if (!isset($_SESSION['admin_id']) || !$_SESSION['admin_id']) {
$admin_check = $conn->query("SELECT id FROM users WHERE role = 'admin' LIMIT 1");
if ($admin_check && $admin_check->num_rows > 0) {
$admin_row = $admin_check->fetch_assoc();
$_SESSION['admin_id'] = $admin_row['id'];
}
}
// Check if we're using student_id or user_id in the support_tickets table
$column_check = $conn->query("SHOW COLUMNS FROM support_tickets LIKE 'student_id'");
$user_column = ($column_check->num_rows > 0) ? 'student_id' : 'user_id';
// Fetch ticket details
$stmt = $conn->prepare("
SELECT t.*, CONCAT(u.first_name, ' ', u.last_name) as student_name, u.email as student_email, u.id as student_id
FROM support_tickets t
LEFT JOIN users u ON t.{$user_column} = u.id
WHERE t.id = ?
");
$stmt->bind_param("i", $ticket_id);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows === 0) {
$_SESSION['error_msg'] = "Ticket not found.";
// We can't use header redirect here, so use JavaScript instead
echo "<script>window.location.href = 'support_tickets.php';</script>";
exit();
}
$ticket = $result->fetch_assoc();
// Handle ticket status update
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_status'])) {
$status = isset($_POST['status']) ? $conn->real_escape_string($_POST['status']) : '';
if (!empty($status)) {
$stmt = $conn->prepare("UPDATE support_tickets SET status = ?, updated_at = NOW() WHERE id = ?");
$stmt->bind_param("si", $status, $ticket_id);
if ($stmt->execute()) {
// Refresh ticket data
$ticket['status'] = $status;
$_SESSION['success_msg'] = "Ticket status updated successfully.";
} else {
$_SESSION['error_msg'] = "Failed to update ticket status.";
}
}
}
// Check if we're using is_admin or user_type in the support_ticket_replies table
$column_check = $conn->query("SHOW COLUMNS FROM support_ticket_replies LIKE 'is_admin'");
$has_is_admin = ($column_check->num_rows > 0);
// Handle reply submission
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['submit_reply'])) {
$reply_message = isset($_POST['reply_message']) ? trim($_POST['reply_message']) : '';
if (empty($reply_message)) {
$_SESSION['error_msg'] = "Reply message cannot be empty.";
} else {
// Get admin ID from session or use a fallback value
$admin_id = isset($_SESSION['admin_id']) ? $_SESSION['admin_id'] : 0;
// Check if admin_id is valid
if ($admin_id <= 0) {
// Try to get admin ID from users table if it exists
$admin_check = $conn->query("SELECT id FROM users WHERE role = 'admin' LIMIT 1");
if ($admin_check && $admin_check->num_rows > 0) {
$admin_row = $admin_check->fetch_assoc();
$admin_id = $admin_row['id'];
} else {
// Last resort fallback - use 1 as admin ID
$admin_id = 1;
}
}
// Insert the reply - adapt based on table structure
if ($has_is_admin) {
$stmt = $conn->prepare("
INSERT INTO support_ticket_replies
(ticket_id, user_id, is_admin, message, created_at)
VALUES (?, ?, 1, ?, NOW())
");
$stmt->bind_param("iis", $ticket_id, $admin_id, $reply_message);
} else {
$stmt = $conn->prepare("
INSERT INTO support_ticket_replies
(ticket_id, user_id, user_type, message, created_at)
VALUES (?, ?, 'admin', ?, NOW())
");
$stmt->bind_param("iis", $ticket_id, $admin_id, $reply_message);
}
if ($stmt->execute()) {
// If the ticket was open, automatically mark it as in progress
if ($ticket['status'] === 'open') {
$stmt = $conn->prepare("UPDATE support_tickets SET status = 'in_progress', updated_at = NOW() WHERE id = ?");
$stmt->bind_param("i", $ticket_id);
$stmt->execute();
$ticket['status'] = 'in_progress';
}
$_SESSION['success_msg'] = "Your reply has been submitted.";
// Clear the form data after successful submission
$reply_message = '';
} else {
$_SESSION['error_msg'] = "Failed to submit your reply. Please try again.";
}
}
}
// Fetch conversation history based on table structure
if ($has_is_admin) {
$stmt = $conn->prepare("
SELECT r.*,
CONCAT(u.first_name, ' ', u.last_name) as author_name,
u.email as author_email,
r.is_admin
FROM support_ticket_replies r
LEFT JOIN users u ON r.user_id = u.id
WHERE r.ticket_id = ?
ORDER BY r.created_at ASC
");
} else {
$stmt = $conn->prepare("
SELECT r.*,
CONCAT(u.first_name, ' ', u.last_name) as author_name,
u.email as author_email,
CASE WHEN r.user_type = 'admin' THEN 1 ELSE 0 END as is_admin
FROM support_ticket_replies r
LEFT JOIN users u ON r.user_id = u.id
WHERE r.ticket_id = ?
ORDER BY r.created_at ASC
");
}
$stmt->bind_param("i", $ticket_id);
$stmt->execute();
$replies_result = $stmt->get_result();
// Define categories
$categories = [
'account' => 'Account Access',
'payment' => 'Payment Issues',
'enrollment' => 'Course Enrollment',
'certificate' => 'Certificate Issues',
'exam' => 'Exam Related',
'technical' => 'Technical Support',
'other' => 'Other Issues'
];
// Define priorities
$priorities = [
'low' => 'Low',
'normal' => 'Normal',
'high' => 'High',
'urgent' => 'Urgent'
];
// Define status labels and colors
$status_labels = [
'open' => ['label' => 'Open', 'class' => 'bg-danger'],
'in_progress' => ['label' => 'In Progress', 'class' => 'bg-warning'],
'resolved' => ['label' => 'Resolved', 'class' => 'bg-success'],
'closed' => ['label' => 'Closed', 'class' => 'bg-secondary']
];
// Get canned responses
// First create the table if it doesn't exist
$conn->query("
CREATE TABLE IF NOT EXISTS `support_canned_responses` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`message` text NOT NULL,
`category` varchar(50) DEFAULT NULL,
`created_by` int(11) DEFAULT NULL,
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
");
$canned_responses = [];
$canned_result = $conn->query("SELECT id, title, message FROM support_canned_responses ORDER BY title");
if ($canned_result && $canned_result->num_rows > 0) {
while ($row = $canned_result->fetch_assoc()) {
$canned_responses[] = $row;
}
}
?>
<div class="container-fluid py-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<a href="support_tickets.php" class="btn btn-sm btn-outline-secondary me-2">
<i class="fas fa-arrow-left me-1"></i> Back to Tickets
</a>
<h2 class="h3 d-inline"><?php echo htmlspecialchars($ticket['subject']); ?></h2>
<span class="badge <?php echo $status_labels[$ticket['status']]['class']; ?> ms-2">
<?php echo $status_labels[$ticket['status']]['label']; ?>
</span>
</div>
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" data-bs-toggle="dropdown">
Actions
</button>
<ul class="dropdown-menu">
<?php foreach ($status_labels as $status_key => $status_value): ?>
<?php if ($status_key !== $ticket['status']): ?>
<li>
<form method="post" action="">
<input type="hidden" name="status" value="<?php echo $status_key; ?>">
<button type="submit" name="update_status" class="dropdown-item">
<i class="fas fa-circle text-<?php echo str_replace('bg-', '', $status_value['class']); ?> me-2"></i>
Mark as <?php echo $status_value['label']; ?>
</button>
</form>
</li>
<?php endif; ?>
<?php endforeach; ?>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item" href="user_details.php?id=<?php echo $ticket['student_id']; ?>">
<i class="fas fa-user me-2"></i> View User Profile
</a>
</li>
</ul>
</div>
</div>
<?php if (isset($_SESSION['success_msg'])): ?>
<div class="alert alert-success alert-dismissible fade show" role="alert">
<?php echo $_SESSION['success_msg']; unset($_SESSION['success_msg']); ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endif; ?>
<?php if (isset($_SESSION['error_msg'])): ?>
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<?php echo $_SESSION['error_msg']; unset($_SESSION['error_msg']); ?>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<?php endif; ?>
<div class="row">
<!-- Ticket Details -->
<div class="col-md-4">
<div class="card mb-4">
<div class="card-header">
<h5 class="card-title mb-0">Ticket Information</h5>
</div>
<div class="card-body">
<div class="mb-3">
<h6 class="fw-bold">Ticket #</h6>
<p><?php
// Handle different field names (ticket_number or ticket_id)
echo htmlspecialchars(isset($ticket['ticket_number']) ? $ticket['ticket_number'] :
(isset($ticket['ticket_id']) ? $ticket['ticket_id'] : 'Unknown'));
?></p>
</div>
<div class="mb-3">
<h6 class="fw-bold">Submitted By</h6>
<?php if (!empty($ticket['student_name'])): ?>
<p>
<?php echo htmlspecialchars($ticket['student_name']); ?><br>
<small><?php echo htmlspecialchars($ticket['student_email']); ?></small>
</p>
<?php else: ?>
<p class="text-muted">Unknown</p>
<?php endif; ?>
</div>
<div class="mb-3">
<h6 class="fw-bold">Category</h6>
<p>
<?php echo isset($categories[$ticket['category']]) ? htmlspecialchars($categories[$ticket['category']]) : htmlspecialchars($ticket['category']); ?>
</p>
</div>
<div class="mb-3">
<h6 class="fw-bold">Priority</h6>
<?php
$priority_class = '';
switch($ticket['priority']) {
case 'low': $priority_class = 'text-success'; break;
case 'normal': $priority_class = 'text-primary'; break;
case 'high': $priority_class = 'text-warning'; break;
case 'urgent': $priority_class = 'text-danger'; break;
}
?>
<p class="<?php echo $priority_class; ?>">
<?php echo isset($priorities[$ticket['priority']]) ? htmlspecialchars($priorities[$ticket['priority']]) : htmlspecialchars($ticket['priority']); ?>
</p>
</div>
<div class="mb-3">
<h6 class="fw-bold">Created</h6>
<p><?php echo date('M d, Y h:i A', strtotime($ticket['created_at'])); ?></p>
</div>
<div class="mb-3">
<h6 class="fw-bold">Last Updated</h6>
<p>
<?php echo !empty($ticket['updated_at']) ? date('M d, Y h:i A', strtotime($ticket['updated_at'])) : 'Not updated yet'; ?>
</p>
</div>
<div class="mb-0">
<h6 class="fw-bold">Status</h6>
<p>
<span class="badge <?php echo $status_labels[$ticket['status']]['class']; ?>">
<?php echo $status_labels[$ticket['status']]['label']; ?>
</span>
</p>
</div>
</div>
</div>
<?php if (count($canned_responses) > 0): ?>
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">Canned Responses</h5>
</div>
<div class="card-body">
<div class="list-group">
<?php foreach ($canned_responses as $response): ?>
<button type="button" class="list-group-item list-group-item-action canned-response"
data-message="<?php echo htmlspecialchars($response['message']); ?>">
<?php echo htmlspecialchars($response['title']); ?>
</button>
<?php endforeach; ?>
</div>
</div>
</div>
<?php endif; ?>
</div>
<!-- Conversation -->
<div class="col-md-8">
<div class="card mb-4">
<div class="card-header">
<h5 class="card-title mb-0">Conversation</h5>
</div>
<div class="card-body">
<div class="conversation">
<!-- Original Ticket -->
<div class="message-wrapper">
<div class="message student">
<div class="message-header">
<div class="message-author">
<strong><?php echo htmlspecialchars($ticket['student_name']); ?></strong>
<span class="text-muted ms-2">(Student)</span>
</div>
<div class="message-time"><?php echo date('M d, Y h:i A', strtotime($ticket['created_at'])); ?></div>
</div>
<div class="message-content">
<p class="mb-0"><?php echo nl2br(htmlspecialchars($ticket['subject'])); ?></p>
</div>
</div>
</div>
<!-- Reply Messages -->
<?php while ($reply = $replies_result->fetch_assoc()): ?>
<div class="message-wrapper">
<div class="message <?php echo $reply['is_admin'] ? 'admin' : 'student'; ?>">
<div class="message-header">
<div class="message-author">
<strong><?php echo htmlspecialchars($reply['author_name']); ?></strong>
<span class="text-muted ms-2">(<?php echo $reply['is_admin'] ? 'Admin' : 'Student'; ?>)</span>
</div>
<div class="message-time"><?php echo date('M d, Y h:i A', strtotime($reply['created_at'])); ?></div>
</div>
<div class="message-content">
<p class="mb-0"><?php echo nl2br(htmlspecialchars($reply['message'])); ?></p>
</div>
</div>
</div>
<?php endwhile; ?>
</div>
</div>
</div>
<!-- Reply Form -->
<?php if ($ticket['status'] !== 'closed'): ?>
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">Reply to Student</h5>
</div>
<div class="card-body">
<form method="post" action="">
<div class="mb-3">
<textarea class="form-control" id="reply_message" name="reply_message" rows="6" required></textarea>
</div>
<div class="d-flex justify-content-between">
<div>
<button type="submit" name="submit_reply" class="btn btn-primary">
<i class="fas fa-paper-plane me-1"></i> Send Reply
</button>
<?php if ($ticket['status'] === 'open' || $ticket['status'] === 'in_progress'): ?>
<button type="submit" name="resolve_ticket" class="btn btn-success ms-2">
<i class="fas fa-check me-1"></i> Reply & Resolve
</button>
<?php endif; ?>
</div>
<div>
<?php if ($ticket['status'] === 'open' || $ticket['status'] === 'in_progress'): ?>
<form method="post" action="" class="d-inline">
<input type="hidden" name="status" value="closed">
<button type="submit" name="update_status" class="btn btn-outline-secondary">
<i class="fas fa-times me-1"></i> Close Ticket
</button>
</form>
<?php endif; ?>
</div>
</div>
</form>
</div>
</div>
<?php else: ?>
<div class="alert alert-secondary">
<i class="fas fa-lock me-2"></i> This ticket is closed. To continue the conversation, please reopen the ticket.
<form method="post" action="" class="mt-2">
<input type="hidden" name="status" value="open">
<button type="submit" name="update_status" class="btn btn-sm btn-outline-secondary">
<i class="fas fa-lock-open me-1"></i> Reopen Ticket
</button>
</form>
</div>
<?php endif; ?>
</div>
</div>
</div>
<style>
.conversation {
max-height: 500px;
overflow-y: auto;
margin-bottom: 20px;
}
.message-wrapper {
margin-bottom: 20px;
}
.message {
padding: 15px;
border-radius: 10px;
position: relative;
}
.message.student {
background-color: #f0f2f5;
}
.message.admin {
background-color: #e3f2fd;
margin-left: 20px;
}
.message-header {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
font-size: 0.9rem;
}
.message-content {
white-space: pre-line;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Handle canned responses
const cannedResponseButtons = document.querySelectorAll('.canned-response');
const replyTextarea = document.getElementById('reply_message');
if (cannedResponseButtons.length > 0 && replyTextarea) {
cannedResponseButtons.forEach(button => {
button.addEventListener('click', function() {
let message = this.getAttribute('data-message');
// Replace placeholders with actual values
const ticket = <?php echo json_encode($ticket); ?>;
const ticketNumber = ticket.ticket_number || ticket.ticket_id || '';
message = message.replace(/{ticket_number}/g, ticketNumber);
message = message.replace(/{student_name}/g, ticket.student_name || '');
message = message.replace(/{course_name}/g, ticket.course_name || '');
replyTextarea.value = message;
replyTextarea.focus();
});
});
}
// Handle "Reply & Resolve" button
const resolveButton = document.querySelector('button[name="resolve_ticket"]');
if (resolveButton) {
resolveButton.addEventListener('click', function(e) {
e.preventDefault();
const form = this.closest('form');
// Add a hidden input for status
const statusInput = document.createElement('input');
statusInput.type = 'hidden';
statusInput.name = 'status';
statusInput.value = 'resolved';
form.appendChild(statusInput);
// Add a hidden input to indicate that we're submitting a reply
const replyInput = document.createElement('input');
replyInput.type = 'hidden';
replyInput.name = 'submit_reply';
replyInput.value = '1';
form.appendChild(replyInput);
// Submit the form
form.submit();
});
}
});
</script>
<?php include_once('includes/footer.php'); ?>