fromis_9/frontend-temp/src/hooks/common/useLightbox.js

126 lines
3.6 KiB
JavaScript
Raw Normal View History

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;