import { useState, useEffect, useCallback, useRef } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { X, Download, ChevronRight, Info, Users, Tag } from 'lucide-react'; import { motion, AnimatePresence } from 'framer-motion'; import { Swiper, SwiperSlide } from 'swiper/react'; import { Virtual } from 'swiper/modules'; import 'swiper/css'; import { getAlbumByName } from '../../../api/public/albums'; import LightboxIndicator from '../../../components/common/LightboxIndicator'; // 모바일 앨범 갤러리 페이지 function MobileAlbumGallery() { const { name } = useParams(); const navigate = useNavigate(); const [album, setAlbum] = useState(null); const [photos, setPhotos] = useState([]); const [loading, setLoading] = useState(true); const [selectedIndex, setSelectedIndex] = useState(null); const [showInfo, setShowInfo] = useState(false); const swiperRef = useRef(null); useEffect(() => { getAlbumByName(name) .then(data => { setAlbum(data); const allPhotos = []; if (data.conceptPhotos && typeof data.conceptPhotos === 'object') { Object.entries(data.conceptPhotos).forEach(([concept, photos]) => { photos.forEach(p => allPhotos.push({ ...p, concept: concept !== 'Default' ? concept : null })); }); } setPhotos(allPhotos); setLoading(false); }) .catch(error => { console.error('앨범 데이터 로드 오류:', error); setLoading(false); }); }, [name]); // 라이트박스 열기 - 히스토리 추가 const openLightbox = useCallback((index) => { setSelectedIndex(index); window.history.pushState({ lightbox: true }, ''); }, []); // 라이트박스 닫기 const closeLightbox = useCallback(() => { setSelectedIndex(null); setShowInfo(false); }, []); // 정보 시트 열기 - 히스토리 추가 const openInfo = useCallback(() => { setShowInfo(true); window.history.pushState({ infoSheet: true }, ''); }, []); // 정보 시트 닫기 const closeInfo = useCallback(() => { setShowInfo(false); }, []); // 뒤로가기 처리 useEffect(() => { const handlePopState = (e) => { if (showInfo) { setShowInfo(false); } else if (selectedIndex !== null) { setSelectedIndex(null); } }; window.addEventListener('popstate', handlePopState); return () => window.removeEventListener('popstate', handlePopState); }, [showInfo, selectedIndex]); // 이미지 다운로드 const downloadImage = useCallback(async () => { const photo = photos[selectedIndex]; if (!photo) return; try { const response = await fetch(photo.original_url); const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = `fromis9_${album?.title || 'photo'}_${String(selectedIndex + 1).padStart(2, '0')}.webp`; document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(url); } catch (error) { console.error('다운로드 오류:', error); } }, [photos, selectedIndex, album?.title]); // 바디 스크롤 방지 useEffect(() => { if (selectedIndex !== null) { document.body.style.overflow = 'hidden'; } else { document.body.style.overflow = ''; } return () => { document.body.style.overflow = ''; }; }, [selectedIndex]); // 사진을 2열 지그재그로 분배 const distributePhotos = () => { const leftColumn = []; const rightColumn = []; photos.forEach((photo, index) => { if (index % 2 === 0) { leftColumn.push({ ...photo, originalIndex: index }); } else { rightColumn.push({ ...photo, originalIndex: index }); } }); return { leftColumn, rightColumn }; }; const { leftColumn, rightColumn } = distributePhotos(); // 현재 사진 정보 const currentPhoto = selectedIndex !== null ? photos[selectedIndex] : null; const hasInfo = currentPhoto?.concept || currentPhoto?.members; // 정보 시트 드래그 핸들러 const handleInfoDragEnd = (_, info) => { if (info.offset.y > 100 || info.velocity.y > 300) { window.history.back(); } }; if (loading) { return (
); } return ( <>
{/* 앨범 헤더 카드 */}
navigate(-1)} > {album?.cover_thumb_url && ( {album.title} )}

컨셉 포토

{album?.title}

{photos.length}장의 사진

{/* 2열 그리드 */}
{leftColumn.map((photo) => ( openLightbox(photo.originalIndex)} className="cursor-pointer overflow-hidden rounded-xl bg-gray-100" > ))}
{rightColumn.map((photo) => ( openLightbox(photo.originalIndex)} className="cursor-pointer overflow-hidden rounded-xl bg-gray-100" > ))}
{/* 풀스크린 라이트박스 */} {selectedIndex !== null && ( {/* 상단 헤더 - 3등분 */}
{selectedIndex + 1} / {photos.length}
{hasInfo && ( )}
{/* Swiper */} { swiperRef.current = swiper; }} onSlideChange={(swiper) => setSelectedIndex(swiper.activeIndex)} className="w-full h-full" spaceBetween={0} slidesPerView={1} resistance={true} resistanceRatio={0.5} > {photos.map((photo, index) => (
))}
{/* 모바일용 인디케이터 (좁은 width) */} swiperRef.current?.slideTo(i)} width={120} /> {/* 정보 바텀시트 */} {showInfo && hasInfo && ( window.history.back()} > e.stopPropagation()} > {/* 드래그 핸들 */}
{/* 정보 내용 */}

사진 정보

{currentPhoto?.members && (

멤버

{currentPhoto.members}

)} {currentPhoto?.concept && (

컨셉

{currentPhoto.concept}

)}
)} )} ); } export default MobileAlbumGallery;