diff --git a/frontend/dashboard.js b/frontend/dashboard.js index 14fac6f..e86a1e9 100644 --- a/frontend/dashboard.js +++ b/frontend/dashboard.js @@ -139,6 +139,23 @@ storage: localStorage, getLogin: () => planningOwnerLogin, }); + const todaySync = createTodaySync({ + storage: localStorage, + getLogin: () => planningOwnerLogin, + fetchJson: fetchReviewJson, + onRemoteIds: ids => { + if (!planningOwnerLogin || !todayWork.replace(ids)) return; + refreshMyWorkView(); + warmTodayOffline(); + }, + onStatus: state => { + const status = qs('#today-sync-status'); + status.textContent = state === 'saved' ? 'Today saved to account.' : + (state === 'pending' ? 'Today saved on this device · sync pending.' : + (state === 'full' ? 'Another device filled Today · showing its saved plan.' : + 'Today sync unavailable · changes stay on this device.')); + }, + }); const laterWork = createLaterWork({ storage: localStorage, getLogin: () => planningOwnerLogin, @@ -424,7 +441,11 @@ addToday: item => { const result = todayWork.add(item); refreshMyWorkView(); - if (result === 'added') warmTodayOffline(); + if (result === 'added') { + todaySync.enqueue('add', todayWork.identity(item)); + todaySync.flush(); + warmTodayOffline(); + } return result; }, onClaimed: item => { @@ -1077,19 +1098,32 @@ (result === 'added' ? 'Added to Today without changing Gitea.' : (result === 'exists' ? 'This item is already in Today.' : 'Could not save Today on this device.')); refreshMyWorkView(); - if (result === 'added') warmTodayOffline(); + if (result === 'added') { + const item = lastMyWork[Number(button.dataset.workIndex)]; + todaySync.enqueue('add', todayWork.identity(item)); + todaySync.flush(); + warmTodayOffline(); + } }); }); document.querySelectorAll('[data-today-remove]').forEach(button => { button.addEventListener('click', () => { - todayWork.remove(lastMyWork[Number(button.dataset.workIndex)]); + const item = lastMyWork[Number(button.dataset.workIndex)]; + if (todayWork.remove(item)) { + todaySync.enqueue('remove', todayWork.identity(item)); + todaySync.flush(); + } qs('#my-work-action-status').textContent = 'Removed from Today without changing Gitea.'; refreshMyWorkView(); }); }); document.querySelectorAll('[data-today-move]').forEach(button => { button.addEventListener('click', () => { - todayWork.move(lastMyWork[Number(button.dataset.workIndex)], button.dataset.todayMove); + const item = lastMyWork[Number(button.dataset.workIndex)]; + if (todayWork.move(item, button.dataset.todayMove)) { + todaySync.enqueue('move', todayWork.identity(item), button.dataset.todayMove); + todaySync.flush(); + } refreshMyWorkView(); document.querySelector('[data-today-move="' + button.dataset.todayMove + '"][data-work-index="' + button.dataset.workIndex + '"]')?.focus(); }); @@ -1971,6 +2005,10 @@ String(snapshot.context.user?.login || '').trim() : ''; planningOwnerLogin = retainedPlanningLogin; updatePlanningAvailability(); + if (planningOwnerLogin) { + todaySync.migrate(todayWork.read()); + todaySync.flush(); + } const contextIdentityFresh = !snapshot.context.error && !contextFreshness?.stale && !contextFreshness?.degraded && !contextFreshness?.revalidating; activeFlushLogin = contextIdentityFresh ? String(snapshot.context.user?.login || '').trim() : ''; diff --git a/frontend/index.html b/frontend/index.html index 01b7429..b9d43cc 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -99,6 +99,7 @@
+
Today is saved on this device.