/** * useStorageQuota Hook * * Monitors storage quota and usage for offline assets. */ import { useState, useEffect, useCallback } from 'react'; import { StorageManager } from '../lib/offline/StorageManager'; import { PRELOAD_CONFIG } from '../config/preload.config'; import type { StorageQuotaInfo } from '../types/offline'; interface UseStorageQuotaResult extends StorageQuotaInfo { isLoading: boolean; error: string | null; refresh: () => Promise; requestPersistence: () => Promise; isPersisted: boolean; isWarning: boolean; isCritical: boolean; formatSize: (bytes: number) => string; } /** * Format bytes to human-readable string */ const formatBytes = (bytes: number): string => { if (bytes === 0) return '0 B'; if (bytes === Infinity) return 'Unlimited'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`; }; export function useStorageQuota(): UseStorageQuotaResult { const [quotaInfo, setQuotaInfo] = useState({ usage: 0, quota: Infinity, percentUsed: 0, available: Infinity, canStore: () => true, }); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const [isPersisted, setIsPersisted] = useState(false); // Fetch quota info const refresh = useCallback(async () => { setIsLoading(true); setError(null); try { const info = await StorageManager.getStorageQuota(); setQuotaInfo(info); // Check persistence status if (typeof navigator !== 'undefined' && navigator.storage?.persisted) { const persisted = await navigator.storage.persisted(); setIsPersisted(persisted); } } catch (err) { setError( err instanceof Error ? err.message : 'Failed to get storage quota', ); } finally { setIsLoading(false); } }, []); // Request persistent storage const requestPersistence = useCallback(async (): Promise => { try { const granted = await StorageManager.requestPersistentStorage(); setIsPersisted(granted); return granted; } catch { return false; } }, []); // Initial fetch and periodic refresh useEffect(() => { refresh(); // Refresh every 30 seconds const interval = setInterval(refresh, 30000); return () => clearInterval(interval); }, [refresh]); // Computed values const isWarning = quotaInfo.percentUsed >= PRELOAD_CONFIG.storage.warningPercent; const isCritical = quotaInfo.percentUsed >= PRELOAD_CONFIG.storage.criticalPercent; return { ...quotaInfo, isLoading, error, refresh, requestPersistence, isPersisted, isWarning, isCritical, formatSize: formatBytes, }; }