/** * TASKMATE - PWA Module * ===================== * Progressive Web App Features */ class PWAManager { constructor() { this.deferredPrompt = null; this.installButton = null; this.isInstalled = false; } /** * Initialize PWA features */ init() { // Check if already installed this.checkInstallStatus(); // Listen for install prompt window.addEventListener('beforeinstallprompt', (e) => { console.log('[PWA] Install prompt available'); e.preventDefault(); this.deferredPrompt = e; this.showInstallButton(); }); // Listen for app installed window.addEventListener('appinstalled', () => { console.log('[PWA] App installed'); this.isInstalled = true; this.hideInstallButton(); this.showInstallSuccess(); }); // Check for iOS if (this.isIOS() && !this.isInStandaloneMode()) { this.showIOSInstallInstructions(); } // Update online/offline status this.updateOnlineStatus(); window.addEventListener('online', () => this.updateOnlineStatus()); window.addEventListener('offline', () => this.updateOnlineStatus()); } /** * Check if app is already installed */ checkInstallStatus() { // Check for display-mode: standalone if (window.matchMedia('(display-mode: standalone)').matches) { this.isInstalled = true; console.log('[PWA] Already running in standalone mode'); return; } // Check for iOS standalone if (window.navigator.standalone) { this.isInstalled = true; console.log('[PWA] Already running in iOS standalone mode'); return; } // Check URL parameters (for TWA) const urlParams = new URLSearchParams(window.location.search); if (urlParams.get('mode') === 'twa') { this.isInstalled = true; console.log('[PWA] Running as TWA'); return; } } /** * Show install button */ showInstallButton() { if (this.isInstalled) return; // Create install button if not exists if (!this.installButton) { this.createInstallButton(); } this.installButton.classList.remove('hidden'); // Show install banner after delay setTimeout(() => { if (!this.isInstalled && this.deferredPrompt) { this.showInstallBanner(); } }, 30000); // 30 seconds } /** * Hide install button */ hideInstallButton() { if (this.installButton) { this.installButton.classList.add('hidden'); } } /** * Create install button in header */ createInstallButton() { this.installButton = document.createElement('button'); this.installButton.className = 'btn btn-primary install-button hidden'; this.installButton.innerHTML = ` App installieren `; // Insert before user menu const headerActions = document.querySelector('.header-actions'); if (headerActions) { headerActions.insertBefore(this.installButton, headerActions.firstChild); } // Handle click this.installButton.addEventListener('click', () => this.handleInstallClick()); } /** * Handle install button click */ async handleInstallClick() { if (!this.deferredPrompt) return; // Show the install prompt this.deferredPrompt.prompt(); // Wait for the user to respond const { outcome } = await this.deferredPrompt.userChoice; console.log(`[PWA] User response: ${outcome}`); // Clear the deferred prompt this.deferredPrompt = null; // Hide button if accepted if (outcome === 'accepted') { this.hideInstallButton(); } } /** * Show install banner */ showInstallBanner() { const banner = document.createElement('div'); banner.className = 'pwa-install-banner'; banner.innerHTML = `

TaskMate App installieren

Installiere TaskMate für schnelleren Zugriff und Offline-Nutzung

`; document.body.appendChild(banner); // Animate in setTimeout(() => banner.classList.add('show'), 100); // Handle buttons banner.querySelector('[data-install]').addEventListener('click', () => { this.handleInstallClick(); this.dismissBanner(banner); }); banner.querySelectorAll('[data-dismiss]').forEach(btn => { btn.addEventListener('click', () => this.dismissBanner(banner)); }); } /** * Dismiss install banner */ dismissBanner(banner) { banner.classList.remove('show'); setTimeout(() => banner.remove(), 300); } /** * Show install success message */ showInstallSuccess() { window.dispatchEvent(new CustomEvent('toast:show', { detail: { message: 'TaskMate wurde erfolgreich installiert!', type: 'success' } })); } /** * Check if iOS */ isIOS() { return /iPhone|iPad|iPod/.test(navigator.userAgent); } /** * Check if in standalone mode */ isInStandaloneMode() { return window.navigator.standalone || window.matchMedia('(display-mode: standalone)').matches; } /** * Show iOS install instructions */ showIOSInstallInstructions() { // Only show once per session if (sessionStorage.getItem('ios-install-shown')) return; const instructions = document.createElement('div'); instructions.className = 'ios-install-instructions'; instructions.innerHTML = `

TaskMate installieren

Tippe auf und wähle "Zum Home-Bildschirm"

`; document.body.appendChild(instructions); // Animate in setTimeout(() => instructions.classList.add('show'), 100); // Handle dismiss instructions.querySelector('[data-dismiss]').addEventListener('click', () => { instructions.classList.remove('show'); setTimeout(() => instructions.remove(), 300); sessionStorage.setItem('ios-install-shown', 'true'); }); } /** * Update online/offline status */ updateOnlineStatus() { const isOnline = navigator.onLine; document.body.classList.toggle('offline', !isOnline); // Update offline banner const offlineBanner = document.getElementById('offline-banner'); if (offlineBanner) { offlineBanner.classList.toggle('hidden', isOnline); } } } // Export const pwaManager = new PWAManager(); export default pwaManager;