205 lines
6.9 KiB
JavaScript
205 lines
6.9 KiB
JavaScript
// Progressive Web App functionality
|
|
// Handles service worker registration and PWA features
|
|
|
|
class PWAManager {
|
|
constructor() {
|
|
this.swRegistration = null;
|
|
this.init();
|
|
}
|
|
|
|
async init() {
|
|
console.log('PWA: Initializing PWA Manager...');
|
|
|
|
if ('serviceWorker' in navigator) {
|
|
try {
|
|
this.swRegistration = await navigator.serviceWorker.register('/sw.js');
|
|
console.log('SW: Service Worker registered successfully');
|
|
|
|
// Listen for updates
|
|
this.swRegistration.addEventListener('updatefound', () => {
|
|
console.log('SW: New version available');
|
|
this.showUpdateNotification();
|
|
});
|
|
|
|
} catch (error) {
|
|
console.log('SW: Service Worker registration failed:', error);
|
|
}
|
|
}
|
|
|
|
// Setup PWA install prompt
|
|
this.setupInstallPrompt();
|
|
|
|
// Setup notifications (if enabled)
|
|
this.setupNotifications();
|
|
|
|
// Show manual install option after 3 seconds if no prompt appeared
|
|
setTimeout(() => {
|
|
if (!document.getElementById('pwa-install-btn')) {
|
|
this.showManualInstallButton();
|
|
}
|
|
}, 3000);
|
|
}
|
|
|
|
setupInstallPrompt() {
|
|
let deferredPrompt;
|
|
|
|
window.addEventListener('beforeinstallprompt', (e) => {
|
|
console.log('PWA: beforeinstallprompt event fired');
|
|
// Prevent Chrome 67 and earlier from automatically showing the prompt
|
|
e.preventDefault();
|
|
deferredPrompt = e;
|
|
|
|
// Show custom install button
|
|
this.showInstallButton(deferredPrompt);
|
|
});
|
|
|
|
window.addEventListener('appinstalled', () => {
|
|
console.log('PWA: App was installed');
|
|
this.hideInstallButton();
|
|
});
|
|
|
|
// Debug: Check if app is already installed
|
|
if (this.isInstalled()) {
|
|
console.log('PWA: App is already installed (standalone mode)');
|
|
} else {
|
|
console.log('PWA: App is not installed, waiting for install prompt...');
|
|
}
|
|
}
|
|
|
|
showInstallButton(deferredPrompt) {
|
|
// Create install button
|
|
const installBtn = document.createElement('button');
|
|
installBtn.id = 'pwa-install-btn';
|
|
installBtn.className = 'btn btn-primary btn-sm';
|
|
installBtn.innerHTML = '<i class="fas fa-download"></i> Install App';
|
|
installBtn.style.cssText = `
|
|
position: fixed;
|
|
bottom: 20px;
|
|
right: 20px;
|
|
z-index: 1000;
|
|
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);
|
|
`;
|
|
|
|
installBtn.addEventListener('click', async () => {
|
|
if (deferredPrompt) {
|
|
deferredPrompt.prompt();
|
|
const { outcome } = await deferredPrompt.userChoice;
|
|
console.log('PWA: User response to install prompt:', outcome);
|
|
deferredPrompt = null;
|
|
this.hideInstallButton();
|
|
}
|
|
});
|
|
|
|
document.body.appendChild(installBtn);
|
|
}
|
|
|
|
hideInstallButton() {
|
|
const installBtn = document.getElementById('pwa-install-btn');
|
|
if (installBtn) {
|
|
installBtn.remove();
|
|
}
|
|
}
|
|
|
|
showUpdateNotification() {
|
|
// Show update available notification
|
|
const notification = document.createElement('div');
|
|
notification.className = 'alert alert-info alert-dismissible';
|
|
notification.style.cssText = `
|
|
position: fixed;
|
|
top: 20px;
|
|
right: 20px;
|
|
z-index: 1050;
|
|
max-width: 300px;
|
|
`;
|
|
|
|
notification.innerHTML = `
|
|
<strong>Update Available!</strong><br>
|
|
A new version of the app is ready.
|
|
<button type="button" class="btn btn-sm btn-outline-info ms-2" id="update-btn">
|
|
Update Now
|
|
</button>
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
`;
|
|
|
|
document.body.appendChild(notification);
|
|
|
|
// Handle update
|
|
document.getElementById('update-btn').addEventListener('click', () => {
|
|
if (this.swRegistration && this.swRegistration.waiting) {
|
|
this.swRegistration.waiting.postMessage({ type: 'SKIP_WAITING' });
|
|
window.location.reload();
|
|
}
|
|
});
|
|
}
|
|
|
|
async setupNotifications() {
|
|
// Check if notifications are supported and get permission
|
|
if ('Notification' in window) {
|
|
const permission = await this.requestNotificationPermission();
|
|
console.log('Notifications permission:', permission);
|
|
}
|
|
}
|
|
|
|
async requestNotificationPermission() {
|
|
if (Notification.permission === 'default') {
|
|
// Only request permission when user interacts with a relevant feature
|
|
// For now, just return the current status
|
|
return Notification.permission;
|
|
}
|
|
return Notification.permission;
|
|
}
|
|
|
|
// Show notification (if permission granted)
|
|
showNotification(title, options = {}) {
|
|
if (Notification.permission === 'granted') {
|
|
const notification = new Notification(title, {
|
|
icon: '/icons/icon-192x192.png',
|
|
badge: '/icons/icon-72x72.png',
|
|
tag: 'littleshop-admin',
|
|
...options
|
|
});
|
|
|
|
// Auto-close after 5 seconds
|
|
setTimeout(() => {
|
|
notification.close();
|
|
}, 5000);
|
|
|
|
return notification;
|
|
}
|
|
}
|
|
|
|
// Show manual install button for browsers that don't auto-prompt
|
|
showManualInstallButton() {
|
|
console.log('PWA: Showing manual install button');
|
|
const installBtn = document.createElement('button');
|
|
installBtn.id = 'pwa-install-btn';
|
|
installBtn.className = 'btn btn-primary btn-sm';
|
|
installBtn.innerHTML = '<i class="fas fa-mobile-alt"></i> Install as App';
|
|
installBtn.style.cssText = `
|
|
position: fixed;
|
|
bottom: 20px;
|
|
right: 20px;
|
|
z-index: 1000;
|
|
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);
|
|
`;
|
|
|
|
installBtn.addEventListener('click', () => {
|
|
alert('To install this app:\\n\\n1. Click the browser menu (⋮)\\n2. Select "Install LittleShop Admin"\\n\\nOr look for the install icon in the address bar!');
|
|
});
|
|
|
|
document.body.appendChild(installBtn);
|
|
}
|
|
|
|
// Check if app is installed
|
|
isInstalled() {
|
|
return window.matchMedia('(display-mode: standalone)').matches ||
|
|
window.navigator.standalone === true;
|
|
}
|
|
}
|
|
|
|
// Initialize PWA Manager
|
|
const pwaManager = new PWAManager();
|
|
window.pwaManager = pwaManager;
|
|
|
|
// Expose notification function globally
|
|
window.showNotification = (title, options) => pwaManager.showNotification(title, options); |