## Backend Changes - Add new API endpoints: combustible, pois, mantenimiento, video, configuracion - Fix vehiculos endpoint to return paginated response with items array - Add /vehiculos/all endpoint for non-paginated list - Add /geocercas/all endpoint - Add /alertas/configuracion GET/PUT endpoints - Add /viajes/activos and /viajes/iniciar endpoints - Add /reportes/stats, /reportes/templates, /reportes/preview endpoints - Add /conductores/all and /conductores/disponibles endpoints - Update router.py to include all new modules ## Frontend Changes - Fix authentication token handling (snake_case vs camelCase) - Update vehiculosApi.listAll to use /vehiculos/all - Fix FuelGauge component usage in Combustible page - Fix chart component exports (named + default exports) - Update API client for proper token refresh ## Infrastructure - Rename services from ADAN to ATLAS - Configure Cloudflare tunnel for atlas.consultoria-as.com - Update systemd service files - Configure PostgreSQL with TimescaleDB - Configure Redis, Mosquitto, Traccar, MediaMTX ## Documentation - Update installation guides - Update API reference - Rename all ADAN references to ATLAS Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
208 lines
5.4 KiB
TypeScript
208 lines
5.4 KiB
TypeScript
/**
|
|
* 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<T>(key: StorageKey, value: T): Promise<void> {
|
|
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<T>(key: StorageKey): Promise<T | null> {
|
|
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<void> {
|
|
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<void> {
|
|
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<T extends Record<string, unknown>>(
|
|
keys: StorageKey[]
|
|
): Promise<Partial<T>> {
|
|
try {
|
|
const pairs = await AsyncStorage.multiGet(keys);
|
|
const result: Record<string, unknown> = {};
|
|
|
|
pairs.forEach(([key, value]) => {
|
|
if (value !== null) {
|
|
try {
|
|
result[key] = JSON.parse(value);
|
|
} catch {
|
|
result[key] = value;
|
|
}
|
|
}
|
|
});
|
|
|
|
return result as Partial<T>;
|
|
} catch (error) {
|
|
console.error('Error leyendo múltiples claves:', error);
|
|
return {};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Guarda múltiples valores
|
|
*/
|
|
async setMultiple(data: Array<[StorageKey, unknown]>): Promise<void> {
|
|
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<void> {
|
|
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<boolean> {
|
|
const value = await this.get(key);
|
|
return value !== null;
|
|
}
|
|
|
|
/**
|
|
* Añade un elemento a un array existente
|
|
*/
|
|
async appendToArray<T>(key: StorageKey, item: T): Promise<void> {
|
|
const existing = await this.get<T[]>(key);
|
|
const array = existing || [];
|
|
array.push(item);
|
|
await this.set(key, array);
|
|
}
|
|
|
|
/**
|
|
* Elimina un elemento de un array por predicado
|
|
*/
|
|
async removeFromArray<T>(
|
|
key: StorageKey,
|
|
predicate: (item: T) => boolean
|
|
): Promise<void> {
|
|
const existing = await this.get<T[]>(key);
|
|
if (existing) {
|
|
const filtered = existing.filter((item) => !predicate(item));
|
|
await this.set(key, filtered);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Actualiza un elemento en un array
|
|
*/
|
|
async updateInArray<T extends { id: string }>(
|
|
key: StorageKey,
|
|
id: string,
|
|
updates: Partial<T>
|
|
): Promise<void> {
|
|
const existing = await this.get<T[]>(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<number> {
|
|
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;
|