Skip to content

Real-time ticket chat updates (auto-refresh every 15s)#1296

Open
KroZen-Dev wants to merge 14 commits intoCtrlpanel-gg:developmentfrom
KroZen-Dev:patch-6
Open

Real-time ticket chat updates (auto-refresh every 15s)#1296
KroZen-Dev wants to merge 14 commits intoCtrlpanel-gg:developmentfrom
KroZen-Dev:patch-6

Conversation

@KroZen-Dev
Copy link
Collaborator

@KroZen-Dev KroZen-Dev commented Jan 11, 2026

🚀 What does this PR do?
This Pull Request introduces automatic synchronization for ticket chat messages. Previously, users and administrators had to manually refresh the entire page to check for new replies. Now, the chat history updates automatically in the background every 15 seconds.

✨ Key Features:
Auto-Refresh: The ticket chat history is fetched and updated every 15 seconds via AJAX.
Improved UX: No more full page reloads required to see new messages.
Status Updates: Ticket status (e.g., Open, Answered, Closed) also updates dynamically without refreshing.

🛠 Technical Changes:
Added getComments method to TicketsController (User & Admin) to return JSON data.

Updated ticket/show.blade.php and admin/ticket/show.blade.php with JavaScript for polling.
Updated routes/web.php to include new API endpoints.

🎯 Benefits:
This improvement significantly speeds up communication between support staff and users, making the support process more fluid and responsive.

@MrWeez MrWeez requested review from 1day2die and Ferks-FK January 11, 2026 16:15
@MrWeez MrWeez added the Low Priority Can wait, not urgent. Handle when possible label Jan 13, 2026
@1day2die
Copy link
Collaborator

why was the alert for ticket deletion removed or am mi missing something here?

@KroZen-Dev
Copy link
Collaborator Author

why was the alert for ticket deletion removed or am mi missing something here?

Yes, my fault, it got mixed up with my local test versions. I'll fix it

@KroZen-Dev
Copy link
Collaborator Author

Returned confirmation. Next time I'll be more careful with local versions 😅

@KroZen-Dev KroZen-Dev changed the title Real-time ticket chat updates (auto-refresh every 30s) Real-time ticket chat updates (auto-refresh every 15s) Jan 26, 2026
@1day2die 1day2die requested a review from Copilot February 2, 2026 20:37
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements automatic real-time updates for ticket chat messages by introducing AJAX polling every 15 seconds. Previously, users had to manually refresh the page to see new replies, but now the chat history synchronizes automatically in the background without requiring full page reloads.

Changes:

  • Added auto-refresh functionality to ticket chat views with 15-second polling intervals
  • Introduced new API endpoints (getComments) in user and admin ticket controllers to return comment data as JSON
  • Added automatic table refresh for the admin ticket index page

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 9 comments.

File Description
themes/default/views/ticket/show.blade.php Added JavaScript polling logic to fetch and render ticket comments every 15 seconds for user-facing ticket view
themes/default/views/admin/ticket/show.blade.php Added JavaScript polling logic to fetch and render ticket comments every 15 seconds for admin ticket view
themes/default/views/admin/ticket/index.blade.php Added DataTable auto-reload every 15 seconds and refactored variable assignment
routes/web.php Added new routes for comment retrieval endpoints and refactored server resource routes

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

<span class="badge badge-primary">${comment.created_at}</span>
</div>
</div>
<div class="card-body" style="white-space:pre-wrap">${comment.ticketcomment}</div>
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User-generated content is being rendered without HTML escaping. The ${comment.ticketcomment} should be escaped to prevent XSS attacks. Consider using a function to escape HTML entities before inserting into the DOM, or use textContent instead of innerHTML for this field.

