diff --git a/app/Views/dashboard/index.php b/app/Views/dashboard/index.php
index 4a7635a..e03b0e5 100644
--- a/app/Views/dashboard/index.php
+++ b/app/Views/dashboard/index.php
@@ -43,8 +43,8 @@
-
Realtime Attendance
-
Live stream via Server-Sent Events. Newest at top.
+
Riwayat Absensi Terbaru
+
Daftar absen terakhir (tanpa live stream), paling baru di atas.
@@ -57,11 +57,7 @@
| Status |
-
-
- | Connecting to stream… |
-
-
+
@@ -131,10 +127,7 @@
.catch(function() {});
var tbody = document.getElementById('attendance-tbody');
- var streamUrl = baseUrl + '/api/dashboard/stream';
- var afterId = 0;
- var placeholderRow = null;
- var connected = false;
+ var realtimeApiUrl = baseUrl + '/api/dashboard/realtime';
function badgeClass(status) {
var s = (status || '').toUpperCase();
@@ -152,10 +145,6 @@
}
function addRow(data) {
- if (placeholderRow && placeholderRow.parentNode) {
- placeholderRow.remove();
- placeholderRow = null;
- }
var tr = document.createElement('tr');
tr.className = 'hover:bg-gray-50 dark:hover:bg-gray-700/30';
tr.setAttribute('data-id', data.id);
@@ -166,8 +155,7 @@
'' + escapeHtml(data.class_name) + ' | ' +
'' + escapeHtml(data.subject) + ' | ' +
'' + escapeHtml(data.status) + ' | ';
- tbody.insertBefore(tr, tbody.firstChild);
- if (data.id > afterId) afterId = data.id;
+ tbody.appendChild(tr);
}
function escapeHtml(str) {
@@ -177,43 +165,29 @@
return div.innerHTML;
}
- function setPlaceholder(msg) {
- if (placeholderRow && placeholderRow.parentNode) placeholderRow.remove();
- placeholderRow = document.createElement('tr');
- placeholderRow.innerHTML = '' + escapeHtml(msg) + ' | ';
- tbody.appendChild(placeholderRow);
+ function loadRealtimeOnce() {
+ fetch(realtimeApiUrl, { method: 'GET', credentials: 'same-origin', headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' } })
+ .then(function(res) { return res.json().then(function(j) { return { ok: res.ok, data: j }; }); })
+ .then(function(r) {
+ if (!r.ok) return;
+ var list = (r.data && r.data.data) ? r.data.data : (Array.isArray(r.data) ? r.data : []);
+ tbody.innerHTML = '';
+ if (!list.length) {
+ var tr = document.createElement('tr');
+ tr.innerHTML = 'Belum ada data absensi hari ini. | ';
+ tbody.appendChild(tr);
+ return;
+ }
+ list.forEach(function(row) { addRow(row); });
+ })
+ .catch(function() {
+ var tr = document.createElement('tr');
+ tr.innerHTML = 'Gagal memuat data absensi. | ';
+ tbody.appendChild(tr);
+ });
}
- function connect() {
- var url = streamUrl + (afterId ? '?after_id=' + afterId : '');
- var es = new EventSource(url);
- es.addEventListener('attendance', function(e) {
- try {
- var data = JSON.parse(e.data);
- if (data && data.id) addRow(data);
- } catch (err) {}
- });
- es.addEventListener('heartbeat', function() {
- if (!connected) {
- connected = true;
- setPlaceholder('No attendance records yet. Waiting for new check-ins…');
- }
- });
- es.addEventListener('timeout', function() {
- es.close();
- connected = false;
- setPlaceholder('Stream ended. Reconnecting…');
- setTimeout(connect, 3000);
- });
- es.onerror = function() {
- es.close();
- connected = false;
- setPlaceholder('Connection lost. Reconnecting…');
- setTimeout(connect, 3000);
- };
- }
-
- connect();
+ loadRealtimeOnce();
if (typeof window.addEventListener === 'function') {
window.addEventListener('beforeunload', function() {