FlotillasGPS - Sistema completo de monitoreo de flotillas GPS
Sistema completo para monitoreo y gestion de flotas de vehiculos con: - Backend FastAPI con PostgreSQL/TimescaleDB - Frontend React con TypeScript y TailwindCSS - App movil React Native con Expo - Soporte para dispositivos GPS, Meshtastic y celulares - Video streaming en vivo con MediaMTX - Geocercas, alertas, viajes y reportes - Autenticacion JWT y WebSockets en tiempo real Documentacion completa y guias de usuario incluidas.
This commit is contained in:
207
mobile/src/services/storage.ts
Normal file
207
mobile/src/services/storage.ts
Normal file
@@ -0,0 +1,207 @@
|
||||
/**
|
||||
* 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: '@adan/auth_token',
|
||||
CONDUCTOR: '@adan/conductor',
|
||||
DISPOSITIVO: '@adan/dispositivo',
|
||||
UBICACIONES_OFFLINE: '@adan/ubicaciones_offline',
|
||||
VIAJE_ACTIVO: '@adan/viaje_activo',
|
||||
CONFIGURACION: '@adan/configuracion',
|
||||
ULTIMO_SYNC: '@adan/ultimo_sync',
|
||||
MENSAJES_PENDIENTES: '@adan/mensajes_pendientes',
|
||||
PARADAS_PENDIENTES: '@adan/paradas_pendientes',
|
||||
COMBUSTIBLE_PENDIENTE: '@adan/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 adanKeys = keys.filter((key) => key.startsWith('@adan/'));
|
||||
await AsyncStorage.multiRemove(adanKeys);
|
||||
} 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 adanKeys = keys.filter((key) => key.startsWith('@adan/'));
|
||||
const pairs = await AsyncStorage.multiGet(adanKeys);
|
||||
|
||||
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;
|
||||
Reference in New Issue
Block a user