Copilot uses AI. Check for mistakes.
data.forEach(comment => {
let rolesHtml = '';
comment.user.roles.forEach(role => {
rolesHtml += `<span style='background-color: ${role.color}' class='badge'>${role.name}</span> `;
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The role.color and role.name values are inserted directly into HTML without sanitization. This could allow XSS attacks if malicious values are present in the database. Ensure these values are properly escaped before rendering.

Copilot uses AI. Check for mistakes.
Comment on lines +170 to +198
setInterval(function() {
fetch("{{ route('admin.ticket.comments', $ticket->ticket_id) }}")
.then(response => response.json())
.then(data => {
let html = '';
data.forEach(comment => {
let rolesHtml = '';
comment.user.roles.forEach(role => {
rolesHtml += `<span style='background-color: ${role.color}' class='badge'>${role.name}</span> `;
});

html += `
<div class="card">
<div class="card-header">
<div class="d-flex justify-content-between">
<h5 class="card-title"><img
src="${comment.user.avatar}"
class="user-image" alt="User Image">
<a href="/admin/users/${comment.user.id}">${comment.user.name}</a>
${rolesHtml}
</h5>
<span class="badge badge-primary">${comment.created_at}</span>
</div>
</div>
<div class="card-body" style="white-space:pre-wrap">${comment.ticketcomment}</div>
</div>`;
});
document.getElementById('ticket-comments').innerHTML = html;
});
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User-generated content is being rendered without HTML escaping. The ${comment.ticketcomment} should be escaped to prevent XSS attacks. Consider using a function to escape HTML entities before inserting into the DOM, or use textContent instead of innerHTML for this field.

Suggested change
setInterval(function() {
fetch("{{ route('admin.ticket.comments', $ticket->ticket_id) }}")
.then(response => response.json())
.then(data => {
let html = '';
data.forEach(comment => {
let rolesHtml = '';
comment.user.roles.forEach(role => {
rolesHtml += `<span style='background-color: ${role.color}' class='badge'>${role.name}</span> `;
});
html += `
<div class="card">
<div class="card-header">
<div class="d-flex justify-content-between">
<h5 class="card-title"><img
src="${comment.user.avatar}"
class="user-image" alt="User Image">
<a href="/admin/users/${comment.user.id}">${comment.user.name}</a>
${rolesHtml}
</h5>
<span class="badge badge-primary">${comment.created_at}</span>
</div>
</div>
<div class="card-body" style="white-space:pre-wrap">${comment.ticketcomment}</div>
</div>`;
});
document.getElementById('ticket-comments').innerHTML = html;
});
function escapeHtml(value) {
if (value === null || value === undefined) {
return '';
}
return String(value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
setInterval(function() {
fetch("{{ route('admin.ticket.comments', $ticket->ticket_id) }}")
.then(response => response.json())
.then(data => {
let html = '';
data.forEach(comment => {
let rolesHtml = '';
comment.user.roles.forEach(role => {
rolesHtml += `<span style='background-color: ${escapeHtml(role.color)}' class='badge'>${escapeHtml(role.name)}</span> `;
});
html += `
<div class="card">
<div class="card-header">
<div class="d-flex justify-content-between">
<h5 class="card-title"><img
src="${escapeHtml(comment.user.avatar)}"
class="user-image" alt="User Image">
<a href="/admin/users/${escapeHtml(comment.user.id)}">${escapeHtml(comment.user.name)}</a>
${rolesHtml}
</h5>
<span class="badge badge-primary">${escapeHtml(comment.created_at)}</span>
</div>
</div>
<div class="card-body" style="white-space:pre-wrap">${escapeHtml(comment.ticketcomment)}</div>
</div>`;
});
document.getElementById('ticket-comments').innerHTML = html;
});

Copilot uses AI. Check for mistakes.
data.forEach(comment => {
let rolesHtml = '';
comment.user.roles.forEach(role => {
rolesHtml += `<span style='background-color: ${role.color}' class='badge'>${role.name}</span> `;
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The role.color and role.name values are inserted directly into HTML without sanitization. This could allow XSS attacks if malicious values are present in the database. Ensure these values are properly escaped before rendering.

Copilot uses AI. Check for mistakes.
Comment on lines +179 to +182
setInterval(function() {
fetch("{{ route('ticket.comments', $ticket->ticket_id) }}")
.then(response => response.json())
.then(data => {
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fetch request lacks error handling. If the request fails (network error, server error, etc.), the user won't receive any feedback. Add a .catch() block to handle errors gracefully, or check response.ok before parsing JSON.

Copilot uses AI. Check for mistakes.
Comment on lines +170 to +173
setInterval(function() {
fetch("{{ route('admin.ticket.comments', $ticket->ticket_id) }}")
.then(response => response.json())
.then(data => {
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fetch request lacks error handling. If the request fails (network error, server error, etc.), the user won't receive any feedback. Add a .catch() block to handle errors gracefully, or check response.ok before parsing JSON.

Copilot uses AI. Check for mistakes.
<div class="card-header">
<div class="d-flex justify-content-between">
<h5 class="card-title"><img
src="${comment.user.avatar}"
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The avatar URL is inserted without validation. If this value contains javascript: or data: URLs, it could lead to XSS attacks. Validate that avatar URLs are safe before rendering them in img src attributes.

Copilot uses AI. Check for mistakes.
<div class="card-header">
<div class="d-flex justify-content-between">
<h5 class="card-title"><img
src="${comment.user.avatar}"
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The avatar URL is inserted without validation. If this value contains javascript: or data: URLs, it could lead to XSS attacks. Validate that avatar URLs are safe before rendering them in img src attributes.

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Low Priority Can wait, not urgent. Handle when possible

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants