// hooks/useOfflineSync.js import { useState, useEffect } from 'react'; import { useApi, useDb } from '@cap-rel/smartcommon'; export function useOfflineSync() { const api = useApi(); const db = useDb({ name: 'monApp', version: 1, stores: { tasks: 'id, synced', syncQueue: 'id++, action, entity, entityId, data' } }); const [isOnline, setIsOnline] = useState(navigator.onLine); const [isSyncing, setIsSyncing] = useState(false); // Détecter le statut réseau useEffect(() => { const handleOnline = () => { setIsOnline(true); sync(); // Synchroniser automatiquement }; const handleOffline = () => setIsOnline(false); window.addEventListener('online', handleOnline); window.addEventListener('offline', handleOffline); return () => { window.removeEventListener('online', handleOnline); window.removeEventListener('offline', handleOffline); }; }, []); // Synchroniser les données const sync = async () => { if (!navigator.onLine || isSyncing) return; setIsSyncing(true); try { // 1. Envoyer les modifications locales const queue = await db.syncQueue.toArray(); for (const item of queue) { try { if (item.action === 'create') { await api.private.post(item.entity, { json: item.data }); } else if (item.action === 'update') { await api.private.put(`${item.entity}/${item.entityId}`, { json: item.data }); } else if (item.action === 'delete') { await api.private.delete(`${item.entity}/${item.entityId}`); } // Supprimer de la queue await db.syncQueue.delete(item.id); } catch (err) { console.error('Sync error:', err); } } // 2. Récupérer les données fraîches du serveur const data = await api.private.get('tasks').json(); // 3. Mettre à jour la base locale await db.tasks.clear(); await db.tasks.bulkAdd(data.tasks.map(t => ({ ...t, synced: true }))); } finally { setIsSyncing(false); } }; // Ajouter une action à la queue const queueAction = async (action, entity, entityId, data) => { await db.syncQueue.add({ action, entity, entityId, data, createdAt: Date.now() }); }; return { db, isOnline, isSyncing, sync, queueAction }; }