- Refactoring: Error Boundaries, apiFetch Wrapper, Socket Status-Tracking - Refactoring: UI Kontrast (theme-aware colors), unused imports bereinigt - Symbol-Verwaltung: Neues Split-Panel (Meine Symbole + Bibliothek) - Symbol-Verwaltung: Umbenennen (TLF rot/blau), Duplikate erlaubt - Symbol-Verwaltung: Karten-Sidebar zeigt eigene Symbole bevorzugt - Schlauch-Labels: Groessere Schrift (13px/10px), verschiebbar (Drag) - Schema: TenantSymbol customName, sortOrder, unique constraint entfernt - Open Source Referenz entfernt (kostenloses Projekt)
58 lines
2.1 KiB
TypeScript
58 lines
2.1 KiB
TypeScript
import { useState, useEffect } from 'react'
|
|
import { flushSyncQueue, getSyncQueue, isOnline as checkOnline } from '@/lib/offline-sync'
|
|
|
|
interface UseOfflineSyncOptions {
|
|
toast: (opts: { title: string; description?: string; variant?: string }) => void
|
|
}
|
|
|
|
export function useOfflineSync({ toast }: UseOfflineSyncOptions) {
|
|
const [isOffline, setIsOffline] = useState(false)
|
|
const [syncQueueCount, setSyncQueueCount] = useState(0)
|
|
|
|
useEffect(() => {
|
|
setIsOffline(!checkOnline())
|
|
setSyncQueueCount(getSyncQueue().length)
|
|
|
|
const goOffline = () => {
|
|
setIsOffline(true)
|
|
toast({ title: 'Offline-Modus', description: 'Änderungen werden lokal gespeichert und beim Reconnect synchronisiert.' })
|
|
}
|
|
const goOnline = async () => {
|
|
setIsOffline(false)
|
|
const queue = getSyncQueue()
|
|
if (queue.length > 0) {
|
|
toast({ title: 'Verbindung wiederhergestellt', description: `${queue.length} Änderung(en) werden synchronisiert...` })
|
|
const result = await flushSyncQueue()
|
|
setSyncQueueCount(getSyncQueue().length)
|
|
if (result.success > 0) {
|
|
toast({ title: 'Synchronisiert', description: `${result.success} Änderung(en) erfolgreich gespeichert.` })
|
|
}
|
|
if (result.failed > 0) {
|
|
toast({ title: 'Sync-Fehler', description: `${result.failed} Änderung(en) konnten nicht gespeichert werden.`, variant: 'destructive' })
|
|
}
|
|
} else {
|
|
toast({ title: 'Wieder online' })
|
|
}
|
|
}
|
|
|
|
window.addEventListener('offline', goOffline)
|
|
window.addEventListener('online', goOnline)
|
|
|
|
// Listen for SW sync messages
|
|
if ('serviceWorker' in navigator) {
|
|
navigator.serviceWorker.addEventListener('message', (event) => {
|
|
if (event.data?.type === 'FLUSH_SYNC_QUEUE') {
|
|
flushSyncQueue().then(() => setSyncQueueCount(getSyncQueue().length))
|
|
}
|
|
})
|
|
}
|
|
|
|
return () => {
|
|
window.removeEventListener('offline', goOffline)
|
|
window.removeEventListener('online', goOnline)
|
|
}
|
|
}, [toast])
|
|
|
|
return { isOffline, syncQueueCount, setSyncQueueCount }
|
|
}
|