When offline, hide Files and Admin from the bottom nav and display "Offline Mode" next to the status dot. The SW offline fallback page also only shows Capture and Queue nav items. Online-only pages (browser, admin, reviewer) are never cached and go straight to the offline fallback when the network is unavailable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
123 lines
3.7 KiB
JavaScript
123 lines
3.7 KiB
JavaScript
// NextSnap - Main application logic
|
|
'use strict';
|
|
|
|
const NextSnap = {
|
|
version: '1.0.0',
|
|
isOnline: navigator.onLine,
|
|
|
|
init() {
|
|
console.log(`NextSnap v${this.version} initializing...`);
|
|
this.setupConnectivityMonitoring();
|
|
this.setupServiceWorkerMessaging();
|
|
this.checkHealth();
|
|
},
|
|
|
|
setupConnectivityMonitoring() {
|
|
// Update online status on events
|
|
window.addEventListener('online', () => {
|
|
console.log('Network: Online');
|
|
this.isOnline = true;
|
|
this.updateConnectivityIndicator();
|
|
// Sync is handled by SyncEngine's own online listener in sync.js
|
|
});
|
|
|
|
window.addEventListener('offline', () => {
|
|
console.log('Network: Offline');
|
|
this.isOnline = false;
|
|
this.updateConnectivityIndicator();
|
|
});
|
|
|
|
// Initial status
|
|
this.updateConnectivityIndicator();
|
|
},
|
|
|
|
updateConnectivityIndicator() {
|
|
const indicator = document.querySelector('.connectivity-indicator');
|
|
if (!indicator) return;
|
|
|
|
indicator.classList.remove('online', 'offline', 'syncing');
|
|
|
|
if (this.isOnline) {
|
|
indicator.classList.add('online');
|
|
indicator.title = 'Online';
|
|
} else {
|
|
indicator.classList.add('offline');
|
|
indicator.title = 'Offline';
|
|
}
|
|
|
|
// Show/hide "Offline Mode" label
|
|
const offlineLabel = document.getElementById('offlineLabel');
|
|
if (offlineLabel) {
|
|
offlineLabel.style.display = this.isOnline ? 'none' : '';
|
|
}
|
|
|
|
// Show/hide online-only nav items (Files, Admin)
|
|
document.querySelectorAll('[data-online-only]').forEach(el => {
|
|
el.style.display = this.isOnline ? '' : 'none';
|
|
});
|
|
},
|
|
|
|
setSyncingStatus(isSyncing) {
|
|
const indicator = document.querySelector('.connectivity-indicator');
|
|
if (!indicator) return;
|
|
|
|
if (isSyncing) {
|
|
indicator.classList.add('syncing');
|
|
indicator.title = 'Syncing...';
|
|
} else {
|
|
indicator.classList.remove('syncing');
|
|
indicator.title = this.isOnline ? 'Online' : 'Offline';
|
|
}
|
|
},
|
|
|
|
setupServiceWorkerMessaging() {
|
|
if ('serviceWorker' in navigator && navigator.serviceWorker.controller) {
|
|
// Listen for messages from service worker
|
|
navigator.serviceWorker.addEventListener('message', (event) => {
|
|
console.log('Message from SW:', event.data);
|
|
});
|
|
}
|
|
},
|
|
|
|
// Force service worker update
|
|
async updateServiceWorker() {
|
|
if ('serviceWorker' in navigator) {
|
|
const registration = await navigator.serviceWorker.getRegistration();
|
|
if (registration) {
|
|
await registration.update();
|
|
console.log('Service worker update check triggered');
|
|
}
|
|
}
|
|
},
|
|
|
|
// Clear all caches (for debugging)
|
|
async clearCache() {
|
|
if ('serviceWorker' in navigator && navigator.serviceWorker.controller) {
|
|
navigator.serviceWorker.controller.postMessage({
|
|
type: 'CLEAR_CACHE'
|
|
});
|
|
console.log('Cache clear requested');
|
|
}
|
|
},
|
|
|
|
async checkHealth() {
|
|
try {
|
|
const response = await fetch('/api/health');
|
|
const data = await response.json();
|
|
console.log('Health check:', data);
|
|
} catch (error) {
|
|
console.error('Health check failed:', error);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Initialize when DOM is ready
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', () => NextSnap.init());
|
|
} else {
|
|
NextSnap.init();
|
|
}
|
|
|
|
// Make NextSnap globally available
|
|
window.NextSnap = NextSnap;
|