// Сервис кэширования данных для offline режима type CachedRequest = { id: string; method: string; url: string; body?: unknown; timestamp: number; retries: number; }; const CACHE_KEY = 'mkd_offline_cache'; const MAX_RETRIES = 10; const MAX_CACHE_AGE = 7 * 24 * 60 * 60 * 1000; // 7 дней class OfflineCacheService { // Сохранить запрос в кэш cacheRequest(method: string, url: string, body?: unknown): string { const cachedRequests = this.getCachedRequests(); const id = `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; const request: CachedRequest = { id, method, url, body, timestamp: Date.now(), retries: 0, }; cachedRequests.push(request); this.saveCachedRequests(cachedRequests); return id; } // Получить все закэшированные запросы getCachedRequests(): CachedRequest[] { try { const stored = localStorage.getItem(CACHE_KEY); if (stored) { const requests = JSON.parse(stored) as CachedRequest[]; // Фильтруем устаревшие запросы const now = Date.now(); return requests.filter(req => now - req.timestamp < MAX_CACHE_AGE); } return []; } catch (e) { console.error('Failed to get cached requests', e); return []; } } // Сохранить закэшированные запросы private saveCachedRequests(requests: CachedRequest[]) { try { localStorage.setItem(CACHE_KEY, JSON.stringify(requests)); } catch (e) { console.error('Failed to save cached requests', e); } } // Удалить запрос из кэша removeRequest(id: string): void { const cachedRequests = this.getCachedRequests(); const filtered = cachedRequests.filter(req => req.id !== id); this.saveCachedRequests(filtered); } // Увеличить счётчик попыток для запроса incrementRetries(id: string): void { const cachedRequests = this.getCachedRequests(); const updated = cachedRequests.map(req => { if (req.id === id) { return { ...req, retries: req.retries + 1 }; } return req; }); this.saveCachedRequests(updated); } // Синхронизировать все закэшированные запросы async syncCachedRequests(apiBaseUrl: string): Promise<{ success: number; failed: number }> { const cachedRequests = this.getCachedRequests(); let success = 0; let failed = 0; for (const request of cachedRequests) { // Пропускаем запросы с превышенным лимитом попыток if (request.retries >= MAX_RETRIES) { this.removeRequest(request.id); failed++; continue; } try { const fullUrl = request.url.startsWith('http') ? request.url : `${apiBaseUrl}${request.url}`; const options: RequestInit = { method: request.method, headers: { 'Content-Type': 'application/json', }, }; if (request.body && (request.method === 'POST' || request.method === 'PUT')) { options.body = JSON.stringify(request.body); } const response = await fetch(fullUrl, options); if (response.ok) { this.removeRequest(request.id); success++; } else { this.incrementRetries(request.id); failed++; } } catch (error) { this.incrementRetries(request.id); failed++; } } return { success, failed }; } // Очистить весь кэш clearCache(): void { localStorage.removeItem(CACHE_KEY); } // Получить количество закэшированных запросов getCacheSize(): number { return this.getCachedRequests().length; } } // Создаём единственный экземпляр сервиса export const offlineCacheService = new OfflineCacheService();