/** * State Persistence Utilities * FE-STATE-001: Utilities for managing state persistence in Zustand stores * * Provides helpers for consistent state persistence configuration */ import { StateStorage } from 'zustand/middleware'; /** * Custom storage implementation with error handling */ export const createPersistentStorage = (name: string): StateStorage => { return { getItem: (key: string): string | null => { try { if (typeof window === 'undefined') { return null; } return localStorage.getItem(key); } catch (error) { console.warn(`[StatePersistence] Failed to get item ${key} from localStorage:`, error); return null; } }, setItem: (key: string, value: string): void => { try { if (typeof window === 'undefined') { return; } localStorage.setItem(key, value); } catch (error) { console.warn(`[StatePersistence] Failed to set item ${key} in localStorage:`, error); // Handle quota exceeded error if (error instanceof DOMException && error.name === 'QuotaExceededError') { console.error('[StatePersistence] localStorage quota exceeded. Clearing old data...'); // Optionally clear old data or notify user } } }, removeItem: (key: string): void => { try { if (typeof window === 'undefined') { return; } localStorage.removeItem(key); } catch (error) { console.warn(`[StatePersistence] Failed to remove item ${key} from localStorage:`, error); } }, }; }; /** * Clear all persisted state for a specific store */ export const clearPersistedState = (storeName: string): void => { try { if (typeof window === 'undefined') { return; } localStorage.removeItem(storeName); } catch (error) { console.warn(`[StatePersistence] Failed to clear persisted state for ${storeName}:`, error); } }; /** * Get persisted state for a specific store */ export const getPersistedState = (storeName: string): T | null => { try { if (typeof window === 'undefined') { return null; } const item = localStorage.getItem(storeName); if (!item) { return null; } return JSON.parse(item) as T; } catch (error) { console.warn(`[StatePersistence] Failed to get persisted state for ${storeName}:`, error); return null; } }; /** * Check if localStorage is available */ export const isLocalStorageAvailable = (): boolean => { try { if (typeof window === 'undefined') { return false; } const test = '__localStorage_test__'; localStorage.setItem(test, test); localStorage.removeItem(test); return true; } catch { return false; } }; /** * Get storage usage information */ export const getStorageInfo = (): { used: number; available: number; percentage: number; } => { try { if (typeof window === 'undefined') { return { used: 0, available: 0, percentage: 0 }; } let used = 0; for (const key in localStorage) { if (localStorage.hasOwnProperty(key)) { used += localStorage[key].length + key.length; } } // Estimate available storage (typically 5-10MB) const available = 5 * 1024 * 1024; // 5MB estimate const percentage = (used / available) * 100; return { used, available, percentage: Math.min(percentage, 100), }; } catch { return { used: 0, available: 0, percentage: 0 }; } };