80 lines
3.1 KiB
JavaScript
80 lines
3.1 KiB
JavaScript
function createTodayCompletion({ todayWork, todaySync, workSession, refresh, warm, announce, advance = null,
|
|
now = Date.now, ttlMs = 10000, onOffer = null, onClear = null,
|
|
setTimer = globalThis.setTimeout, clearTimer = globalThis.clearTimeout,
|
|
undo = [globalThis.document?.getElementById('today-completion-undo'),
|
|
globalThis.document?.getElementById('undo-today-completion')] }) {
|
|
const [undoReceipt, undoControl] = undo;
|
|
let pending = null;
|
|
let expiryTimer = null;
|
|
|
|
function clear() {
|
|
if (expiryTimer !== null) clearTimer?.(expiryTimer);
|
|
expiryTimer = null;
|
|
pending = null;
|
|
if (undoReceipt) undoReceipt.hidden = true;
|
|
onClear?.();
|
|
}
|
|
|
|
function completeTodayItem(item, options = {}) {
|
|
const identity = item && todayWork.identity(item);
|
|
const snapshot = item && (todayWork.capture?.(item) ||
|
|
(identity ? { id: identity, index: 0, ids: [identity], plan: { capacity_minutes: null, estimates: {} } } : null));
|
|
if (!snapshot || !todayWork.remove(item)) {
|
|
announce(options.failureMessage || 'Could not update Today on this device. Try again.');
|
|
return false;
|
|
}
|
|
todaySync.enqueue('remove', todayWork.identity(item));
|
|
todaySync.flush();
|
|
refresh();
|
|
warm();
|
|
(advance || (() => workSession.complete()))();
|
|
announce(options.successMessage || 'Done for Today. The Gitea item is unchanged.');
|
|
pending = { snapshot, expires_at: now() + ttlMs };
|
|
if (undoReceipt) undoReceipt.hidden = false;
|
|
if (undoControl) undoControl.disabled = false;
|
|
onOffer?.({ identity: snapshot.id, expires_at: pending.expires_at });
|
|
expiryTimer = setTimer?.(clear, ttlMs) ?? null;
|
|
expiryTimer?.unref?.();
|
|
return true;
|
|
}
|
|
|
|
completeTodayItem.undo = () => {
|
|
if (!pending) return 'missing';
|
|
if (now() >= pending.expires_at) {
|
|
clear();
|
|
announce('Undo expired. Add the item back to Today from My Work.');
|
|
return 'expired';
|
|
}
|
|
const snapshot = pending.snapshot;
|
|
const result = todayWork.restore?.(snapshot) || 'unavailable';
|
|
if (result !== 'restored') {
|
|
const messages = {
|
|
full: 'Today is full. Remove another item before adding this work back.',
|
|
changed: 'Today changed on this device. Add the item back from My Work.',
|
|
unavailable: 'Could not restore Today on this device. Add the item back from My Work.',
|
|
};
|
|
clear();
|
|
announce(messages[result] || messages.unavailable);
|
|
return result;
|
|
}
|
|
todaySync.enqueue('add', snapshot.id);
|
|
for (let index = snapshot.ids.length - 1; index > snapshot.index; index -= 1) {
|
|
todaySync.enqueue('move', snapshot.id, 'up');
|
|
}
|
|
todaySync.flush();
|
|
refresh();
|
|
warm();
|
|
clear();
|
|
announce('Restored to Today. Your current work session is unchanged.');
|
|
return 'restored';
|
|
};
|
|
completeTodayItem.clear = clear;
|
|
undoControl?.addEventListener?.('click', () => {
|
|
undoControl.disabled = true;
|
|
if (completeTodayItem.undo() !== 'restored') undoControl.disabled = false;
|
|
});
|
|
return completeTodayItem;
|
|
}
|
|
|
|
if (typeof module !== 'undefined' && module.exports) module.exports = createTodayCompletion;
|