import type { AvatarData, TryOnHistoryItem } from './types'; const STORAGE_PREFIX = 'aisthetix'; const AVATAR_KEY = `${STORAGE_PREFIX}-avatar`; const HISTORY_KEY = `${STORAGE_PREFIX}-history`; const VISITOR_ID_KEY = `${STORAGE_PREFIX}-visitor-id`; const MAX_HISTORY_ITEMS = 10; // Avatar Storage export function getAvatar(): AvatarData | null { try { const data = localStorage.getItem(AVATAR_KEY); if (data) { return JSON.parse(data); } } catch (e) { console.error('Error reading avatar from storage:', e); } return null; } export function saveAvatar(imageData: string): void { try { const avatar: AvatarData = { imageData, createdAt: new Date().toISOString(), }; const serialized = JSON.stringify(avatar); // Estimate size (roughly 3/4 of base64 string size due to encoding overhead) const sizeInBytes = serialized.length * 2; // UTF-16 encoding const maxSize = 5 * 1024 * 1024; // 5MB limit if (sizeInBytes > maxSize) { throw new Error('Image too large to store locally (exceeds 5MB limit)'); } try { localStorage.setItem(AVATAR_KEY, serialized); } catch (storageError) { if (storageError instanceof Error && storageError.name === 'QuotaExceededError') { throw new Error('Storage quota exceeded. Please clear browser cache or try a smaller image.'); } throw storageError; } } catch (e) { console.error('Error saving avatar to storage:', e); // Re-throw with user-friendly message if (e instanceof Error) { throw e; } throw new Error('Failed to save avatar'); } } export function clearAvatar(): void { try { localStorage.removeItem(AVATAR_KEY); } catch (e) { console.error('Error clearing avatar from storage:', e); } } // History Storage export function getHistory(): TryOnHistoryItem[] { try { const data = localStorage.getItem(HISTORY_KEY); if (data) { return JSON.parse(data); } } catch (e) { console.error('Error reading history from storage:', e); } return []; } export function addToHistory(item: Omit): void { try { const history = getHistory(); const newItem: TryOnHistoryItem = { ...item, id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, }; // Add to beginning, limit to max items history.unshift(newItem); if (history.length > MAX_HISTORY_ITEMS) { history.pop(); } localStorage.setItem(HISTORY_KEY, JSON.stringify(history)); } catch (e) { console.error('Error adding to history:', e); } } export function clearHistory(): void { try { localStorage.removeItem(HISTORY_KEY); } catch (e) { console.error('Error clearing history:', e); } } // Visitor ID for per-user rate limiting export function getVisitorId(): string { try { let visitorId = localStorage.getItem(VISITOR_ID_KEY); if (!visitorId) { visitorId = `anon_${crypto.randomUUID()}`; localStorage.setItem(VISITOR_ID_KEY, visitorId); } return visitorId; } catch { // If localStorage unavailable, generate ephemeral ID (resets on page reload) return `anon_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } } // Consent Storage — asked once per visitor before an AI try-on is generated const CONSENT_KEY = 'aisthetix_tryon_consent'; export function hasConsent(): boolean { try { return localStorage.getItem(CONSENT_KEY) === '1'; } catch { return false; } } export function setConsent(): void { try { localStorage.setItem(CONSENT_KEY, '1'); } catch { // If localStorage is unavailable, consent will simply be re-requested next visit. } } // Check if localStorage is available export function isStorageAvailable(): boolean { try { const test = '__storage_test__'; localStorage.setItem(test, test); localStorage.removeItem(test); return true; } catch (e) { return false; } }