function createFindWork({ fetchJson, onItems, onPagination, onStatus }) { let available = []; let pagination = { page: 1, total: 0, has_more: false }; let loadRequest = null; let claimRequest = null; function apply(result, append) { const incoming = Array.isArray(result?.items) ? result.items : []; if (append) { const byId = new Map(available.map(item => [item.id, item])); incoming.forEach(item => { if (item && !byId.has(item.id)) byId.set(item.id, { ...item }); }); available = Array.from(byId.values()); } else { available = incoming.map(item => ({ ...item })); } pagination = { page: Number(result?.page) || 1, total: Number(result?.total) || available.length, has_more: result?.has_more === true, }; onItems(available.slice()); onPagination({ ...pagination }); } function loadPage(page, append) { if (loadRequest) return loadRequest; loadRequest = fetchJson('api/v1/available-issues?page=' + page, { headers: { Accept: 'application/json' }, }).then(result => { apply(result, append); return result; }).finally(() => { loadRequest = null; }); return loadRequest; } return { reset(result) { apply(result, false); }, load() { return loadPage(1, false); }, loadMore() { if (!pagination.has_more) return Promise.resolve(false); return loadPage(pagination.page + 1, true); }, items() { return available.slice(); }, claim(item) { if (claimRequest) return claimRequest; const key = item.repository + '#' + item.number; onStatus('Assigning ' + key + '…'); const path = 'api/v1/repos/' + item.repository.split('/').map(encodeURIComponent).join('/') + '/issues/' + encodeURIComponent(item.number) + '/claim'; claimRequest = fetchJson(path, { method: 'PATCH', headers: { Accept: 'application/json' }, }).then(confirmed => { if (!Array.isArray(confirmed?.assignees) || !confirmed.assignees.length) { throw new Error('Issue assignment was not confirmed.'); } available = available.filter(candidate => candidate.repository !== item.repository || candidate.number !== item.number ); onItems(available.slice()); onStatus('Assigned ' + key + ' to you.'); return confirmed; }).finally(() => { claimRequest = null; }); return claimRequest; }, }; } if (typeof module !== 'undefined' && module.exports) module.exports = createFindWork;