Files
nextsnap/app/static/js/app.js
kamaji cad4118f72 Add NextSnap PWA with photo gallery viewer and continuous capture
Offline-first photo capture app for Nextcloud with:
- Camera capture with continuous mode (auto-reopens after each photo)
- File browser with fullscreen image gallery, swipe navigation, and rename
- Upload queue with background sync engine
- Admin panel for Nextcloud user management
- Service worker for offline-first caching (v13)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 04:53:13 -06:00

112 lines
3.3 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';
}
},
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;