stackchain-dashboard/frontend/mobile-first-task.js
timmy ebb7a78cab
All checks were successful
CI / lint (pull_request) Successful in 2m48s
CI / build-release (pull_request) Successful in 6s
CI / browser-journey (pull_request) Successful in 4m3s
CI / release-candidate (pull_request) Has been skipped
feat: finish onboarding with active Today (Closes #1144)
2026-08-19 18:51:15 +00:00

104 lines
4.0 KiB
JavaScript

(function (root, factory) {
if (typeof module === 'object' && module.exports) module.exports = factory;
else root.createMobileFirstTask = factory;
})(typeof self !== 'undefined' ? self : this, function createMobileFirstTask(options) {
const doc = typeof document !== 'undefined' ? document : null;
const win = typeof window !== 'undefined' ? window : null;
options = Object.assign({
storage: typeof localStorage !== 'undefined' ? localStorage : null,
isOnline: () => typeof navigator === 'undefined' || navigator.onLine,
mediaQuery: win?.matchMedia('(max-width: 600px)') || {matches:false},
eventTarget: win,
sheet: doc?.querySelector('#mobile-first-task'),
title: doc?.querySelector('#mobile-first-task-title'),
findButton: doc?.querySelector('#mobile-first-task-find'),
createButton: doc?.querySelector('#mobile-first-task-create'),
setupButton: doc?.querySelector('#mobile-first-task-setup'),
closeButton: doc?.querySelector('#close-mobile-first-task'),
status: doc?.querySelector('#mobile-first-task-status'),
isTodayActive: () => false,
onFind: () => doc?.querySelector('#find-work')?.click(),
onCreate: () => doc?.querySelector('#new-issue')?.click(),
onSetup: () => doc?.querySelector('#open-device-setup')?.click(),
}, options);
const prefix = 'stackchain.first-task.v1:';
function account() {
return String(options.getLogin?.() || '').trim().toLowerCase();
}
function key() {
const login = account();
return login ? prefix + login : '';
}
function completed() {
const currentKey = key();
if (!currentKey) return false;
try { return options.storage.getItem(currentKey) === 'complete'; }
catch (_error) { return false; }
}
function required() {
return Boolean(options.mediaQuery.matches && account() && !options.isTodayActive() && !completed());
}
function markComplete() {
const currentKey = key();
if (!currentKey) return;
try { options.storage.setItem(currentKey, 'complete'); }
catch (_error) {}
}
function render() {
const online = options.isOnline();
const awaitingStart = options.hasWork();
options.findButton.disabled = !online;
if (options.title) options.title.textContent = awaitingStart ? 'Finish starting your first task' : 'Start your first task';
options.findButton.textContent = 'Find & start';
options.createButton.textContent = 'Create & start';
options.status.textContent = awaitingStart ?
'Your task is ready. Start it from Find or create and start another task.' : online ?
'Choose a task to claim and start, or create and start one of your own.' :
'You are offline. Create a task now and it will stay in Drafts until you reconnect.';
}
function open() {
if (!required()) return false;
render();
if (!options.sheet.open) options.sheet.showModal();
(options.findButton.disabled ? options.createButton : options.findButton).focus();
return true;
}
function refresh() {
if (account() && options.isTodayActive() && !completed()) {
markComplete();
if (options.sheet.open) options.sheet.close();
return 'completed';
}
if (options.sheet.open) render();
if (required() && options.hasWork()) return 'awaiting-start';
return required() ? 'required' : 'inactive';
}
function handoff(callback, requiresOnline = false) {
if (requiresOnline && !options.isOnline()) return;
if (options.sheet.open) options.sheet.close();
callback();
}
function start() {
options.findButton.addEventListener('click', () => handoff(options.onFind, true));
options.createButton.addEventListener('click', () => handoff(options.onCreate));
options.setupButton.addEventListener('click', () => handoff(options.onSetup));
options.closeButton.addEventListener('click', () => {
if (options.sheet.open) options.sheet.close();
});
options.eventTarget?.addEventListener('online', render);
options.eventTarget?.addEventListener('offline', render);
}
return {required, open, refresh, render, start};
});