159 lines
5.0 KiB
JavaScript
159 lines
5.0 KiB
JavaScript
function createUpdateOwnership({
|
|
claim, addToday, available, start, recover, onClaimed, onState, onStartState,
|
|
}) {
|
|
let detail = null;
|
|
let update = null;
|
|
let claimedItem = null;
|
|
let request = null;
|
|
|
|
function state(value) {
|
|
onState?.(value);
|
|
}
|
|
|
|
function startState(value) {
|
|
onStartState?.(value);
|
|
}
|
|
|
|
function claimed(result) {
|
|
claimedItem = {
|
|
...result,
|
|
repository: detail.repository,
|
|
kind: 'issue',
|
|
notification_id: update?.notification_id,
|
|
updated_at: update?.updated_at || result.updated_at,
|
|
has_update: true,
|
|
};
|
|
detail.issue.claimable = false;
|
|
onClaimed?.(claimedItem);
|
|
startState({ action: 'hidden', busy: false, message: '' });
|
|
return claimedItem;
|
|
}
|
|
|
|
function recoverStartedItem(item) {
|
|
recover?.(item);
|
|
startState({
|
|
action: 'hidden',
|
|
busy: false,
|
|
message: 'Assigned to you, but Today could not start. The update is still unread; the owned issue is open so you can recover.',
|
|
});
|
|
state({ action: 'today', busy: false, message: '' });
|
|
return 'recovery';
|
|
}
|
|
|
|
function open(nextDetail, nextUpdate) {
|
|
detail = nextDetail;
|
|
update = nextUpdate;
|
|
claimedItem = null;
|
|
request = null;
|
|
state({
|
|
action: nextDetail?.issue?.claimable ? 'claim' : 'hidden',
|
|
busy: false,
|
|
message: '',
|
|
});
|
|
startState({
|
|
action: nextDetail?.issue?.claimable && available && start ? 'start' : 'hidden',
|
|
busy: false,
|
|
message: '',
|
|
});
|
|
}
|
|
|
|
function act() {
|
|
if (request) return request;
|
|
if (claimedItem) {
|
|
const result = addToday(claimedItem);
|
|
const messages = {
|
|
added: 'Added to Today.',
|
|
exists: 'This issue is already in Today.',
|
|
full: 'Today is limited to 5 items. Remove one before adding more.',
|
|
unavailable: 'Could not save Today on this device.',
|
|
};
|
|
state({ action: 'today', busy: false, message: messages[result] || messages.unavailable });
|
|
return Promise.resolve(result);
|
|
}
|
|
if (!detail?.issue?.claimable) return Promise.resolve('hidden');
|
|
|
|
state({ action: 'claim', busy: true, message: 'Assigning…' });
|
|
request = Promise.resolve(claim({
|
|
repository: detail.repository,
|
|
number: detail.issue.number,
|
|
})).then(result => {
|
|
claimed(result);
|
|
state({ action: 'today', busy: false, message: 'Assigned to you. The update is still unread.' });
|
|
return claimedItem;
|
|
}).catch(error => {
|
|
if (error?.status === 409) {
|
|
detail.issue.claimable = false;
|
|
startState({ action: 'hidden', busy: false, message: '' });
|
|
state({
|
|
action: 'hidden',
|
|
busy: false,
|
|
message: 'Someone else claimed or closed this issue. The update is still unread.',
|
|
});
|
|
return 'conflict';
|
|
}
|
|
state({
|
|
action: 'claim',
|
|
busy: false,
|
|
message: (error?.message || 'The issue could not be assigned.') + ' The update and your reply draft are safe; retry.',
|
|
});
|
|
return 'retry';
|
|
}).finally(() => { request = null; });
|
|
return request;
|
|
}
|
|
|
|
function startNow() {
|
|
if (request) return request;
|
|
if (!detail?.issue?.claimable || !available || !start) return Promise.resolve('hidden');
|
|
if (!available()) {
|
|
const message = 'Today is limited to 5 items. Remove one before taking ownership.';
|
|
startState({ action: 'start', busy: false, message });
|
|
return Promise.resolve('full');
|
|
}
|
|
startState({ action: 'start', busy: true, message: 'Assigning and starting…' });
|
|
state({ action: 'claim', busy: true, message: '' });
|
|
request = Promise.resolve(claim({
|
|
repository: detail.repository,
|
|
number: detail.issue.number,
|
|
})).then(result => {
|
|
const item = claimed(result);
|
|
const outcome = start(item);
|
|
if (outcome === 'started') {
|
|
startState({
|
|
action: 'hidden',
|
|
busy: false,
|
|
message: 'Assigned, added to Today, and ready to work. The update is still unread.',
|
|
});
|
|
state({ action: 'today', busy: false, message: '' });
|
|
return outcome;
|
|
}
|
|
return recoverStartedItem(item);
|
|
}).catch(error => {
|
|
if (claimedItem) {
|
|
return recoverStartedItem(claimedItem);
|
|
}
|
|
if (error?.status === 409) {
|
|
detail.issue.claimable = false;
|
|
state({ action: 'hidden', busy: false, message: '' });
|
|
startState({
|
|
action: 'hidden',
|
|
busy: false,
|
|
message: 'Someone else claimed or closed this issue. The update is still unread.',
|
|
});
|
|
return 'conflict';
|
|
}
|
|
state({ action: 'claim', busy: false, message: '' });
|
|
startState({
|
|
action: 'start',
|
|
busy: false,
|
|
message: (error?.message || 'The issue could not be assigned.') + ' The update and your reply draft are safe; retry.',
|
|
});
|
|
return 'retry';
|
|
}).finally(() => { request = null; });
|
|
return request;
|
|
}
|
|
|
|
return { open, act, start:startNow };
|
|
}
|
|
|
|
if (typeof module !== 'undefined' && module.exports) module.exports = createUpdateOwnership;
|