import { useState, useEffect, useCallback } from 'react'; /** * 라이트박스 상태 및 동작 관리 훅 * @param {Object} options * @param {Array<{url: string, thumb_url?: string}|string>} options.images - 이미지 배열 * @param {Function} options.onClose - 닫기 콜백 (optional) * @returns {Object} 라이트박스 상태 및 메서드 */ export function useLightbox({ images = [], onClose } = {}) { const [isOpen, setIsOpen] = useState(false); const [currentIndex, setCurrentIndex] = useState(0); // 라이트박스 열기 const open = useCallback((index = 0) => { setCurrentIndex(index); setIsOpen(true); window.history.pushState({ lightbox: true }, ''); }, []); // 라이트박스 닫기 const close = useCallback(() => { setIsOpen(false); onClose?.(); }, [onClose]); // 이전 이미지 const goToPrev = useCallback(() => { if (images.length <= 1) return; setCurrentIndex((prev) => (prev > 0 ? prev - 1 : images.length - 1)); }, [images.length]); // 다음 이미지 const goToNext = useCallback(() => { if (images.length <= 1) return; setCurrentIndex((prev) => (prev < images.length - 1 ? prev + 1 : 0)); }, [images.length]); // 특정 인덱스로 이동 const goToIndex = useCallback( (index) => { if (index >= 0 && index < images.length) { setCurrentIndex(index); } }, [images.length] ); // 뒤로가기 처리 useEffect(() => { if (!isOpen) return; const handlePopState = () => { close(); }; window.addEventListener('popstate', handlePopState); return () => window.removeEventListener('popstate', handlePopState); }, [isOpen, close]); // body 스크롤 방지 (Lightbox 컴포넌트에서 처리하므로 여기선 생략) // 이미지 프리로딩 useEffect(() => { if (!isOpen || images.length === 0) return; // 현재, 이전, 다음 이미지 프리로드 const indicesToPreload = [ currentIndex, (currentIndex + 1) % images.length, (currentIndex - 1 + images.length) % images.length, ]; indicesToPreload.forEach((index) => { const img = new Image(); const imageItem = images[index]; img.src = typeof imageItem === 'string' ? imageItem : imageItem?.url || imageItem; }); }, [isOpen, currentIndex, images]); // 이미지 다운로드 const downloadImage = useCallback(async () => { const imageItem = images[currentIndex]; const imageUrl = typeof imageItem === 'string' ? imageItem : imageItem?.url || imageItem; if (!imageUrl) return; try { const response = await fetch(imageUrl); const blob = await response.blob(); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = `image_${currentIndex + 1}.jpg`; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); } catch (error) { console.error('이미지 다운로드 실패:', error); } }, [images, currentIndex]); // 현재 이미지 URL 가져오기 const getCurrentImageUrl = useCallback(() => { const imageItem = images[currentIndex]; return typeof imageItem === 'string' ? imageItem : imageItem?.url || imageItem; }, [images, currentIndex]); return { isOpen, currentIndex, currentImage: images[currentIndex], currentImageUrl: getCurrentImageUrl(), totalCount: images.length, open, close, goToPrev, goToNext, goToIndex, downloadImage, setCurrentIndex, }; } export default useLightbox;