import { useParams, Link } from 'react-router-dom'; import { useQuery, keepPreviousData } from '@tanstack/react-query'; import { useEffect, useState, useRef } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { Calendar, Clock, ChevronLeft, Link2, X, ChevronRight } from 'lucide-react'; import Linkify from 'react-linkify'; import { getSchedule } from '@/api'; import { decodeHtmlEntities, formatFullDate, formatTime, formatXDateTimeWithTime } from '@/utils'; import Birthday from './Birthday'; /** * 특수 일정 ID 파싱 * @param {string} id - 일정 ID * @returns {object|null} { type, year, nameEn } 또는 null */ function parseSpecialId(id) { // birthday-{year}-{nameEn} 형식 const birthdayMatch = id.match(/^birthday-(\d{4})-(.+)$/); if (birthdayMatch) { return { type: 'birthday', year: birthdayMatch[1], nameEn: birthdayMatch[2] }; } // debut-{year} 형식 const debutMatch = id.match(/^debut-(\d{4})$/); if (debutMatch) { return { type: 'debut', year: debutMatch[1] }; } // anniversary-{year} 형식 const anniversaryMatch = id.match(/^anniversary-(\d{4})$/); if (anniversaryMatch) { return { type: 'anniversary', year: anniversaryMatch[1] }; } return null; } /** * 전체화면 시 자동 가로 회전 훅 (숏츠가 아닐 때만) */ function useFullscreenOrientation(isShorts) { useEffect(() => { if (isShorts) return; const handleFullscreenChange = async () => { const isFullscreen = !!document.fullscreenElement; if (isFullscreen) { try { if (screen.orientation && screen.orientation.lock) { await screen.orientation.lock('landscape'); } } catch (e) { // 지원하지 않는 브라우저 } } else { try { if (screen.orientation && screen.orientation.unlock) { screen.orientation.unlock(); } } catch (e) { // 무시 } } }; document.addEventListener('fullscreenchange', handleFullscreenChange); document.addEventListener('webkitfullscreenchange', handleFullscreenChange); return () => { document.removeEventListener('fullscreenchange', handleFullscreenChange); document.removeEventListener('webkitfullscreenchange', handleFullscreenChange); }; }, [isShorts]); } /** * Mobile 유튜브 섹션 */ function MobileYoutubeSection({ schedule }) { const videoId = schedule.videoId; const isShorts = schedule.videoType === 'shorts'; // 숏츠가 아닐 때만 가로 회전 (숏츠는 전체화면에서 세로 유지) useFullscreenOrientation(isShorts); const members = schedule.members || []; const isFullGroup = members.length === 5; if (!videoId) return null; return (
{/* 영상 임베드 - 숏츠도 가로 비율로 표시 (전체화면에서는 유튜브가 세로로 처리) */}