diff --git a/frontend/app.js b/frontend/app.js
index 093f9af..c70d6aa 100755
--- a/frontend/app.js
+++ b/frontend/app.js
@@ -1528,6 +1528,28 @@ async function renderSettings() {
+
+
+
+
Reset
+
+
+ Force refresh UI
+ Re-fetches the app shell and assets, bypassing the browser cache, then reloads.
+
+
+
+
+
+
+
+ Reset app
+ Clears all local storage, unregisters the service worker, and deletes every cache. You will need to reload after.
+
+
+
+
+
`;
c.appendChild(wrap);
@@ -1633,6 +1655,49 @@ async function renderSettings() {
$('backupNowBtn').addEventListener('click', () => doAutoBackup());
$('importBackupBtn').addEventListener('click', () => $('backupFileInput').click());
$('backupFileInput').addEventListener('change', importBackup);
+
+ // ---- Reset ----
+ $('refreshUiBtn').addEventListener('click', async () => {
+ const btn = $('refreshUiBtn');
+ btn.disabled = true;
+ btn.textContent = 'Refreshing…';
+ try {
+ await Promise.all([
+ fetch('/', { cache: 'reload' }),
+ fetch('/app.js', { cache: 'reload' }),
+ fetch('/app.css', { cache: 'reload' }),
+ ]);
+ } catch { /* network hiccup — reload anyway */ }
+ location.reload();
+ });
+
+ $('resetAppBtn').addEventListener('click', () => {
+ showModal(
+ 'Reset app?',
+ (() => { const p = document.createElement('p'); p.textContent = 'This clears all local data and caches. The page will reload.'; return p; })(),
+ [
+ { label: 'Cancel', onClick: closeModal },
+ {
+ label: 'Reset', danger: true, onClick: async () => {
+ closeModal();
+ try {
+ localStorage.clear();
+ sessionStorage.clear();
+ if ('serviceWorker' in navigator) {
+ const regs = await navigator.serviceWorker.getRegistrations();
+ await Promise.all(regs.map((r) => r.unregister()));
+ }
+ if ('caches' in window) {
+ const keys = await caches.keys();
+ await Promise.all(keys.map((k) => caches.delete(k)));
+ }
+ } catch { /* best effort — reload regardless */ }
+ window.location.href = '/';
+ },
+ },
+ ],
+ );
+ });
}
function renderCard(v, index, list) {