diff --git a/source/packages/com_mokosuiteclient/admin/src/Controller/DisplayController.php b/source/packages/com_mokosuiteclient/admin/src/Controller/DisplayController.php index 7678a79f..18bfc8f8 100644 --- a/source/packages/com_mokosuiteclient/admin/src/Controller/DisplayController.php +++ b/source/packages/com_mokosuiteclient/admin/src/Controller/DisplayController.php @@ -85,7 +85,12 @@ class DisplayController extends BaseController public function sendHeartbeat() { - Session::checkToken() or die(Text::_('JINVALID_TOKEN')); + if (!Session::checkToken()) + { + $this->jsonResponse(['success' => false, 'message' => 'Session expired — please reload the page.']); + + return; + } try { diff --git a/source/packages/com_mokosuiteclient/media/js/dashboard.js b/source/packages/com_mokosuiteclient/media/js/dashboard.js index 88ae33c0..15817773 100644 --- a/source/packages/com_mokosuiteclient/media/js/dashboard.js +++ b/source/packages/com_mokosuiteclient/media/js/dashboard.js @@ -126,20 +126,31 @@ document.addEventListener('DOMContentLoaded', function () { fd.append(token, '1'); fetch(url, {method: 'POST', body: fd, headers: {'X-Requested-With': 'XMLHttpRequest'}}) - .then(function (r) { return r.json(); }) + .then(function (r) { + return r.text().then(function (text) { + try { return JSON.parse(text); } + catch (e) { return {success: false, message: 'Server error: ' + text.substring(0, 200)}; } + }); + }) .then(function (d) { + var msg = d.message || (d.success ? 'Heartbeat sent to HQ.' : 'Heartbeat failed.'); if (d.success) { - Joomla.renderMessages({message: [d.message || 'Heartbeat sent to HQ.']}); + if (icon) { icon.className = 'icon-check'; icon.style.color = '#198754'; } + Joomla.renderMessages({message: [msg]}); } else { - Joomla.renderMessages({error: [d.message || 'Heartbeat failed.']}); + if (icon) { icon.className = 'icon-times'; icon.style.color = '#dc3545'; } + Joomla.renderMessages({error: [msg]}); } }) - .catch(function () { - Joomla.renderMessages({error: ['Network error sending heartbeat.']}); + .catch(function (err) { + if (icon) { icon.className = 'icon-times'; icon.style.color = '#dc3545'; } + Joomla.renderMessages({error: ['Heartbeat failed: ' + (err.message || 'network error')]}); }) .finally(function () { btn.disabled = false; - if (icon) icon.className = 'icon-upload'; + setTimeout(function () { + if (icon) { icon.className = 'icon-upload'; icon.style.color = ''; } + }, 3000); }); }); }