5000) {
$error_message = 'Reply must be 5000 characters or less.';
} else {
try {
$stmt = $panelPdo->prepare("SELECT id, status FROM support_tickets WHERE id = ? AND sender_type = 'client' AND sender_id = ?");
$stmt->execute([$replyTicketId, $client_id]);
$ticket = $stmt->fetch();
if (!$ticket) {
$error_message = 'Ticket not found or access denied.';
} elseif ($ticket['status'] === 'closed') {
$error_message = 'Cannot reply to a closed ticket.';
} else {
$stmt = $panelPdo->prepare("INSERT INTO support_messages (ticket_id, sender_type, sender_id, message, is_internal) VALUES (?, 'user', ?, ?, 0)");
$stmt->execute([$replyTicketId, $client_id, $replyMessage]);
$messageId = $panelPdo->lastInsertId();
// Handle file attachments
if ($supportHelperLoaded && !empty($_FILES['attachments']['name'][0])) {
handleSupportAttachments($panelPdo, $messageId, $_FILES['attachments']);
}
// Reopen ticket if resolved/pending
if (in_array($ticket['status'], ['resolved', 'pending'])) {
$panelPdo->prepare("UPDATE support_tickets SET status = 'open', updated_at = NOW() WHERE id = ?")->execute([$replyTicketId]);
} else {
$panelPdo->prepare("UPDATE support_tickets SET updated_at = NOW() WHERE id = ?")->execute([$replyTicketId]);
}
$success_message = 'Reply sent successfully!';
$viewTicketId = $replyTicketId;
}
} catch (Exception $e) {
error_log("Client ticket reply error: " . $e->getMessage());
$error_message = 'Failed to send reply. Please try again.';
}
}
}
// -- Handle ticket creation --
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !isset($_POST['reply_ticket_id'])) {
$subject = isset($_POST['subject']) ? trim($_POST['subject']) : '';
$message = isset($_POST['message']) ? trim($_POST['message']) : '';
$priority = isset($_POST['priority']) ? $_POST['priority'] : 'medium';
if (empty($subject) || empty($message)) {
$error_message = 'Subject and message are required.';
} elseif (strlen($subject) > 255) {
$error_message = 'Subject must be 255 characters or less.';
} elseif (strlen($message) > 5000) {
$error_message = 'Message must be 5000 characters or less.';
} else {
try {
$panelPdo->beginTransaction();
$ticketNumber = 'TKT-' . date('Ymd') . '-' . strtoupper(substr(bin2hex(random_bytes(4)), 0, 6));
$stmt = $panelPdo->prepare("INSERT INTO support_tickets (ticket_number, user_id, sender_type, sender_id, subject, status, priority) VALUES (?, NULL, 'client', ?, ?, 'open', ?)");
$stmt->execute([$ticketNumber, $client_id, $subject, $priority]);
$ticketId = $panelPdo->lastInsertId();
$stmt = $panelPdo->prepare("INSERT INTO support_messages (ticket_id, sender_type, sender_id, message, is_internal) VALUES (?, 'user', ?, ?, 0)");
$stmt->execute([$ticketId, $client_id, $message]);
$messageId = $panelPdo->lastInsertId();
$panelPdo->commit();
// Handle file attachments
if ($supportHelperLoaded && !empty($_FILES['attachments']['name'][0])) {
handleSupportAttachments($panelPdo, $messageId, $_FILES['attachments']);
}
$success_message = "Support ticket created successfully! Ticket Number: $ticketNumber
We will respond to your query shortly.";
$_POST = [];
} catch (Exception $e) {
if ($panelPdo->inTransaction()) $panelPdo->rollBack();
error_log("Client ticket creation error: " . $e->getMessage());
$error_message = 'Failed to create support ticket. Please try again.';
}
}
}
// -- Load ticket detail if viewing --
if ($viewTicketId) {
try {
$stmt = $panelPdo->prepare("
SELECT st.*, au.full_name as assigned_to_name
FROM support_tickets st
LEFT JOIN admin_users au ON st.assigned_to = au.id
WHERE st.id = ? AND st.sender_type = 'client' AND st.sender_id = ?
");
$stmt->execute([$viewTicketId, $client_id]);
$viewTicket = $stmt->fetch();
if ($viewTicket) {
$stmt = $panelPdo->prepare("
SELECT sm.*,
CASE
WHEN sm.sender_type = 'admin' THEN COALESCE((SELECT full_name FROM admin_users WHERE id = sm.sender_id), 'Support Team')
ELSE ?
END as sender_name
FROM support_messages sm
WHERE sm.ticket_id = ? AND sm.is_internal = 0
ORDER BY sm.created_at ASC
");
$stmt->execute([$client_name, $viewTicketId]);
$ticketMessages = $stmt->fetchAll();
// Load attachments for all messages
if ($supportHelperLoaded && function_exists('getAttachmentsForMessages') && !empty($ticketMessages)) {
$msgIds = array_column($ticketMessages, 'id');
$messageAttachments = getAttachmentsForMessages($panelPdo, $msgIds);
}
}
} catch (Exception $e) {
error_log("Client ticket load error: " . $e->getMessage());
}
}
// -- Load tickets list --
try {
$stmt = $panelPdo->prepare("
SELECT st.*, au.full_name as assigned_to_name,
(SELECT COUNT(*) FROM support_messages WHERE ticket_id = st.id AND is_internal = 0) as message_count
FROM support_tickets st
LEFT JOIN admin_users au ON st.assigned_to = au.id
WHERE st.sender_type = 'client' AND st.sender_id = ?
ORDER BY st.updated_at DESC
");
$stmt->execute([$client_id]);
$tickets = $stmt->fetchAll();
} catch (Exception $e) {
error_log("Client ticket list error: " . $e->getMessage());
$tickets = [];
}
// Helper: get file icon class
function getClientFileIcon($type, $name) {
$ext = strtolower(pathinfo($name, PATHINFO_EXTENSION));
if (in_array($ext, ['jpg','jpeg','png','gif','webp'])) return 'fa-file-image';
if ($ext === 'pdf') return 'fa-file-pdf';
if (in_array($ext, ['doc','docx'])) return 'fa-file-word';
if (in_array($ext, ['xls','xlsx','csv'])) return 'fa-file-excel';
return 'fa-file-alt';
}
// Ticket counts by status
$statusCounts = ['open' => 0, 'pending' => 0, 'resolved' => 0, 'closed' => 0];
foreach ($tickets as $t) {
if (isset($statusCounts[$t['status']])) $statusCounts[$t['status']]++;
}
$page_title = 'Support';
include 'client-portal-header.php';
?>
Create and manage support tickets. Logged in as:
No messages yet.
You haven't created any support tickets. Create one above if you need assistance.