// =============================== // AVVIO // =============================== console.log("main.js avviato"); // =============================== // UTILS AUTH + SYNC HEADER UI // =============================== function isAuthenticated() { // Fonte verità: presenza del token in localStorage return !!localStorage.getItem("token"); } /** * Sincronizza l’UI dell’header in base allo stato auth: * - Aggiunge una classe sul body (CSS-friendly) * - Mostra/Nasconde il bottone logout (hotfix inline, se vuoi puoi affidarti solo al CSS) */ function syncHeaderAuthUI() { const authed = isAuthenticated(); document.body.classList.toggle('authenticated', authed); const logoutBtn = document.getElementById('logoutBtn'); if (logoutBtn) { // Hotfix immediato: forza la visibilità anche via inline style // (puoi rimuovere queste due righe se preferisci usare solo la regola CSS body.authenticated #logoutBtn) logoutBtn.style.display = authed ? 'inline-flex' : 'none'; } } // =============================== // PATCH: misura l'altezza reale dell'header e aggiorna --header-h // (serve per far partire la mappa subito sotto l’header, anche su mobile) // =============================== (function () { const root = document.documentElement; const header = document.querySelector('header'); function setHeaderHeight() { const h = header ? Math.round(header.getBoundingClientRect().height) : 60; root.style.setProperty('--header-h', h + 'px'); } setHeaderHeight(); if (window.ResizeObserver && header) { const ro = new ResizeObserver(setHeaderHeight); ro.observe(header); } else { window.addEventListener('resize', setHeaderHeight); window.addEventListener('orientationchange', setHeaderHeight); } window.addEventListener('load', setHeaderHeight); })(); // =============================== // PATCH: quando si apre la mappa (#globalMap.open) invalida le dimensioni Leaflet // (utile perché prima era display:none; invalidateSize evita “tagli” o tile sfasati) // =============================== (function () { const mapEl = document.getElementById('globalMap'); if (!mapEl) return; function invalidateWhenOpen() { if (!mapEl.classList.contains('open')) return; // Aspetta un tick così il layout è aggiornato setTimeout(() => { try { // In mapGlobal.js imposta: window.leafletMapInstance = window.globalMap; window.leafletMapInstance?.invalidateSize(); } catch (e) { console.warn('invalidateSize non eseguito:', e); } }, 0); } // 1) Osserva il cambio classe (quando aggiungi .open) const mo = new MutationObserver((mutations) => { if (mutations.some(m => m.attributeName === 'class')) { invalidateWhenOpen(); } }); mo.observe(mapEl, { attributes: true, attributeFilter: ['class'] }); // 2) Fallback: se usi il bottone #openMapBtn per aprire/chiudere document.getElementById('openMapBtn')?.addEventListener('click', () => { setTimeout(invalidateWhenOpen, 0); }); })(); // =============================== // MENU ⋮ (toggle apri/chiudi con lo stesso bottone, senza global conflicts) // =============================== (() => { const optBtn = document.getElementById("optionsBtn"); const optSheet = document.getElementById("optionsSheet"); const overlayEl= document.getElementById("sheetOverlay"); if (!optBtn || !optSheet) return; function openOptionsSheet() { try { window.closeBottomSheet?.(); } catch {} optSheet.classList.add("open"); overlayEl?.classList.add("open"); // ARIA (facoltativo) optBtn.setAttribute("aria-expanded", "true"); optSheet.setAttribute("aria-hidden", "false"); } function closeOptionsSheet() { optSheet.classList.remove("open"); overlayEl?.classList.remove("open"); // ARIA (facoltativo) optBtn.setAttribute("aria-expanded", "false"); optSheet.setAttribute("aria-hidden", "true"); } function toggleOptionsSheet(e) { e?.preventDefault(); e?.stopPropagation(); if (optSheet.classList.contains("open")) closeOptionsSheet(); else openOptionsSheet(); } // Click sul bottone: toggle (fase di cattura per battere eventuali altri handler) optBtn.addEventListener("click", toggleOptionsSheet, { capture: true }); // Chiudi clic overlay overlayEl?.addEventListener("click", (e) => { e.stopPropagation(); closeOptionsSheet(); }); // Chiudi con ESC document.addEventListener("keydown", (e) => { if (e.key === "Escape" && optSheet.classList.contains("open")) { closeOptionsSheet(); } }); // Evita chiusure involontarie per click interni optSheet.addEventListener("click", (e) => e.stopPropagation()); // Espone una close per usarla altrove (es. dopo la scelta) window.closeOptionsSheet = closeOptionsSheet; })(); // =============================== // LOGIN AUTOMATICO SU INDEX // =============================== document.addEventListener("DOMContentLoaded", async () => { // Allinea subito l’UI in base al token eventualmente già presente syncHeaderAuthUI(); try { // 1) Carica config const cfgRes = await fetch('/config'); const cfg = await cfgRes.json(); window.BASE_URL = cfg.baseUrl; // 2) Recupera token salvato const savedToken = localStorage.getItem("token"); // Se non c'è token → mostra login if (!savedToken) { document.getElementById("loginModal").style.display = "flex"; return; } // 3) Verifica token const ping = await fetch(`${window.BASE_URL}/photos`, { headers: { "Authorization": "Bearer " + savedToken } }); if (!ping.ok) { // Token invalido → cancella e mostra login localStorage.removeItem("token"); syncHeaderAuthUI(); // riallinea header subito document.getElementById("loginModal").style.display = "flex"; return; } // 4) Token valido → salva e carica gallery window.token = savedToken; syncHeaderAuthUI(); // <— mostra il logout senza refresh loadPhotos(); } catch (err) { console.error("Errore autenticazione:", err); document.getElementById("loginModal").style.display = "flex"; } }); // =============================== // VARIABILI GLOBALI // =============================== let currentSort = "desc"; let currentGroup = "auto"; let currentFilter = null; window.currentSort = currentSort; window.currentGroup = currentGroup; window.currentFilter = currentFilter; // =============================== // BOTTONI OPZIONI // =============================== document.querySelectorAll("#optionsSheet .sheet-btn").forEach(btn => { btn.addEventListener("click", () => { if (btn.dataset.sort) window.currentSort = currentSort = btn.dataset.sort; if (btn.dataset.group) window.currentGroup = currentGroup = btn.dataset.group; if (btn.dataset.filter) window.currentFilter = currentFilter = btn.dataset.filter; // Chiudi sheet e overlay dopo la scelta (usa l’API esposta sopra) window.closeOptionsSheet?.(); refreshGallery(); }); }); // =============================== // REFRESH GALLERY // =============================== function refreshGallery() { console.log("Aggiornamento galleria..."); const data = Array.isArray(window.photosData) ? window.photosData : []; let photos = [...data]; if (typeof applyFilters === 'function') photos = applyFilters(photos); if (typeof sortByDate === 'function') photos = sortByDate(photos, currentSort); let sections = [{ label: 'Tutte', photos }]; if (typeof groupByDate === 'function') sections = groupByDate(photos, currentGroup); if (typeof renderGallery === 'function') { renderGallery(sections); } } window.refreshGallery = refreshGallery; // =============================== // SETTINGS (⚙️) — apre admin.html // =============================== const settingsBtn = document.getElementById('settingsBtn'); settingsBtn?.addEventListener('click', () => { window.location.href = "admin.html"; }); // =============================== // LOGIN SUBMIT // =============================== document.getElementById("loginSubmit").addEventListener("click", async () => { const email = document.getElementById("loginEmail").value; const password = document.getElementById("loginPassword").value; const errorEl = document.getElementById("loginError"); errorEl.textContent = ""; try { const res = await fetch(`${window.BASE_URL}/auth/login`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email, password }) }); if (!res.ok) { errorEl.textContent = "Utente o password errati"; return; } const data = await res.json(); const token = data.token; // Salva token localStorage.setItem("token", token); window.token = token; // Chiudi login const loginModalEl = document.getElementById("loginModal"); if (loginModalEl) loginModalEl.style.display = "none"; // Riallinea UI header subito (mostra logout) e carica gallery syncHeaderAuthUI(); loadPhotos(); } catch (err) { console.error("Errore login:", err); errorEl.textContent = "Errore di connessione al server"; } });