(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; let inFlight = null; 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 attend(item) { if (typeof document === 'undefined') return false; const index = options.getIndex ? options.getIndex(item) : -1; const selector = item.quarantined ? '.draft-copy' : item.checklist_conflict ? '.draft-review-checklist' : '.draft-resume'; const action = document.querySelector('#my-work-list ' + selector + '[data-draft-index="' + index + '"]'); if (!action) throw new Error('This delivery changed. Reopen recovery to load its current action.'); action.click(); return true; } function activate() { if (inFlight) return inFlight; const items = ordered(); const item = currentItem(items); const perform = state(item) === 'attention' ? attend : options.activate; if (!item) return Promise.resolve(render()); if (elements?.action) elements.action.disabled = true; if (elements?.status) elements.status.textContent = 'Working…'; inFlight = (async () => { let failure = null; try { await perform(item, state(item)); } catch (error) { failure = String(error?.message || 'Delivery could not be completed.').trim().slice(0, 160); } finally { if (elements?.action) elements.action.disabled = false; } const result = render(); if (failure && elements?.status) { elements.status.textContent = failure + ' Try again when the connection is ready.'; } return result; })().finally(() => { inFlight = null; }); return inFlight; } 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}; });