diff --git a/frontend/src/pages/pc/public/ScheduleDetail.jsx b/frontend/src/pages/pc/public/ScheduleDetail.jsx index 298085d..b530f1e 100644 --- a/frontend/src/pages/pc/public/ScheduleDetail.jsx +++ b/frontend/src/pages/pc/public/ScheduleDetail.jsx @@ -1,854 +1,23 @@ import { useParams, Link } from 'react-router-dom'; import { useQuery, keepPreviousData } from '@tanstack/react-query'; -import { useEffect, useRef, useState } from 'react'; -import { motion, AnimatePresence } from 'framer-motion'; -import { Clock, Calendar, ExternalLink, ChevronRight, ChevronDown, ChevronLeft, Check, Link2, MapPin, Navigation } from 'lucide-react'; -import { getSchedule, getXProfile } from '../../../api/public/schedules'; - -// 카카오맵 SDK 키 -const KAKAO_MAP_KEY = import.meta.env.VITE_KAKAO_JS_KEY; - -// 카테고리 ID 상수 -const CATEGORY_ID = { - YOUTUBE: 2, - X: 3, - ALBUM: 4, - FANSIGN: 5, - CONCERT: 6, - TICKET: 7, -}; - -// HTML 엔티티 디코딩 함수 -const decodeHtmlEntities = (text) => { - if (!text) return ''; - const textarea = document.createElement('textarea'); - textarea.innerHTML = text; - return textarea.value; -}; - -// 유튜브 비디오 ID 추출 -const extractYoutubeVideoId = (url) => { - if (!url) return null; - const shortMatch = url.match(/youtu\.be\/([a-zA-Z0-9_-]{11})/); - if (shortMatch) return shortMatch[1]; - const watchMatch = url.match(/youtube\.com\/watch\?v=([a-zA-Z0-9_-]{11})/); - if (watchMatch) return watchMatch[1]; - const shortsMatch = url.match(/youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})/); - if (shortsMatch) return shortsMatch[1]; - return null; -}; - -// 날짜 포맷팅 -const formatFullDate = (dateStr) => { - if (!dateStr) return ''; - const date = new Date(dateStr); - const dayNames = ['일', '월', '화', '수', '목', '금', '토']; - return `${date.getFullYear()}. ${date.getMonth() + 1}. ${date.getDate()}. (${dayNames[date.getDay()]})`; -}; - -// 시간 포맷팅 -const formatTime = (timeStr) => { - if (!timeStr) return null; - return timeStr.slice(0, 5); -}; - -// X용 날짜/시간 포맷팅 (오후 2:30 · 2026년 1월 15일) -const formatXDateTime = (dateStr, timeStr) => { - if (!dateStr) return ''; - const date = new Date(dateStr); - const year = date.getFullYear(); - const month = date.getMonth() + 1; - const day = date.getDate(); - - let result = `${year}년 ${month}월 ${day}일`; - - if (timeStr) { - const [hours, minutes] = timeStr.split(':').map(Number); - const period = hours < 12 ? '오전' : '오후'; - const hour12 = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours; - result = `${period} ${hour12}:${String(minutes).padStart(2, '0')} · ${result}`; - } - - return result; -}; - -// 영상 정보 컴포넌트 (공통) -function VideoInfo({ schedule, isShorts }) { - const members = schedule.members || []; - const isFullGroup = members.length === 5; - - return ( -
- {/* 제목 */} -

- {decodeHtmlEntities(schedule.title)} -

- - {/* 메타 정보 */} -
- {/* 날짜 */} -
- - {formatFullDate(schedule.date)} -
- - {/* 시간 */} - {schedule.time && ( - <> -
-
- - {formatTime(schedule.time)} -
- - )} - - {/* 채널명 */} - {schedule.source_name && ( - <> -
-
- - {schedule.source_name} -
- - )} -
- - {/* 멤버 목록 */} - {members.length > 0 && ( -
- {isFullGroup ? ( - - 프로미스나인 - - ) : ( - members.map((member) => ( - - {member.name} - - )) - )} -
- )} - - {/* 유튜브에서 보기 버튼 */} -
- - - - - YouTube에서 보기 - -
-
- ); -} - -// 유튜브 섹션 컴포넌트 -function YoutubeSection({ schedule }) { - const videoId = extractYoutubeVideoId(schedule.source_url); - const isShorts = schedule.source_url?.includes('/shorts/'); - - if (!videoId) return null; - - // 숏츠: 가로 레이아웃 (영상 + 정보) - if (isShorts) { - return ( -
- {/* 영상 임베드 */} - -
-