/** * Servicio de almacenamiento local usando AsyncStorage * Wrapper con tipado y manejo de errores */ import AsyncStorage from '@react-native-async-storage/async-storage'; // Claves de almacenamiento export const STORAGE_KEYS = { AUTH_TOKEN: '@atlas/auth_token', CONDUCTOR: '@atlas/conductor', DISPOSITIVO: '@atlas/dispositivo', UBICACIONES_OFFLINE: '@atlas/ubicaciones_offline', VIAJE_ACTIVO: '@atlas/viaje_activo', CONFIGURACION: '@atlas/configuracion', ULTIMO_SYNC: '@atlas/ultimo_sync', MENSAJES_PENDIENTES: '@atlas/mensajes_pendientes', PARADAS_PENDIENTES: '@atlas/paradas_pendientes', COMBUSTIBLE_PENDIENTE: '@atlas/combustible_pendiente', } as const; type StorageKey = typeof STORAGE_KEYS[keyof typeof STORAGE_KEYS]; class StorageService { /** * Guarda un valor en el almacenamiento */ async set(key: StorageKey, value: T): Promise { try { const jsonValue = JSON.stringify(value); await AsyncStorage.setItem(key, jsonValue); } catch (error) { console.error(`Error guardando ${key}:`, error); throw new Error(`No se pudo guardar en ${key}`); } } /** * Obtiene un valor del almacenamiento */ async get(key: StorageKey): Promise { try { const jsonValue = await AsyncStorage.getItem(key); if (jsonValue === null) { return null; } return JSON.parse(jsonValue) as T; } catch (error) { console.error(`Error leyendo ${key}:`, error); return null; } } /** * Elimina un valor del almacenamiento */ async remove(key: StorageKey): Promise { try { await AsyncStorage.removeItem(key); } catch (error) { console.error(`Error eliminando ${key}:`, error); throw new Error(`No se pudo eliminar ${key}`); } } /** * Elimina múltiples valores */ async removeMultiple(keys: StorageKey[]): Promise { try { await AsyncStorage.multiRemove(keys); } catch (error) { console.error('Error eliminando múltiples claves:', error); throw new Error('No se pudieron eliminar las claves'); } } /** * Obtiene múltiples valores */ async getMultiple>( keys: StorageKey[] ): Promise> { try { const pairs = await AsyncStorage.multiGet(keys); const result: Record = {}; pairs.forEach(([key, value]) => { if (value !== null) { try { result[key] = JSON.parse(value); } catch { result[key] = value; } } }); return result as Partial; } catch (error) { console.error('Error leyendo múltiples claves:', error); return {}; } } /** * Guarda múltiples valores */ async setMultiple(data: Array<[StorageKey, unknown]>): Promise { try { const pairs: Array<[string, string]> = data.map(([key, value]) => [ key, JSON.stringify(value), ]); await AsyncStorage.multiSet(pairs); } catch (error) { console.error('Error guardando múltiples valores:', error); throw new Error('No se pudieron guardar los valores'); } } /** * Limpia todo el almacenamiento de la app */ async clearAll(): Promise { try { const keys = await AsyncStorage.getAllKeys(); const atlasKeys = keys.filter((key) => key.startsWith('@atlas/')); await AsyncStorage.multiRemove(atlasKeys); } catch (error) { console.error('Error limpiando almacenamiento:', error); throw new Error('No se pudo limpiar el almacenamiento'); } } /** * Verifica si existe una clave */ async exists(key: StorageKey): Promise { const value = await this.get(key); return value !== null; } /** * Añade un elemento a un array existente */ async appendToArray(key: StorageKey, item: T): Promise { const existing = await this.get(key); const array = existing || []; array.push(item); await this.set(key, array); } /** * Elimina un elemento de un array por predicado */ async removeFromArray( key: StorageKey, predicate: (item: T) => boolean ): Promise { const existing = await this.get(key); if (existing) { const filtered = existing.filter((item) => !predicate(item)); await this.set(key, filtered); } } /** * Actualiza un elemento en un array */ async updateInArray( key: StorageKey, id: string, updates: Partial ): Promise { const existing = await this.get(key); if (existing) { const updated = existing.map((item) => item.id === id ? { ...item, ...updates } : item ); await this.set(key, updated); } } /** * Obtiene el tamaño aproximado del almacenamiento */ async getStorageSize(): Promise { try { const keys = await AsyncStorage.getAllKeys(); const atlasKeys = keys.filter((key) => key.startsWith('@atlas/')); const pairs = await AsyncStorage.multiGet(atlasKeys); let totalSize = 0; pairs.forEach(([key, value]) => { totalSize += key.length + (value?.length || 0); }); return totalSize; } catch (error) { console.error('Error calculando tamaño:', error); return 0; } } } export const storage = new StorageService(); export default storage;