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 (
컨셉 포토
{album?.title}
{photos.length}장의 사진
멤버
{currentPhoto.members}
컨셉
{currentPhoto.concept}