Add Cloudflare email and collaboration workflows
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
const trigger = bell.querySelector('.notification-bell__trigger');
|
||||
const countEl = bell.querySelector('[data-unread-count]');
|
||||
const dropdown = bell.querySelector('[data-notification-dropdown]');
|
||||
if (!trigger || !countEl || !dropdown) return;
|
||||
let isOpen = false;
|
||||
|
||||
trigger.addEventListener('click', (e) => {
|
||||
@@ -76,31 +77,42 @@
|
||||
notifications.forEach(n => {
|
||||
const li = document.createElement('li');
|
||||
li.className = n.readAt ? 'notification-item is-read' : 'notification-item';
|
||||
li.innerHTML = `
|
||||
const button = document.createElement('button');
|
||||
button.type = 'button';
|
||||
button.className = 'notification-item__button';
|
||||
button.innerHTML = `
|
||||
<div class="notification-message">${escapeHtml(n.message)}</div>
|
||||
<time class="notification-time">${formatDate(n.createdAt)}</time>
|
||||
`;
|
||||
if (!n.readAt) {
|
||||
li.addEventListener('click', () => markRead(n.id));
|
||||
}
|
||||
button.addEventListener('click', async () => {
|
||||
if (!n.readAt) await markRead(n.id, false);
|
||||
const target = notificationURL(n);
|
||||
if (target) window.location.assign(target);
|
||||
});
|
||||
li.appendChild(button);
|
||||
list.appendChild(li);
|
||||
});
|
||||
|
||||
// Add "Mark all read" button
|
||||
const footer = document.createElement('li');
|
||||
footer.className = 'notification-footer';
|
||||
const btn = document.createElement('button');
|
||||
btn.textContent = 'Mark all read';
|
||||
btn.addEventListener('click', markAllRead);
|
||||
footer.appendChild(btn);
|
||||
list.appendChild(footer);
|
||||
if (notifications.some(notification => !notification.readAt)) {
|
||||
const footer = document.createElement('li');
|
||||
footer.className = 'notification-footer';
|
||||
const btn = document.createElement('button');
|
||||
btn.textContent = 'Mark all read';
|
||||
btn.addEventListener('click', markAllRead);
|
||||
footer.appendChild(btn);
|
||||
list.appendChild(footer);
|
||||
}
|
||||
}
|
||||
|
||||
async function markRead(id) {
|
||||
async function markRead(id, refresh = true) {
|
||||
try {
|
||||
await fetch(`/api/notifications/${id}/read`, { method: 'POST' });
|
||||
updateBell();
|
||||
loadNotifications();
|
||||
const response = await fetch(`/api/notifications/${encodeURIComponent(id)}/read`, { method: 'POST' });
|
||||
if (!response.ok) throw new Error(await response.text());
|
||||
if (refresh) {
|
||||
updateBell();
|
||||
loadNotifications();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('mark read', err);
|
||||
}
|
||||
@@ -108,7 +120,8 @@
|
||||
|
||||
async function markAllRead() {
|
||||
try {
|
||||
await fetch('/api/notifications/read-all', { method: 'POST' });
|
||||
const response = await fetch('/api/notifications/read-all', { method: 'POST' });
|
||||
if (!response.ok) throw new Error(await response.text());
|
||||
updateBell();
|
||||
loadNotifications();
|
||||
} catch (err) {
|
||||
@@ -127,6 +140,12 @@
|
||||
return d.toLocaleString();
|
||||
}
|
||||
|
||||
function notificationURL(notification) {
|
||||
if (notification.resourceType !== 'document' || !notification.resourceId) return '';
|
||||
const path = notification.resourceId.replace(/^doc:/, '').split('/').map(encodeURIComponent).join('/');
|
||||
return '/docs/' + path;
|
||||
}
|
||||
|
||||
// Listen for WebSocket notification events
|
||||
if (window.__cairnquireRealtime) {
|
||||
window.__cairnquireRealtime.on('notification', () => {
|
||||
|
||||
Reference in New Issue
Block a user