78 lines
2.1 KiB
JavaScript
78 lines
2.1 KiB
JavaScript
import { Controller } from '@hotwired/stimulus';
|
|
|
|
export default class extends Controller {
|
|
static targets = ['badge', 'list'];
|
|
|
|
connect() {
|
|
this._poll();
|
|
this._interval = setInterval(() => this._poll(), 30000);
|
|
}
|
|
|
|
disconnect() {
|
|
clearInterval(this._interval);
|
|
}
|
|
|
|
async _poll() {
|
|
try {
|
|
const response = await fetch('/api/notifications');
|
|
if (!response.ok) return;
|
|
|
|
const data = await response.json();
|
|
this._updateBadge(data.unreadCount);
|
|
this._updateTitle(data.unreadCount);
|
|
this._updateList(data.notifications);
|
|
} catch (e) {
|
|
// silently ignore polling errors
|
|
}
|
|
}
|
|
|
|
_updateBadge(count) {
|
|
if (count > 0) {
|
|
this.badgeTarget.textContent = count;
|
|
this.badgeTarget.hidden = false;
|
|
} else {
|
|
this.badgeTarget.hidden = true;
|
|
}
|
|
}
|
|
|
|
_updateTitle(count) {
|
|
const base = 'Actorle';
|
|
document.title = count > 0 ? `(${count}) ${base}` : base;
|
|
}
|
|
|
|
_updateList(notifications) {
|
|
if (notifications.length === 0) {
|
|
this.listTarget.innerHTML = '<p class="dropdown-empty">Aucune notification</p>';
|
|
return;
|
|
}
|
|
|
|
this.listTarget.innerHTML = notifications.map(n => `
|
|
<div class="notification-item ${n.read ? '' : 'notification-unread'}">
|
|
<p>${this._escapeHtml(n.message)}</p>
|
|
<time>${this._formatDate(n.createdAt)}</time>
|
|
</div>
|
|
`).join('');
|
|
}
|
|
|
|
async markRead() {
|
|
await fetch('/api/notifications/read', { method: 'POST' });
|
|
this._poll();
|
|
}
|
|
|
|
_escapeHtml(text) {
|
|
const div = document.createElement('div');
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|
|
|
|
_formatDate(isoString) {
|
|
const date = new Date(isoString);
|
|
return date.toLocaleDateString('fr-FR', {
|
|
day: 'numeric',
|
|
month: 'short',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
});
|
|
}
|
|
}
|