149 lines
5.6 KiB
JavaScript
149 lines
5.6 KiB
JavaScript
(function (root, factory) {
|
|
if (typeof module === 'object' && module.exports) module.exports = factory;
|
|
else root.createMobileDeliveryRecovery = factory;
|
|
})(typeof self !== 'undefined' ? self : this, function createMobileDeliveryRecovery(options) {
|
|
const byId = id => typeof document === 'undefined' ? null : document.getElementById(id);
|
|
const elements = options.elements || (typeof document === 'undefined' ? null : {
|
|
dialog: byId('mobile-delivery-recovery'), close: byId('close-mobile-delivery-recovery'),
|
|
title: byId('mobile-delivery-recovery-title'), destination: byId('mobile-delivery-recovery-destination'),
|
|
reason: byId('mobile-delivery-recovery-reason'), progress: byId('mobile-delivery-recovery-progress'),
|
|
action: byId('mobile-delivery-recovery-action'), status: byId('mobile-delivery-recovery-status'),
|
|
});
|
|
const priority = {authorization: 0, attention: 1, uncertain: 2, waiting: 3};
|
|
|
|
function identity(item) {
|
|
return String(item?.outbox_id || item?.id || '');
|
|
}
|
|
|
|
function state(item) {
|
|
if (item?.status === 'authorization') return 'authorization';
|
|
if (item?.status === 'attention' || item?.checklist_conflict || item?.quarantined) return 'attention';
|
|
if (item?.delivery_state === 'uncertain') return 'uncertain';
|
|
return 'waiting';
|
|
}
|
|
|
|
function primary(item) {
|
|
const kind = state(item);
|
|
if (kind === 'authorization') {
|
|
return item?.outbox_kind === 'issue-close' ? 'Authorize & close' : 'Authorize & send';
|
|
}
|
|
if (item?.checklist_conflict) return 'Review changes';
|
|
if (kind === 'attention') return item?.quarantined ? 'Copy content' : 'Open current item';
|
|
if (kind === 'uncertain') return 'Verified not posted — retry';
|
|
return 'Retry now';
|
|
}
|
|
|
|
function ordered() {
|
|
return [...(options.getItems ? options.getItems() : [])].sort((left, right) => {
|
|
const byState = priority[state(left)] - priority[state(right)];
|
|
if (byState) return byState;
|
|
return identity(left).localeCompare(identity(right));
|
|
});
|
|
}
|
|
|
|
const stateLabels = {
|
|
authorization: 'Authorization required',
|
|
attention: 'Needs attention',
|
|
uncertain: 'Delivery uncertain',
|
|
waiting: 'Ready to retry',
|
|
};
|
|
let currentId = '';
|
|
let active = false;
|
|
|
|
function currentItem(items) {
|
|
return items.find(item => identity(item) === currentId) || items[0];
|
|
}
|
|
|
|
function snapshot() {
|
|
const items = ordered();
|
|
const item = currentItem(items);
|
|
if (item) currentId = identity(item);
|
|
else currentId = '';
|
|
const index = item ? items.indexOf(item) : -1;
|
|
return {
|
|
count: items.length,
|
|
current: item ? {
|
|
id: identity(item),
|
|
state: state(item),
|
|
primary: primary(item),
|
|
position: index + 1,
|
|
total: items.length,
|
|
} : null,
|
|
};
|
|
}
|
|
|
|
function render() {
|
|
const result = snapshot();
|
|
if (!elements) return result;
|
|
const items = ordered();
|
|
const item = currentItem(items);
|
|
if (!item) {
|
|
if (active) {
|
|
active = false;
|
|
if (elements.dialog?.open) elements.dialog.close();
|
|
if (options.onComplete) options.onComplete();
|
|
}
|
|
return result;
|
|
}
|
|
elements.title.textContent = item.title || 'Queued delivery';
|
|
elements.destination.textContent = [item.repository, item.details].filter(Boolean).join(' · ') || 'Saved delivery';
|
|
elements.reason.textContent = item.last_attempt_error || item.ownership || stateLabels[state(item)];
|
|
elements.progress.textContent = 'Delivery ' + result.current.position + ' of ' + result.current.total + ' · ' + stateLabels[state(item)];
|
|
elements.action.textContent = primary(item);
|
|
if (elements.status) elements.status.textContent = '';
|
|
return result;
|
|
}
|
|
|
|
function open() {
|
|
const queue = byId('mobile-queue-sheet');
|
|
if (queue?.open) queue.close();
|
|
if (options.beforeOpen) options.beforeOpen();
|
|
currentId = '';
|
|
const result = snapshot();
|
|
if (!result.current) return 'empty';
|
|
active = true;
|
|
render();
|
|
if (elements?.dialog && !elements.dialog.open) elements.dialog.showModal();
|
|
return 'opened';
|
|
}
|
|
|
|
async function defaultActivate(item) {
|
|
if (typeof document === 'undefined') return false;
|
|
const index = options.getIndex ? options.getIndex(item) : -1;
|
|
const selector = item.status === 'authorization' ? '.draft-authorize' :
|
|
item.checklist_conflict ? '.draft-review-checklist' : item.quarantined ? '.draft-copy' :
|
|
item.status === 'attention' ? '.draft-resume' : '.draft-send';
|
|
const action = document.querySelector('#my-work-list ' + selector + '[data-draft-index="' + index + '"]');
|
|
if (!action) {
|
|
if (elements.status) elements.status.textContent = 'This delivery changed. Reopen recovery to load its current action.';
|
|
return false;
|
|
}
|
|
action.click();
|
|
if (selector === '.draft-resume' || selector === '.draft-copy') elements.dialog.close();
|
|
await Promise.resolve();
|
|
return true;
|
|
}
|
|
|
|
async function activate() {
|
|
const items = ordered();
|
|
const item = currentItem(items);
|
|
const perform = options.activate || defaultActivate;
|
|
if (!item) return render();
|
|
if (elements?.action) elements.action.disabled = true;
|
|
if (elements?.status) elements.status.textContent = 'Working…';
|
|
try {
|
|
await perform(item, state(item));
|
|
} finally {
|
|
if (elements?.action) elements.action.disabled = false;
|
|
}
|
|
return render();
|
|
}
|
|
|
|
function start() {
|
|
if (elements?.action?.addEventListener) elements.action.addEventListener('click', activate);
|
|
if (elements?.close?.addEventListener) elements.close.addEventListener('click', () => elements.dialog.close());
|
|
}
|
|
|
|
return {activate, open, render, snapshot, start};
|
|
});
|