feat: bulk acknowledge unread updates (#141)
This commit is contained in:
1 parent
cafc062b9f
commit
db9e51e683
6 files changed
+246
No files matched your search
@@ -66,6 +66,8 @@ textarea { resize: vertical; min-height: 120px; }
|
||||
.my-work-card:hover { border-color:var(--accent); }
|
||||
.my-work-card-title { display:block; margin:5px 0; font-weight:650; }
|
||||
.mark-update-read { min-height:44px; width:100%; }
|
||||
.my-work-bulk { position:sticky; bottom:0; z-index:4; margin:10px -4px -12px; padding:10px 4px; padding-bottom:calc(10px + env(safe-area-inset-bottom)); background:rgba(11,21,38,.98); border-top:1px solid #2a496e; }
|
||||
.my-work-bulk button { min-height:44px; width:100%; }
|
||||
.my-work[data-stale="true"] { border-color:#fcd34d; }
|
||||
.review-sheet { position:fixed; inset:0; z-index:50; display:none; justify-content:flex-end; background:rgba(5,12,21,.72); backdrop-filter:blur(4px); }
|
||||
.review-sheet.open { display:flex; }
|
||||
@@ -138,6 +140,9 @@ textarea { resize: vertical; min-height: 120px; }
|
||||
</div>
|
||||
<div class="my-work-list" id="my-work-list"></div>
|
||||
<div class="small" id="my-work-action-status" aria-live="assertive"></div>
|
||||
<div class="my-work-bulk" id="bulk-mark-read-bar" hidden>
|
||||
<button id="bulk-mark-read" type="button"></button>
|
||||
</div>
|
||||
</section>
|
||||
<aside class="sidebar">
|
||||
<details class="panel stack" data-panel-key="context" open>
|
||||
@@ -316,6 +321,8 @@ textarea { resize: vertical; min-height: 120px; }
|
||||
let progress = null;
|
||||
let draft = null;
|
||||
let reviewFiles = [];
|
||||
let bulkConfirmationPending = false;
|
||||
let bulkMarkPending = false;
|
||||
|
||||
async function fetchReviewJson(url, options) {
|
||||
const response = await fetch(url, options);
|
||||
@@ -345,6 +352,17 @@ textarea { resize: vertical; min-height: 120px; }
|
||||
return payload;
|
||||
}
|
||||
|
||||
async function markNotificationsRead(ids) {
|
||||
const response = await fetch('api/v1/notifications/read', {
|
||||
method: 'PATCH',
|
||||
headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ ids }),
|
||||
});
|
||||
const payload = await response.json().catch(() => ({}));
|
||||
if (!response.ok) throw new Error(payload.error || 'Bulk mark read failed.');
|
||||
return payload;
|
||||
}
|
||||
|
||||
const notificationAcknowledger = createNotificationAcknowledger({
|
||||
markRead: markNotificationRead,
|
||||
onItems: items => {
|
||||
@@ -353,6 +371,14 @@ textarea { resize: vertical; min-height: 120px; }
|
||||
},
|
||||
onStatus: message => { qs('#my-work-action-status').textContent = message; },
|
||||
});
|
||||
const bulkNotificationAcknowledger = createBulkNotificationAcknowledger({
|
||||
markRead: markNotificationsRead,
|
||||
onItems: items => {
|
||||
lastMyWork = items;
|
||||
refreshMyWorkView();
|
||||
},
|
||||
onStatus: message => { qs('#my-work-action-status').textContent = message; },
|
||||
});
|
||||
|
||||
function renderContextSnapshot(data) {
|
||||
liveMode = true;
|
||||
@@ -446,6 +472,14 @@ textarea { resize: vertical; min-height: 120px; }
|
||||
}
|
||||
});
|
||||
});
|
||||
const ids = notificationIds(visible);
|
||||
const bulkBar = qs('#bulk-mark-read-bar');
|
||||
const bulkButton = qs('#bulk-mark-read');
|
||||
bulkBar.hidden = selectedWorkFilter !== 'update' || ids.length === 0;
|
||||
bulkButton.disabled = bulkMarkPending;
|
||||
bulkButton.textContent = bulkConfirmationPending ?
|
||||
'Confirm marking ' + ids.length + ' updates read' :
|
||||
'Mark all ' + ids.length + ' updates read';
|
||||
}
|
||||
|
||||
function reviewFileElement(filename) {
|
||||
@@ -734,6 +768,27 @@ textarea { resize: vertical; min-height: 120px; }
|
||||
function load() { return contextPoller.refresh(); }
|
||||
|
||||
qs('#refresh').addEventListener('click', load);
|
||||
qs('#bulk-mark-read').addEventListener('click', async () => {
|
||||
const ids = notificationIds(filterMyWork(lastMyWork, 'update'));
|
||||
if (!ids.length || bulkMarkPending) return;
|
||||
if (!bulkConfirmationPending) {
|
||||
bulkConfirmationPending = true;
|
||||
qs('#my-work-action-status').textContent = 'Confirm to mark all visible updates read.';
|
||||
renderMyWork();
|
||||
return;
|
||||
}
|
||||
bulkConfirmationPending = false;
|
||||
bulkMarkPending = true;
|
||||
renderMyWork();
|
||||
const result = await bulkNotificationAcknowledger.acknowledge(lastMyWork, ids);
|
||||
if (result) {
|
||||
const marked = new Set(result.marked);
|
||||
lastNotifications = lastNotifications.filter(item => !marked.has(item.id));
|
||||
}
|
||||
bulkMarkPending = false;
|
||||
renderMyWork();
|
||||
(document.querySelector('[data-notification-id]') || qs('[data-work-filter="update"]'))?.focus();
|
||||
});
|
||||
document.querySelectorAll('[data-work-filter]').forEach(button => {
|
||||
button.setAttribute('aria-pressed', String(button.dataset.workFilter === selectedWorkFilter));
|
||||
button.addEventListener('click', () => {
|
||||
|
||||
Reference in new issue
Block a user