refactor: remove localStorage for settings — all settings server-centralised
- getSettings() no longer reads from localStorage; uses _settingsCache only - saveSettingsToStorage() no longer writes to localStorage - _applySyncedSettings() no longer writes to localStorage - syncSettingsFromDB() meal_plan/tts_voice blocks no longer write to localStorage - loadSettingsUI() server-merge block no longer writes to localStorage - flipCamera() saves camera_facing directly to server via _saveSettingToServer() - New helper _saveSettingToServer(data): calls save_settings API for partial updates - onShoppingEnabledChange() / onShoppingModeChange() now immediately persist to server .env via _saveSettingToServer() — no wait for Save button - Early-theme IIFE: reads dedicated evershelf_dark_mode key (falls back to old evershelf_settings for backward compat) — only dark_mode kept in localStorage as a technical necessity for pre-render theme application
This commit is contained in:
+26
-13
@@ -1050,8 +1050,12 @@ if (!_SUPPORTED_LANGS[_currentLang]) _currentLang = 'en';
|
|||||||
// Apply theme IMMEDIATELY to prevent flash of unstyled content
|
// Apply theme IMMEDIATELY to prevent flash of unstyled content
|
||||||
(function _earlyTheme() {
|
(function _earlyTheme() {
|
||||||
try {
|
try {
|
||||||
const s = JSON.parse(localStorage.getItem('evershelf_settings') || '{}');
|
// Use dedicated key (server-synced); fall back to old full-settings object for back-compat
|
||||||
const mode = s.dark_mode || 'auto';
|
let mode = localStorage.getItem('evershelf_dark_mode');
|
||||||
|
if (!mode) {
|
||||||
|
const s = JSON.parse(localStorage.getItem('evershelf_settings') || '{}');
|
||||||
|
mode = s.dark_mode || 'auto';
|
||||||
|
}
|
||||||
const h = new Date().getHours();
|
const h = new Date().getHours();
|
||||||
const dark = mode === 'on' || (mode === 'auto' && (h >= 20 || h < 7));
|
const dark = mode === 'on' || (mode === 'auto' && (h >= 20 || h < 7));
|
||||||
document.documentElement.setAttribute('data-theme', dark ? 'dark' : 'light');
|
document.documentElement.setAttribute('data-theme', dark ? 'dark' : 'light');
|
||||||
@@ -1887,7 +1891,8 @@ async function flipCamera() {
|
|||||||
const current = s.camera_facing || 'environment';
|
const current = s.camera_facing || 'environment';
|
||||||
const next = current === 'environment' ? 'user' : 'environment';
|
const next = current === 'environment' ? 'user' : 'environment';
|
||||||
s.camera_facing = next;
|
s.camera_facing = next;
|
||||||
try { localStorage.setItem('evershelf_settings', JSON.stringify(s)); } catch(_) {}
|
_settingsCache = s;
|
||||||
|
_saveSettingToServer({ camera_facing: next });
|
||||||
showToast(next === 'user' ? t('scan.flip_front') : t('scan.flip_back'), 'info');
|
showToast(next === 'user' ? t('scan.flip_front') : t('scan.flip_back'), 'info');
|
||||||
stopScanner();
|
stopScanner();
|
||||||
setTimeout(() => initScanner(), 150);
|
setTimeout(() => initScanner(), 150);
|
||||||
@@ -2060,9 +2065,9 @@ let _settingsDirty = false;
|
|||||||
|
|
||||||
function getSettings() {
|
function getSettings() {
|
||||||
if (!_settingsCache) {
|
if (!_settingsCache) {
|
||||||
try {
|
// Settings come from server — do NOT read from localStorage (per-device storage).
|
||||||
_settingsCache = JSON.parse(localStorage.getItem('evershelf_settings') || '{}');
|
// _settingsCache is populated by _applySyncedSettings() on app init.
|
||||||
} catch(e) { _settingsCache = {}; }
|
_settingsCache = {};
|
||||||
}
|
}
|
||||||
const s = _settingsCache;
|
const s = _settingsCache;
|
||||||
// Build recipe_prefs array from individual booleans
|
// Build recipe_prefs array from individual booleans
|
||||||
@@ -2079,12 +2084,19 @@ function getSettings() {
|
|||||||
|
|
||||||
function saveSettingsToStorage(settings) {
|
function saveSettingsToStorage(settings) {
|
||||||
_settingsCache = settings;
|
_settingsCache = settings;
|
||||||
localStorage.setItem('evershelf_settings', JSON.stringify(settings));
|
// Store ONLY dark_mode locally for the pre-render early-theme IIFE.
|
||||||
// Persist to DB
|
// All other settings are server-side only (centralised, shared across clients).
|
||||||
|
try { localStorage.setItem('evershelf_dark_mode', settings.dark_mode || 'auto'); } catch(_) {}
|
||||||
|
// Persist user-prefs subset to DB
|
||||||
_settingsDirty = true;
|
_settingsDirty = true;
|
||||||
_debouncedSyncSettings();
|
_debouncedSyncSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Save one or more settings directly to server .env (partial update). */
|
||||||
|
async function _saveSettingToServer(data) {
|
||||||
|
try { await api('save_settings', {}, 'POST', data); } catch(e) { /* offline */ }
|
||||||
|
}
|
||||||
|
|
||||||
const _debouncedSyncSettings = debounce(function() {
|
const _debouncedSyncSettings = debounce(function() {
|
||||||
if (!_settingsDirty) return;
|
if (!_settingsDirty) return;
|
||||||
_settingsDirty = false;
|
_settingsDirty = false;
|
||||||
@@ -2125,13 +2137,12 @@ async function syncSettingsFromDB() {
|
|||||||
const s = getSettings();
|
const s = getSettings();
|
||||||
s.meal_plan = srv.meal_plan;
|
s.meal_plan = srv.meal_plan;
|
||||||
_settingsCache = s;
|
_settingsCache = s;
|
||||||
localStorage.setItem('evershelf_settings', JSON.stringify(s));
|
|
||||||
if (document.getElementById('meal-plan-grid')) renderMealPlanEditor();
|
if (document.getElementById('meal-plan-grid')) renderMealPlanEditor();
|
||||||
}
|
}
|
||||||
// tts_voice preference (best-effort cross-device — falls back if voice unavailable)
|
// tts_voice preference (best-effort cross-device — falls back if voice unavailable)
|
||||||
if (srv.tts_voice) {
|
if (srv.tts_voice) {
|
||||||
const s = getSettings();
|
const s = getSettings();
|
||||||
if (!s.tts_voice) { s.tts_voice = srv.tts_voice; _settingsCache = s; localStorage.setItem('evershelf_settings', JSON.stringify(s)); }
|
if (!s.tts_voice) { s.tts_voice = srv.tts_voice; _settingsCache = s; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── User data previously stored in localStorage, now server-synced ──
|
// ── User data previously stored in localStorage, now server-synced ──
|
||||||
@@ -2174,7 +2185,7 @@ async function syncSettingsFromDB() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply server settings object into localStorage cache.
|
* Apply server settings object into in-memory cache (_settingsCache).
|
||||||
* Called both from _initApp (to reuse an already-fetched response) and syncSettingsFromDB.
|
* Called both from _initApp (to reuse an already-fetched response) and syncSettingsFromDB.
|
||||||
*/
|
*/
|
||||||
function _applySyncedSettings(serverSettings) {
|
function _applySyncedSettings(serverSettings) {
|
||||||
@@ -2204,7 +2215,8 @@ function _applySyncedSettings(serverSettings) {
|
|||||||
}
|
}
|
||||||
if (changed) {
|
if (changed) {
|
||||||
_settingsCache = s;
|
_settingsCache = s;
|
||||||
localStorage.setItem('evershelf_settings', JSON.stringify(s));
|
// Persist dark_mode locally for early-theme only
|
||||||
|
try { localStorage.setItem('evershelf_dark_mode', s.dark_mode || 'auto'); } catch(_) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2870,7 +2882,6 @@ async function loadSettingsUI() {
|
|||||||
}
|
}
|
||||||
if (changed) {
|
if (changed) {
|
||||||
_settingsCache = s;
|
_settingsCache = s;
|
||||||
localStorage.setItem('evershelf_settings', JSON.stringify(s));
|
|
||||||
// Re-populate UI with merged values
|
// Re-populate UI with merged values
|
||||||
document.getElementById('setting-gemini-key').value = s.gemini_key || '';
|
document.getElementById('setting-gemini-key').value = s.gemini_key || '';
|
||||||
document.getElementById('setting-bring-email').value = s.bring_email || '';
|
document.getElementById('setting-bring-email').value = s.bring_email || '';
|
||||||
@@ -3296,6 +3307,7 @@ function onShoppingEnabledChange() {
|
|||||||
const s = getSettings();
|
const s = getSettings();
|
||||||
s.shopping_enabled = document.getElementById('setting-shopping-enabled').checked;
|
s.shopping_enabled = document.getElementById('setting-shopping-enabled').checked;
|
||||||
saveSettingsToStorage(s);
|
saveSettingsToStorage(s);
|
||||||
|
_saveSettingToServer({ shopping_enabled: s.shopping_enabled });
|
||||||
}
|
}
|
||||||
|
|
||||||
function onShoppingModeChange(value) {
|
function onShoppingModeChange(value) {
|
||||||
@@ -3304,6 +3316,7 @@ function onShoppingModeChange(value) {
|
|||||||
const s = getSettings();
|
const s = getSettings();
|
||||||
s.shopping_mode = value;
|
s.shopping_mode = value;
|
||||||
saveSettingsToStorage(s);
|
saveSettingsToStorage(s);
|
||||||
|
_saveSettingToServer({ shopping_mode: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveSettings() {
|
async function saveSettings() {
|
||||||
|
|||||||
Reference in New Issue
Block a user