import AsyncStorage from '@react-native-async-storage/async-storage'; import { Product, Sale, Customer } from '../types'; const KEYS = { PRODUCTS: '@offline_products', PENDING_SALES: '@pending_sales', CUSTOMERS: '@offline_customers', LAST_SYNC: '@last_sync', OFFLINE_MODE: '@offline_mode', }; interface PendingSale { id: string; items: Array<{ productId: string; quantity: number; unitPrice: number }>; paymentMethod: string; customerId?: string; total: number; createdAt: string; synced: boolean; } class OfflineStorage { // Products async saveProducts(products: Product[]): Promise { await AsyncStorage.setItem(KEYS.PRODUCTS, JSON.stringify(products)); } async getProducts(): Promise { const data = await AsyncStorage.getItem(KEYS.PRODUCTS); return data ? JSON.parse(data) : []; } async getProductByBarcode(barcode: string): Promise { const products = await this.getProducts(); return products.find((p) => p.barcode === barcode) || null; } async updateProductStock(productId: string, quantitySold: number): Promise { const products = await this.getProducts(); const updatedProducts = products.map((p) => p.id === productId ? { ...p, stock: Math.max(0, p.stock - quantitySold) } : p ); await this.saveProducts(updatedProducts); } // Pending Sales (offline sales to sync later) async savePendingSale(sale: Omit): Promise { const pendingSales = await this.getPendingSales(); const newSale: PendingSale = { ...sale, id: `offline_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, createdAt: new Date().toISOString(), synced: false, }; pendingSales.push(newSale); await AsyncStorage.setItem(KEYS.PENDING_SALES, JSON.stringify(pendingSales)); // Update local stock for (const item of sale.items) { await this.updateProductStock(item.productId, item.quantity); } return newSale.id; } async getPendingSales(): Promise { const data = await AsyncStorage.getItem(KEYS.PENDING_SALES); return data ? JSON.parse(data) : []; } async getUnsyncedSales(): Promise { const sales = await this.getPendingSales(); return sales.filter((s) => !s.synced); } async markSaleAsSynced(saleId: string): Promise { const sales = await this.getPendingSales(); const updatedSales = sales.map((s) => s.id === saleId ? { ...s, synced: true } : s ); await AsyncStorage.setItem(KEYS.PENDING_SALES, JSON.stringify(updatedSales)); } async removeSyncedSales(): Promise { const sales = await this.getPendingSales(); const unsyncedSales = sales.filter((s) => !s.synced); await AsyncStorage.setItem(KEYS.PENDING_SALES, JSON.stringify(unsyncedSales)); } // Customers async saveCustomers(customers: Customer[]): Promise { await AsyncStorage.setItem(KEYS.CUSTOMERS, JSON.stringify(customers)); } async getCustomers(): Promise { const data = await AsyncStorage.getItem(KEYS.CUSTOMERS); return data ? JSON.parse(data) : []; } // Sync metadata async setLastSync(timestamp: string): Promise { await AsyncStorage.setItem(KEYS.LAST_SYNC, timestamp); } async getLastSync(): Promise { return AsyncStorage.getItem(KEYS.LAST_SYNC); } // Offline mode async setOfflineMode(enabled: boolean): Promise { await AsyncStorage.setItem(KEYS.OFFLINE_MODE, JSON.stringify(enabled)); } async isOfflineMode(): Promise { const data = await AsyncStorage.getItem(KEYS.OFFLINE_MODE); return data ? JSON.parse(data) : false; } // Clear all offline data async clearAll(): Promise { await AsyncStorage.multiRemove([ KEYS.PRODUCTS, KEYS.PENDING_SALES, KEYS.CUSTOMERS, KEYS.LAST_SYNC, ]); } // Get offline stats async getOfflineStats(): Promise<{ productCount: number; pendingSalesCount: number; pendingSalesTotal: number; lastSync: string | null; }> { const [products, pendingSales, lastSync] = await Promise.all([ this.getProducts(), this.getUnsyncedSales(), this.getLastSync(), ]); return { productCount: products.length, pendingSalesCount: pendingSales.length, pendingSalesTotal: pendingSales.reduce((sum, s) => sum + s.total, 0), lastSync, }; } } export const offlineStorage = new OfflineStorage(); export default offlineStorage;