// Offline detection and sync queue for saving changes when reconnecting const SYNC_QUEUE_KEY = 'lageplan-sync-queue' interface SyncQueueItem { id: string url: string method: string body: string timestamp: number } /** Get all queued saves */ export function getSyncQueue(): SyncQueueItem[] { try { const raw = localStorage.getItem(SYNC_QUEUE_KEY) return raw ? JSON.parse(raw) : [] } catch { return [] } } /** Add a save operation to the sync queue (called when offline) */ export function addToSyncQueue(url: string, method: string, body: any): void { const queue = getSyncQueue() // Deduplicate: if same URL+method exists, replace it with newer data const existing = queue.findIndex(q => q.url === url && q.method === method) const item: SyncQueueItem = { id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`, url, method, body: JSON.stringify(body), timestamp: Date.now(), } if (existing >= 0) { queue[existing] = item } else { queue.push(item) } localStorage.setItem(SYNC_QUEUE_KEY, JSON.stringify(queue)) } /** Flush the sync queue — send all queued requests to the server */ export async function flushSyncQueue(): Promise<{ success: number; failed: number }> { const queue = getSyncQueue() if (queue.length === 0) return { success: 0, failed: 0 } let success = 0 let failed = 0 const remaining: SyncQueueItem[] = [] for (const item of queue) { try { const res = await fetch(item.url, { method: item.method, headers: { 'Content-Type': 'application/json' }, body: item.body, }) if (res.ok) { success++ } else { // Server error — keep in queue for retry remaining.push(item) failed++ } } catch { // Still offline — keep in queue remaining.push(item) failed++ } } localStorage.setItem(SYNC_QUEUE_KEY, JSON.stringify(remaining)) return { success, failed } } /** Clear the sync queue */ export function clearSyncQueue(): void { localStorage.removeItem(SYNC_QUEUE_KEY) } /** Check if we're online */ export function isOnline(): boolean { return navigator.onLine } /** Register Background Sync (if supported) */ export async function registerBackgroundSync(): Promise { if ('serviceWorker' in navigator && 'SyncManager' in window) { try { const reg = await navigator.serviceWorker.ready await (reg as any).sync.register('sync-saves') } catch { // Background Sync not supported or failed — will use manual flush } } }