Sindbad~EG File Manager

Current Path : /home/copmadinaarea/thecopmadinaarea.org/portal/
Upload File :
Current File : /home/copmadinaarea/thecopmadinaarea.org/portal/service-worker.js

// Service Worker for Church Management System PWA
const CACHE_NAME = 'church-app-v1.0.0';
const OFFLINE_URL = '/copmadinaarea/offline.html';

// Assets to cache on install
const STATIC_CACHE = [
    '/copmadinaarea/',
    '/copmadinaarea/index.php',
    '/copmadinaarea/manifest.json',
    '/copmadinaarea/offline.html',
    // Add critical CSS/JS if you have them as separate files
];

// Dynamic cache for pages
const DYNAMIC_CACHE = 'church-app-dynamic-v1.0.0';

// Cache size limits
const CACHE_LIMITS = {
    pages: 50,
    images: 100
};

// Install event - cache static assets
self.addEventListener('install', (event) => {
    console.log('[Service Worker] Installing...');
    
    event.waitUntil(
        caches.open(CACHE_NAME)
            .then((cache) => {
                console.log('[Service Worker] Caching static assets');
                return cache.addAll(STATIC_CACHE);
            })
            .then(() => self.skipWaiting())
    );
});

// Activate event - clean up old caches
self.addEventListener('activate', (event) => {
    console.log('[Service Worker] Activating...');
    
    event.waitUntil(
        caches.keys().then((cacheNames) => {
            return Promise.all(
                cacheNames.map((cacheName) => {
                    if (cacheName !== CACHE_NAME && cacheName !== DYNAMIC_CACHE) {
                        console.log('[Service Worker] Deleting old cache:', cacheName);
                        return caches.delete(cacheName);
                    }
                })
            );
        }).then(() => self.clients.claim())
    );
});

// Fetch event - serve from cache, fallback to network
self.addEventListener('fetch', (event) => {
    const { request } = event;
    const url = new URL(request.url);
    
    // Skip cross-origin requests
    if (url.origin !== location.origin) {
        return;
    }
    
    // Skip API calls from caching (always fetch fresh)
    if (url.pathname.includes('/api/')) {
        event.respondWith(
            fetch(request).catch(() => {
                return new Response(JSON.stringify({
                    success: false,
                    message: 'You are offline. Please check your internet connection.'
                }), {
                    headers: { 'Content-Type': 'application/json' }
                });
            })
        );
        return;
    }
    
    // Network-first strategy for PHP pages
    if (request.url.endsWith('.php') || request.url.includes('?')) {
        event.respondWith(
            fetch(request)
                .then((response) => {
                    // Only cache GET requests (POST requests can't be cached)
                    if (request.method === 'GET' && response.status === 200) {
                        // Clone the response
                        const responseClone = response.clone();
                        
                        // Cache successful GET responses
                        caches.open(DYNAMIC_CACHE).then((cache) => {
                            cache.put(request, responseClone);
                            limitCacheSize(DYNAMIC_CACHE, CACHE_LIMITS.pages);
                        });
                    }
                    
                    return response;
                })
                .catch(() => {
                    // Try to get from cache
                    return caches.match(request).then((cachedResponse) => {
                        if (cachedResponse) {
                            return cachedResponse;
                        }
                        
                        // Show offline page for navigation requests
                        if (request.mode === 'navigate') {
                            return caches.match(OFFLINE_URL);
                        }
                        
                        return new Response('Offline - content not available', {
                            status: 503,
                            statusText: 'Service Unavailable'
                        });
                    });
                })
        );
        return;
    }
    
    // Cache-first strategy for static assets (images, CSS, JS)
    event.respondWith(
        caches.match(request).then((cachedResponse) => {
            if (cachedResponse) {
                return cachedResponse;
            }
            
            return fetch(request).then((response) => {
                // Don't cache non-successful responses
                if (!response || response.status !== 200 || response.type === 'error') {
                    return response;
                }
                
                const responseClone = response.clone();
                
                caches.open(DYNAMIC_CACHE).then((cache) => {
                    cache.put(request, responseClone);
                    
                    // Limit cache size based on file type
                    if (request.url.match(/\.(jpg|jpeg|png|gif|svg|webp)$/)) {
                        limitCacheSize(DYNAMIC_CACHE, CACHE_LIMITS.images);
                    }
                });
                
                return response;
            });
        })
    );
});

// Background Sync - for offline form submissions
self.addEventListener('sync', (event) => {
    console.log('[Service Worker] Background sync:', event.tag);
    
    if (event.tag === 'sync-forms') {
        event.waitUntil(syncForms());
    }
});

// Push Notification
self.addEventListener('push', (event) => {
    console.log('[Service Worker] Push received');
    
    let notificationData = {
        title: 'Church App',
        body: 'You have a new notification',
        icon: '/copmadinaarea/assets/icons/icon-192x192.png',
        badge: '/copmadinaarea/assets/icons/icon-72x72.png',
        vibrate: [200, 100, 200],
        data: {
            url: '/copmadinaarea/'
        }
    };
    
    if (event.data) {
        try {
            notificationData = event.data.json();
        } catch (e) {
            notificationData.body = event.data.text();
        }
    }
    
    event.waitUntil(
        self.registration.showNotification(notificationData.title, notificationData)
    );
});

// Notification click
self.addEventListener('notificationclick', (event) => {
    console.log('[Service Worker] Notification clicked');
    
    event.notification.close();
    
    const urlToOpen = event.notification.data?.url || '/copmadinaarea/';
    
    event.waitUntil(
        clients.matchAll({ type: 'window', includeUncontrolled: true })
            .then((clientList) => {
                // Check if app is already open
                for (let client of clientList) {
                    if (client.url === urlToOpen && 'focus' in client) {
                        return client.focus();
                    }
                }
                
                // Open new window
                if (clients.openWindow) {
                    return clients.openWindow(urlToOpen);
                }
            })
    );
});

// Helper function to limit cache size
function limitCacheSize(cacheName, maxItems) {
    caches.open(cacheName).then((cache) => {
        cache.keys().then((keys) => {
            if (keys.length > maxItems) {
                cache.delete(keys[0]).then(() => {
                    limitCacheSize(cacheName, maxItems);
                });
            }
        });
    });
}

// Helper function to sync offline forms
async function syncForms() {
    const cache = await caches.open('offline-forms');
    const requests = await cache.keys();
    
    return Promise.all(
        requests.map(async (request) => {
            try {
                const response = await fetch(request.clone());
                if (response.ok) {
                    await cache.delete(request);
                }
                return response;
            } catch (error) {
                console.error('Sync failed for:', request.url, error);
            }
        })
    );
}

// Message handler for communication with main app
self.addEventListener('message', (event) => {
    console.log('[Service Worker] Message received:', event.data);
    
    if (event.data.action === 'skipWaiting') {
        self.skipWaiting();
    }
    
    if (event.data.action === 'clearCache') {
        event.waitUntil(
            caches.keys().then((cacheNames) => {
                return Promise.all(
                    cacheNames.map((cacheName) => caches.delete(cacheName))
                );
            })
        );
    }
});

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists