Files
2026-07-14 04:33:26 +02:00

237 lines
9.0 KiB
JavaScript

/**
* PWA Install and Service Worker Helper
* Powered by Antigravity AI
*/
(function () {
const BASE_PATH = window.BASE_PATH || '';
// Register Service Worker
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
const swUrl = `${BASE_PATH}/sw.js`;
navigator.serviceWorker.register(swUrl)
.then((registration) => {
console.log('[PWA] Service Worker registrato con successo:', registration.scope);
})
.catch((error) => {
console.error('[PWA] Registrazione Service Worker fallita:', error);
});
});
}
// Detectors
const isStandalone = window.matchMedia('(display-mode: standalone)').matches || window.navigator.standalone === true;
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
// Se l'app viene aperta in modalità standalone (PWA) su desktop, reindirizza all'interno dell'app
if (isStandalone && !isMobile) {
const urlParams = new URLSearchParams(window.location.search);
if (!urlParams.has('app') || urlParams.get('app') !== 'true') {
const currentPath = window.location.pathname;
const pathWithoutBase = currentPath.replace(BASE_PATH, '').replace(/^\//, '');
const redirectParam = pathWithoutBase ? '&redirect=' + encodeURIComponent(pathWithoutBase) : '';
window.location.href = BASE_PATH + '/?app=true' + redirectParam;
}
}
// Global variables
window.deferredPrompt = null;
// Check if banner was dismissed in the last 7 days
function isBannerDismissed() {
const dismissedTime = localStorage.getItem('pwa-banner-dismissed');
if (!dismissedTime) return false;
const sevenDays = 7 * 24 * 60 * 60 * 1000;
return (Date.now() - parseInt(dismissedTime, 10)) < sevenDays;
}
// Dismiss banner
function dismissBanner() {
localStorage.setItem('pwa-banner-dismissed', Date.now().toString());
const banner = document.getElementById('pwa-install-banner');
if (banner) {
banner.classList.remove('show');
setTimeout(() => {
banner.style.display = 'none';
}, 400);
}
}
// Initialize UI components and listeners
function initPwaUI() {
// If already in standalone mode, hide all promotional components
if (isStandalone) {
console.log('[PWA] Applicazione avviata in modalità Standalone. Nascondo elementi PWA.');
return;
}
const headerBtn = document.getElementById('pwa-header-install-btn');
const desktopBtn = document.getElementById('desktopPwaInstallBtn');
const banner = document.getElementById('pwa-install-banner');
const bannerInstallBtn = document.getElementById('pwa-banner-install-btn');
const bannerCloseBtn = document.getElementById('pwa-banner-close-btn');
// On iOS, show the installation buttons immediately (as they don't support beforeinstallprompt)
if (isIOS) {
console.log('[PWA] Rilevato dispositivo iOS');
if (headerBtn) headerBtn.style.display = 'inline-flex';
if (desktopBtn) desktopBtn.style.display = 'inline-flex';
if (banner && !isBannerDismissed()) {
banner.style.display = 'flex';
setTimeout(() => banner.classList.add('show'), 100);
}
}
// Attach click listeners to all PWA installation buttons
const triggerInstall = (e) => {
e.preventDefault();
if (window.deferredPrompt) {
// Show native install prompt (Android / Desktop Chrome / Edge)
window.deferredPrompt.prompt();
window.deferredPrompt.userChoice.then((choiceResult) => {
if (choiceResult.outcome === 'accepted') {
console.log('[PWA] Utente ha installato la PWA');
dismissBanner();
} else {
console.log('[PWA] Utente ha annullato l\'installazione');
}
window.deferredPrompt = null;
});
} else {
// Fallback for iOS Safari or other unsupported prompts
showInstructionsModal();
}
};
if (headerBtn) headerBtn.addEventListener('click', triggerInstall);
if (desktopBtn) desktopBtn.addEventListener('click', triggerInstall);
if (bannerInstallBtn) bannerInstallBtn.addEventListener('click', triggerInstall);
if (bannerCloseBtn) {
bannerCloseBtn.addEventListener('click', (e) => {
e.preventDefault();
dismissBanner();
});
}
// Modal Close logic
const modal = document.getElementById('pwa-instructions-modal');
const modalCloseBtnTop = document.getElementById('pwa-modal-close-btn');
const closeModal = () => {
if (modal) {
modal.classList.remove('show');
setTimeout(() => {
modal.style.display = 'none';
}, 300);
}
};
if (modalCloseBtnTop) modalCloseBtnTop.addEventListener('click', closeModal);
if (modal) {
modal.addEventListener('click', (e) => {
if (e.target === modal) closeModal();
});
}
}
// Listen for beforeinstallprompt (Chrome / Android / Edge)
window.addEventListener('beforeinstallprompt', (e) => {
// Prevent Chrome 67 and earlier from automatically showing the prompt
e.preventDefault();
// Se siamo su desktop, non salviamo il prompt e non mostriamo nessun banner promozionale PWA
if (!isMobile) {
console.log('[PWA] Installazione via browser intercettata su desktop. Ignorata per requisiti.');
return;
}
// Stash the event so it can be triggered later.
window.deferredPrompt = e;
console.log('[PWA] Evento beforeinstallprompt intercettato.');
// Show custom buttons and banner (if not dismissed)
const headerBtn = document.getElementById('pwa-header-install-btn');
const desktopBtn = document.getElementById('desktopPwaInstallBtn');
const banner = document.getElementById('pwa-install-banner');
if (headerBtn) headerBtn.style.display = 'inline-flex';
if (desktopBtn) desktopBtn.style.display = 'inline-flex';
if (banner && !isBannerDismissed()) {
banner.style.display = 'flex';
setTimeout(() => banner.classList.add('show'), 100);
}
});
// Track successful installation
window.addEventListener('appinstalled', () => {
console.log('[PWA] L\'applicazione è stata installata con successo.');
window.deferredPrompt = null;
// Hide all promotional components
const headerBtn = document.getElementById('pwa-header-install-btn');
const desktopBtn = document.getElementById('desktopPwaInstallBtn');
const banner = document.getElementById('pwa-install-banner');
if (headerBtn) headerBtn.style.display = 'none';
if (desktopBtn) desktopBtn.style.display = 'none';
if (banner) banner.style.display = 'none';
});
// Show instructions modal (iOS / Fallback)
function showInstructionsModal() {
const modal = document.getElementById('pwa-instructions-modal');
const content = document.getElementById('pwa-instructions-content');
if (!modal || !content) return;
if (isIOS) {
content.innerHTML = `
<div class="pwa-step">
<div class="pwa-step-num">1</div>
<div class="pwa-step-text">Tocca l'icona di <strong>Condividi</strong> <span class="pwa-inline-icon"><i class="material-icons" style="font-size:18px; color:#f7b835;">share</i></span> (il quadrato con la freccia verso l'alto) nella barra in basso di Safari.</div>
</div>
<div class="pwa-step">
<div class="pwa-step-num">2</div>
<div class="pwa-step-text">Scorri l'elenco delle opzioni verso il basso e seleziona <strong>Aggiungi alla schermata Home</strong> <span class="pwa-inline-icon"><i class="material-icons" style="font-size:18px; color:#f7b835;">add_box</i></span>.</div>
</div>
<div class="pwa-step">
<div class="pwa-step-num">3</div>
<div class="pwa-step-text">Tocca <strong>Aggiungi</strong> nell'angolo in alto a destra per inserire l'icona sul tuo telefono.</div>
</div>
`;
} else {
content.innerHTML = `
<div class="pwa-step">
<div class="pwa-step-num">1</div>
<div class="pwa-step-text">Apri il menu delle impostazioni del browser toccando i <strong>tre puntini</strong> <span class="pwa-inline-icon"><i class="material-icons" style="font-size:18px; color:#f7b835;">more_vert</i></span> in alto a destra.</div>
</div>
<div class="pwa-step">
<div class="pwa-step-num">2</div>
<div class="pwa-step-text">Seleziona la voce <strong>Installa applicazione</strong> o <strong>Aggiungi a schermata Home</strong>.</div>
</div>
<div class="pwa-step">
<div class="pwa-step-num">3</div>
<div class="pwa-step-text">Conferma per scaricare la PWA sul tuo telefono.</div>
</div>
`;
}
modal.style.display = 'flex';
setTimeout(() => modal.classList.add('show'), 10);
}
// Run on DOM loaded
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initPwaUI);
} else {
initPwaUI();
}
})();