function createNotificationUndo({ restore, onItems, onStatus, onOffer = () => {}, onClear = () => {} }) { let offered = null; let pending = false; return { offer(item, items) { if (!item || !Number.isInteger(item.notification_id)) return false; offered = { item, items: Array.isArray(items) ? [...items] : [] }; const label = item.key || 'Update'; onStatus(label + ' marked read. Undo?'); onOffer(item); return true; }, async run() { if (!offered || pending) return false; const current = offered; const label = current.item.key || 'Update'; pending = true; onStatus('Restoring ' + label + '…'); try { await restore(current.item.notification_id); if (offered !== current) return false; const restored = [current.item].concat(current.items.filter( item => item?.notification_id !== current.item.notification_id )); offered = null; onItems(restored, current.item); onStatus(label + ' is unread again.'); onClear(); return true; } catch (_error) { onStatus('Could not restore ' + label + '. Retry Undo.'); return false; } finally { pending = false; } }, clear() { offered = null; onClear(); }, }; } async function requestNotificationUnread(notificationId) { const response = await fetch('api/v1/notifications/' + encodeURIComponent(notificationId) + '/unread', { method: 'PATCH', headers: { Accept: 'application/json' }, }); const payload = await response.json().catch(() => ({})); if (!response.ok) throw new Error(payload.error || 'Restore unread failed.'); return payload; } function createDashboardNotificationUndo({ restore, getItems, setItems, getNotifications, setNotifications, refresh, select }) { let timer = null; const controller = createNotificationUndo({ restore, onItems: (items, restored) => { setItems(items); const notifications = getNotifications(); if (!notifications.some(item => item.id === restored.notification_id)) { setNotifications([{ id:restored.notification_id }].concat(notifications)); } refresh(); }, onStatus: message => { select('#notification-undo-status').textContent = message; select('#my-work-action-status').textContent = message; }, onOffer: item => { clearTimeout(timer); select('#notification-undo').hidden = false; select('#undo-notification').disabled = false; select('#undo-notification').setAttribute('aria-label', 'Undo marking ' + (item.key || 'update') + ' read'); timer = setTimeout(() => controller.clear(), 10000); }, onClear: () => { select('#notification-undo').hidden = true; }, }); return controller; } if (typeof module !== 'undefined' && module.exports) { module.exports = createNotificationUndo; module.exports.createDashboardNotificationUndo = createDashboardNotificationUndo; }