Files
kaunter/resources/views/layouts/partials/notification_inbox.blade.php
T
ismailmasseran c437a3f504
Build Docker Image / build-frontend (push) Successful in 53s
Feature/whatsapp blast (#24)
Co-authored-by: ISMAIL MASSERAN <topaz@Mac.dlinkrouter.local>
Co-authored-by: ISMAIL MASSERAN <topaz@ISMAILs-Macbook.local>
Reviewed-on: #24
2026-09-24 11:28:05 +08:00

245 lines
7.1 KiB
PHP

<style>
.staff-notification-menu {
min-width: 340px;
max-width: 380px;
padding: 0;
}
.staff-notification-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 14px;
border-bottom: 1px solid #eee;
font-weight: 600;
font-size: 13px;
}
.staff-notification-header button {
border: 0;
background: none;
color: #1abc9c;
font-size: 12px;
padding: 0;
cursor: pointer;
}
.staff-notification-header button:disabled {
color: #bbb;
cursor: default;
}
.staff-notification-list {
max-height: 360px;
overflow-y: auto;
}
.staff-notification-item {
display: block;
padding: 10px 14px;
border-bottom: 1px solid #f3f3f3;
white-space: normal;
color: #333;
text-decoration: none;
}
.staff-notification-item:hover {
background: #f8f9fa;
text-decoration: none;
color: #333;
}
.staff-notification-item.is-unread {
background: #eafaf6;
}
.staff-notification-item .sn-title {
font-size: 13px;
font-weight: 600;
margin-bottom: 2px;
}
.staff-notification-item.is-unread .sn-title {
font-weight: 700;
}
.staff-notification-item .sn-body,
.staff-notification-item .sn-time {
font-size: 12px;
color: #666;
margin: 0;
}
.staff-notification-empty {
padding: 18px 14px;
text-align: center;
color: #888;
font-size: 13px;
}
.staff-notification-badge {
position: absolute;
top: 2px;
right: 0;
font-size: 10px;
min-width: 16px;
padding: 2px 5px;
border-radius: 10px;
background: #e74c3c;
color: #fff;
line-height: 1.2;
display: none;
}
.staff-notification-toggle {
position: relative;
display: inline-block;
}
a.nav-link #staff-notification-badge {
position: absolute;
top: 2px;
right: -4px;
}
li.nav-item.dropdown > a.nav-link {
position: relative;
}
</style>
<div id="staff-notification-inbox">
<div class="staff-notification-header">
<span>Notifikasi</span>
<button type="button" id="staff-notification-mark-all" disabled>Tanda semua dibaca</button>
</div>
<div id="staff-notification-list" class="staff-notification-list">
<div class="staff-notification-empty">Memuatkan...</div>
</div>
</div>
<script>
(function () {
var listUrl = @json(route('notifications.index'));
var markAllUrl = @json(route('notifications.read.all'));
var markOneUrlTemplate = @json(url('/notifications/__ID__/read'));
var csrf = document.querySelector('meta[name="csrf-token"]');
var csrfToken = csrf ? csrf.getAttribute('content') : '';
function markOneUrl(id) {
return markOneUrlTemplate.replace('__ID__', id);
}
function escapeHtml(value) {
return String(value == null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
}
function setBadge(count) {
var badge = document.getElementById('staff-notification-badge');
var bell = document.getElementById('bell');
if (!badge) {
return;
}
if (count > 0) {
badge.style.display = 'inline-block';
badge.textContent = count > 99 ? '99+' : String(count);
if (bell) {
bell.style.color = '#e74c3c';
}
} else {
badge.style.display = 'none';
badge.textContent = '';
if (bell) {
bell.style.color = '';
}
}
var markAll = document.getElementById('staff-notification-mark-all');
if (markAll) {
markAll.disabled = count < 1;
}
}
function render(payload) {
var wrap = document.getElementById('staff-notification-list');
if (!wrap) {
return;
}
var items = payload.notifications || [];
setBadge(payload.unread_count || 0);
if (!items.length) {
wrap.innerHTML = '<div class="staff-notification-empty">Tiada notifikasi</div>';
return;
}
wrap.innerHTML = items.map(function (item) {
var unread = !item.read_at;
return (
'<a class="dropdown-item staff-notification-item' + (unread ? ' is-unread' : '') + '" href="' + escapeHtml(item.url || '#') + '" data-id="' + item.id + '">' +
'<div class="sn-title">' + escapeHtml(item.title) + '</div>' +
(item.body ? '<p class="sn-body">' + escapeHtml(item.body) + '</p>' : '') +
'<p class="sn-time">' + escapeHtml(item.created_at_human || '') + '</p>' +
'</a>'
);
}).join('');
}
function loadInbox() {
return fetch(listUrl, {
headers: { 'Accept': 'application/json', 'X-Requested-With': 'XMLHttpRequest' },
credentials: 'same-origin'
}).then(function (res) {
if (!res.ok) {
throw new Error('Gagal muat notifikasi');
}
return res.json();
}).then(render).catch(function () {
var wrap = document.getElementById('staff-notification-list');
if (wrap) {
wrap.innerHTML = '<div class="staff-notification-empty">Tidak dapat memuatkan notifikasi</div>';
}
});
}
function postJson(url) {
return fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-TOKEN': csrfToken
},
credentials: 'same-origin',
body: '{}'
}).then(function (res) {
if (!res.ok) {
throw new Error('Gagal kemaskini notifikasi');
}
return res.json();
});
}
document.addEventListener('click', function (event) {
var target = event.target;
if (target && target.nodeType !== 1) {
target = target.parentElement;
}
if (!target || !target.closest) {
return;
}
var item = target.closest('.staff-notification-item');
if (!item) {
return;
}
var id = item.getAttribute('data-id');
if (!id) {
return;
}
postJson(markOneUrl(id)).catch(function () {});
});
var markAll = document.getElementById('staff-notification-mark-all');
if (markAll) {
markAll.addEventListener('click', function (event) {
event.preventDefault();
event.stopPropagation();
postJson(markAllUrl).then(function () {
loadInbox();
}).catch(function () {});
});
}
loadInbox();
setInterval(loadInbox, 30000);
})();
</script>