import { useEffect, useRef } from 'react'; import { useLayerStore } from '@/store'; import { toast } from '@/lib/toast-utils'; const AUTO_SAVE_KEY = 'paint-ui-autosave'; const AUTO_SAVE_INTERVAL = 30000; // 30 seconds interface AutoSaveData { timestamp: number; layers: any[]; } /** * Auto-save hook - saves project to localStorage periodically */ export function useAutoSave() { const { layers } = useLayerStore(); const lastSaveRef = useRef(0); const saveTimeoutRef = useRef(null); // Save project to localStorage const saveProject = () => { try { const saveData: AutoSaveData = { timestamp: Date.now(), layers: layers.map((layer) => ({ ...layer, canvas: layer.canvas ? layer.canvas.toDataURL() : null, mask: layer.mask?.canvas ? { ...layer.mask, canvas: layer.mask.canvas.toDataURL(), } : null, })), }; localStorage.setItem(AUTO_SAVE_KEY, JSON.stringify(saveData)); lastSaveRef.current = Date.now(); } catch (error) { console.error('Auto-save failed:', error); } }; // Auto-save on interval useEffect(() => { if (layers.length === 0) return; // Clear existing timeout if (saveTimeoutRef.current) { clearTimeout(saveTimeoutRef.current); } // Schedule next save saveTimeoutRef.current = setTimeout(() => { saveProject(); }, AUTO_SAVE_INTERVAL); return () => { if (saveTimeoutRef.current) { clearTimeout(saveTimeoutRef.current); } }; }, [layers]); return { saveProject, lastSave: lastSaveRef.current, }; } /** * Check if auto-saved project exists */ export function hasAutoSave(): boolean { if (typeof window === 'undefined') return false; return localStorage.getItem(AUTO_SAVE_KEY) !== null; } /** * Load auto-saved project */ export async function loadAutoSave(): Promise { try { const saved = localStorage.getItem(AUTO_SAVE_KEY); if (!saved) return false; const data: AutoSaveData = JSON.parse(saved); const { clearLayers, createLayer } = useLayerStore.getState(); // Clear existing layers clearLayers(); // Restore layers for (const savedLayer of data.layers) { const layer = createLayer({ name: savedLayer.name, width: savedLayer.width, height: savedLayer.height, x: savedLayer.x, y: savedLayer.y, opacity: savedLayer.opacity, blendMode: savedLayer.blendMode, }); // Restore canvas if (savedLayer.canvas && layer.canvas) { const img = new Image(); await new Promise((resolve, reject) => { img.onload = resolve; img.onerror = reject; img.src = savedLayer.canvas; }); const ctx = layer.canvas.getContext('2d'); if (ctx) { ctx.drawImage(img, 0, 0); } } // Restore mask if (savedLayer.mask?.canvas) { const maskCanvas = document.createElement('canvas'); maskCanvas.width = savedLayer.width; maskCanvas.height = savedLayer.height; const maskImg = new Image(); await new Promise((resolve, reject) => { maskImg.onload = resolve; maskImg.onerror = reject; maskImg.src = savedLayer.mask.canvas; }); const maskCtx = maskCanvas.getContext('2d'); if (maskCtx) { maskCtx.drawImage(maskImg, 0, 0); } useLayerStore.getState().updateLayer(layer.id, { mask: { canvas: maskCanvas, enabled: savedLayer.mask.enabled, inverted: savedLayer.mask.inverted, }, }); } // Restore other properties useLayerStore.getState().updateLayer(layer.id, { visible: savedLayer.visible, locked: savedLayer.locked, order: savedLayer.order, }); } const date = new Date(data.timestamp); toast.success(`Auto-save restored from ${date.toLocaleTimeString()}`); return true; } catch (error) { console.error('Failed to load auto-save:', error); toast.error('Failed to restore auto-save'); return false; } } /** * Clear auto-save */ export function clearAutoSave(): void { if (typeof window !== 'undefined') { localStorage.removeItem(AUTO_SAVE_KEY); } } /** * Get auto-save timestamp */ export function getAutoSaveTime(): Date | null { if (typeof window === 'undefined') return null; const saved = localStorage.getItem(AUTO_SAVE_KEY); if (!saved) return null; try { const data: AutoSaveData = JSON.parse(saved); return new Date(data.timestamp); } catch { return null; } }