fix(settings): fix screensaver toggle (add toggle-slider, correct layout)

- Replace checkbox-label with toggle-row pattern matching other toggles
- Add missing <span class="toggle-slider"></span> inside toggle-switch
- Add data-i18n attributes to card title and hint
- Add screensaver.card_title / card_hint translations in all 3 locales

feat(demo): full demo mode implementation
- _applyDemoModeUI(): set _geminiAvailable=true + call _updateGeminiButtonState()
- api(): no-op all bring_add/bring_remove/bring_set_spec calls in demo mode
- api(): return in-memory shoppingItems for bring_list in demo mode
- loadShoppingList(): show placeholder list in demo mode, skip all Bring! calls

fix(shopping): graceful Bring! missing credentials handling
- Show friendly message with link to settings instead of raw PHP error
- Add shopping.bring_not_configured i18n key in IT/EN/DE

Bump app.js cache buster to v=20260504b
This commit is contained in:
dadaloop82
2026-05-04 16:52:22 +00:00
parent 4df06b01f4
commit 874ae90afa
5 changed files with 61 additions and 10 deletions
+42 -1
View File
@@ -112,6 +112,9 @@ function _updateGeminiButtonState() {
function _applyDemoModeUI() {
if (!_demoMode) return;
// In demo mode Gemini is always "available" — no real key needed
_geminiAvailable = true;
_updateGeminiButtonState();
// Hide the settings ⚙️ nav button
document.querySelectorAll('.nav-btn[data-page="settings"]').forEach(btn => {
btn.style.display = 'none';
@@ -119,7 +122,7 @@ function _applyDemoModeUI() {
// Prevent the setup wizard from showing
const wizard = document.getElementById('setup-wizard');
if (wizard) wizard.style.display = 'none';
// Optionally show a small demo badge in the header
// Show a small demo badge in the header
const headerLeft = document.getElementById('header-left');
if (headerLeft && !document.getElementById('_demo_badge')) {
const badge = document.createElement('span');
@@ -2233,6 +2236,17 @@ function togglePasswordVisibility(inputId) {
// ===== API HELPER =====
async function api(action, params = {}, method = 'GET', body = null, extraHeaders = {}) {
// In demo mode, all Bring! write operations are no-ops
if (_demoMode) {
const BRING_WRITE_ACTIONS = ['bring_add', 'bring_remove', 'bring_migrate_names', 'bring_set_spec'];
if (BRING_WRITE_ACTIONS.includes(action)) {
return { success: true, added: 0, removed: 0, skipped: 0, _demo: true };
}
// bring_list returns the in-memory demo list
if (action === 'bring_list') {
return { success: true, purchase: shoppingItems, listUUID: 'demo-list', _demo: true };
}
}
let url = `${API_BASE}?action=${action}`;
if (method === 'GET') {
Object.entries(params).forEach(([k, v]) => {
@@ -8637,13 +8651,40 @@ async function loadShoppingList() {
currentEl.style.display = 'none';
suggestionsEl.style.display = 'none';
// ── Demo mode: show placeholder list, skip all Bring! API calls ──────────
if (_demoMode) {
statusEl.style.display = 'none';
shoppingListUUID = 'demo-list';
shoppingItems = [
{ name: 'Latte', specification: '🟠 presto · 1L', rawName: 'Latte' },
{ name: 'Pane', specification: '', rawName: 'Pane' },
{ name: 'Uova', specification: '⚡ urgente', rawName: 'Uova' },
{ name: 'Pasta', specification: '500g', rawName: 'Pasta' },
{ name: 'Pomodori', specification: '1kg', rawName: 'Pomodori' },
];
renderShoppingItems();
currentEl.style.display = 'block';
loadSmartShopping().then(() => {
_syncOnBringFlags();
renderSmartShopping();
updateShoppingTabCounts();
renderShoppingItems();
});
return;
}
try {
const data = await api('bring_list');
statusEl.style.display = 'none';
if (!data.success) {
statusEl.style.display = 'block';
const isMissingCreds = data.error && data.error.toLowerCase().includes('credenziali bring');
if (isMissingCreds) {
statusEl.innerHTML = `<div class="bring-error">🔑 ${t('shopping.bring_not_configured') || 'Bring! non è configurato. Aggiungi email e password nelle <a href="#" onclick="showPage(\'settings\');return false;">impostazioni</a>.'}</div>`;
} else {
statusEl.innerHTML = `<div class="bring-error">⚠️ ${escapeHtml(data.error || t('error.bring_connection'))}</div>`;
}
return;
}
+6 -5
View File
@@ -1089,14 +1089,15 @@
</div>
</div>
<div class="settings-card">
<h4>🌑 Salvaschermo</h4>
<p class="settings-hint">Mostra un orologio con fatti utili dopo 5 minuti di inattività. Di default è disattivato.</p>
<h4 data-i18n="settings.screensaver.card_title">🌙 Salvaschermo</h4>
<p class="settings-hint" data-i18n="settings.screensaver.card_hint">Mostra un orologio con fatti utili dopo 5 minuti di inattività. Di default è disattivato.</p>
<div class="form-group">
<label class="checkbox-label">
<label class="toggle-row">
<span data-i18n="settings.screensaver.label">Attiva salvaschermo</span>
<span class="toggle-switch">
<input type="checkbox" id="setting-screensaver-enabled">
<span class="toggle-slider"></span>
</span>
<span data-i18n="settings.screensaver.label">Attiva salvaschermo</span>
</label>
</div>
</div>
@@ -1317,6 +1318,6 @@
</div>
</div>
<script src="assets/js/app.js?v=20260504a"></script>
<script src="assets/js/app.js?v=20260504b"></script>
</body>
</html>
+4 -1
View File
@@ -326,6 +326,7 @@
"shopping": {
"title": "🛒 Einkaufsliste",
"bring_loading": "Verbindung zu Bring!...",
"bring_not_configured": "Bring! ist nicht konfiguriert. Füge E-Mail und Passwort in den <a href='#' onclick=\"showPage('settings');return false;\">Einstellungen</a> hinzu.",
"tab_to_buy": "🛍️ Zu kaufen",
"tab_forecast": "🧠 Vorhersage",
"total_label": "💰 Geschätzter Gesamtbetrag",
@@ -596,7 +597,9 @@
"restart_notice": "Die Seite wird neu geladen, um die neue Sprache anzuwenden."
},
"screensaver": {
"label": "Bildschirmschoner aktivieren"
"label": "Bildschirmschoner aktivieren",
"card_title": "🌙 Bildschirmschoner",
"card_hint": "Zeigt nach 5 Minuten Inaktivität eine Uhr mit nützlichen Fakten. Standardmäßig deaktiviert."
},
"scale": {
"title": "⚖️ Smart-Waage",
+4 -1
View File
@@ -325,6 +325,7 @@
"shopping": {
"title": "🛒 Shopping List",
"bring_loading": "Connecting to Bring!...",
"bring_not_configured": "Bring! is not configured. Add your email and password in <a href='#' onclick=\"showPage('settings');return false;\">settings</a>.",
"tab_to_buy": "🛍️ To buy",
"tab_forecast": "🧠 Forecast",
"total_label": "💰 Estimated total",
@@ -595,7 +596,9 @@
"restart_notice": "The page will reload to apply the new language."
},
"screensaver": {
"label": "Enable screensaver"
"label": "Enable screensaver",
"card_title": "🌙 Screensaver",
"card_hint": "Shows a clock with useful facts after 5 minutes of inactivity. Disabled by default."
},
"scale": {
"title": "⚖️ Smart Scale",
+4 -1
View File
@@ -325,6 +325,7 @@
"shopping": {
"title": "🛒 Lista della Spesa",
"bring_loading": "Connessione a Bring!...",
"bring_not_configured": "Bring! non è configurato. Aggiungi email e password nelle <a href='#' onclick=\"showPage('settings');return false;\">impostazioni</a>.",
"tab_to_buy": "🛍️ Da comprare",
"tab_forecast": "🧠 In previsione",
"total_label": "💰 Totale stimato",
@@ -595,7 +596,9 @@
"restart_notice": "La pagina verrà ricaricata per applicare la nuova lingua."
},
"screensaver": {
"label": "Attiva salvaschermo"
"label": "Attiva salvaschermo",
"card_title": "🌙 Salvaschermo",
"card_hint": "Mostra un orologio con fatti utili dopo 5 minuti di inattività. Di default è disattivato."
},
"scale": {
"title": "⚖️ Bilancia Smart",