Spaces:
Sleeping
Sleeping
| /** | |
| * Data Manager Module | |
| * Handles caching and retrieval of trade data to reduce API calls | |
| */ | |
| const DataManager = (function() { | |
| // In-memory cache | |
| const memoryCache = {}; | |
| // Check if localStorage is available | |
| const storageAvailable = function() { | |
| try { | |
| const storage = window.localStorage; | |
| const x = '__storage_test__'; | |
| storage.setItem(x, x); | |
| storage.removeItem(x); | |
| return true; | |
| } catch(e) { | |
| return false; | |
| } | |
| }; | |
| // Generate a cache key from request parameters | |
| const generateCacheKey = function(params) { | |
| return `trade_data_${params.reporterCode}_${params.partnerCode}_${params.period}_${params.cmdCode}_${params.flowCode || 'all'}`; | |
| }; | |
| // Save data to localStorage and memory cache | |
| const saveToCache = function(params, data) { | |
| const key = generateCacheKey(params); | |
| // Save to memory cache | |
| memoryCache[key] = { | |
| timestamp: Date.now(), | |
| data: data | |
| }; | |
| // Save to localStorage if available | |
| if (storageAvailable()) { | |
| try { | |
| localStorage.setItem(key, JSON.stringify({ | |
| timestamp: Date.now(), | |
| data: data | |
| })); | |
| } catch(e) { | |
| console.warn('Failed to save to localStorage:', e); | |
| } | |
| } | |
| }; | |
| // Get data from cache | |
| const getFromCache = function(params) { | |
| const key = generateCacheKey(params); | |
| // Try memory cache first | |
| if (memoryCache[key]) { | |
| return memoryCache[key].data; | |
| } | |
| // Try localStorage | |
| if (storageAvailable()) { | |
| try { | |
| const storedData = localStorage.getItem(key); | |
| if (storedData) { | |
| const parsed = JSON.parse(storedData); | |
| // Refresh memory cache with this data | |
| memoryCache[key] = parsed; | |
| return parsed.data; | |
| } | |
| } catch(e) { | |
| console.warn('Failed to retrieve from localStorage:', e); | |
| } | |
| } | |
| return null; | |
| }; | |
| // Check if data is cached | |
| const isDataCached = function(params) { | |
| return getFromCache(params) !== null; | |
| }; | |
| // Export CSV from data | |
| const exportToCsv = function(data, filename = 'trade_data.csv') { | |
| if (!data || !data.columns || !data.rows || data.rows.length === 0) { | |
| console.error('Invalid data for CSV export'); | |
| return false; | |
| } | |
| // Create CSV header row | |
| let csv = data.columns.join(',') + '\n'; | |
| // Add data rows | |
| data.rows.forEach(row => { | |
| const rowValues = data.columns.map(col => { | |
| // Handle value that might contain commas | |
| const value = row[col] !== undefined ? row[col] : ''; | |
| if (typeof value === 'string' && (value.includes(',') || value.includes('"') || value.includes('\n'))) { | |
| return `"${value.replace(/"/g, '""')}"`; | |
| } | |
| return value; | |
| }); | |
| csv += rowValues.join(',') + '\n'; | |
| }); | |
| // Create and trigger download | |
| const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); | |
| const url = URL.createObjectURL(blob); | |
| const link = document.createElement('a'); | |
| link.setAttribute('href', url); | |
| link.setAttribute('download', filename); | |
| link.style.visibility = 'hidden'; | |
| document.body.appendChild(link); | |
| link.click(); | |
| document.body.removeChild(link); | |
| return true; | |
| }; | |
| // List all cached data sets | |
| const listCachedData = function() { | |
| const cachedData = []; | |
| // List from memory cache | |
| for (const key in memoryCache) { | |
| if (key.startsWith('trade_data_')) { | |
| const parts = key.split('_'); | |
| cachedData.push({ | |
| key: key, | |
| reporter: parts[2], | |
| partner: parts[3], | |
| year: parts[4], | |
| commodity: parts[5], | |
| flow: parts[6], | |
| timestamp: new Date(memoryCache[key].timestamp).toLocaleString() | |
| }); | |
| } | |
| } | |
| // Combine with any localStorage data not in memory | |
| if (storageAvailable()) { | |
| for (let i = 0; i < localStorage.length; i++) { | |
| const key = localStorage.key(i); | |
| if (key.startsWith('trade_data_') && !memoryCache[key]) { | |
| try { | |
| const data = JSON.parse(localStorage.getItem(key)); | |
| const parts = key.split('_'); | |
| cachedData.push({ | |
| key: key, | |
| reporter: parts[2], | |
| partner: parts[3], | |
| year: parts[4], | |
| commodity: parts[5], | |
| flow: parts[6], | |
| timestamp: new Date(data.timestamp).toLocaleString() | |
| }); | |
| } catch(e) { | |
| console.warn('Failed to parse localStorage item:', key); | |
| } | |
| } | |
| } | |
| } | |
| return cachedData; | |
| }; | |
| // Clear specific cache entry | |
| const clearCacheEntry = function(key) { | |
| // Clear from memory | |
| if (memoryCache[key]) { | |
| delete memoryCache[key]; | |
| } | |
| // Clear from localStorage | |
| if (storageAvailable()) { | |
| localStorage.removeItem(key); | |
| } | |
| }; | |
| // Clear all cache | |
| const clearAllCache = function() { | |
| // Clear memory cache | |
| for (const key in memoryCache) { | |
| if (key.startsWith('trade_data_')) { | |
| delete memoryCache[key]; | |
| } | |
| } | |
| // Clear localStorage | |
| if (storageAvailable()) { | |
| const keysToRemove = []; | |
| for (let i = 0; i < localStorage.length; i++) { | |
| const key = localStorage.key(i); | |
| if (key.startsWith('trade_data_')) { | |
| keysToRemove.push(key); | |
| } | |
| } | |
| // Remove items separately to avoid index issues | |
| keysToRemove.forEach(key => localStorage.removeItem(key)); | |
| } | |
| }; | |
| // Public API | |
| return { | |
| saveToCache, | |
| getFromCache, | |
| isDataCached, | |
| exportToCsv, | |
| listCachedData, | |
| clearCacheEntry, | |
| clearAllCache | |
| }; | |
| })(); | |