diff --git a/backend/src/services/schedule.js b/backend/src/services/schedule.js index 43dabb3..5dfbd61 100644 --- a/backend/src/services/schedule.js +++ b/backend/src/services/schedule.js @@ -242,13 +242,19 @@ export async function getScheduleDetail(db, id, getXProfile = null) { }; // 카테고리별 추가 필드 - if (s.category_id === CATEGORY_IDS.YOUTUBE && s.youtube_video_id) { - result.videoId = s.youtube_video_id; - result.videoType = s.youtube_video_type; - result.channelName = s.youtube_channel; - result.videoUrl = s.youtube_video_type === 'shorts' - ? `https://www.youtube.com/shorts/${s.youtube_video_id}` - : `https://www.youtube.com/watch?v=${s.youtube_video_id}`; + if (s.category_id === CATEGORY_IDS.YOUTUBE) { + // 채널 이름은 항상 반환 (예정 일정 포함) + if (s.youtube_channel) { + result.channelName = s.youtube_channel; + } + // video_id가 있는 경우에만 영상 관련 필드 추가 + if (s.youtube_video_id) { + result.videoId = s.youtube_video_id; + result.videoType = s.youtube_video_type; + result.videoUrl = s.youtube_video_type === 'shorts' + ? `https://www.youtube.com/shorts/${s.youtube_video_id}` + : `https://www.youtube.com/watch?v=${s.youtube_video_id}`; + } } else if (s.category_id === CATEGORY_IDS.X && s.x_post_id) { const username = config.x.defaultUsername; result.postId = s.x_post_id; diff --git a/frontend/src/pages/pc/public/schedule/sections/YoutubeSection.jsx b/frontend/src/pages/pc/public/schedule/sections/YoutubeSection.jsx index 2cd8846..4247f5d 100644 --- a/frontend/src/pages/pc/public/schedule/sections/YoutubeSection.jsx +++ b/frontend/src/pages/pc/public/schedule/sections/YoutubeSection.jsx @@ -1,23 +1,32 @@ import { motion } from 'framer-motion'; -import { Calendar, Link2 } from 'lucide-react'; +import { Calendar, Link2, Clock } from 'lucide-react'; import { decodeHtmlEntities, formatXDateTimeWithTime } from './utils'; /** * 영상 정보 컴포넌트 (공통) */ -function VideoInfo({ schedule, isShorts }) { +function VideoInfo({ schedule, isShorts, isScheduled = false }) { const members = schedule.members || []; const isFullGroup = members.length === 5; + // 채널명: channelName 또는 source.name에서 가져옴 + const channelName = schedule.channelName || schedule.source?.name; return (
{/* 제목 */} -

- {decodeHtmlEntities(schedule.title)} -

+
+

+ {decodeHtmlEntities(schedule.title)} +

+ {isScheduled && ( + + 예정 + + )} +
{/* 메타 정보 */} -
+
{/* 날짜/시간 */}
@@ -25,12 +34,12 @@ function VideoInfo({ schedule, isShorts }) {
{/* 채널명 */} - {schedule.channelName && ( + {channelName && ( <>
- {schedule.channelName} + {channelName}
)} @@ -51,19 +60,55 @@ function VideoInfo({ schedule, isShorts }) {
)} - {/* 유튜브에서 보기 버튼 */} -
- - + {/* 유튜브에서 보기 버튼 (예정 일정이 아닐 때만) */} + {!isScheduled && ( +
+ + + + + YouTube에서 보기 + +
+ )} +
+ ); +} + +/** + * 예정 일정 Placeholder 컴포넌트 + */ +function ScheduledPlaceholder() { + return ( +
+ {/* 배경 패턴 */} +
+
+
+ + {/* 유튜브 아이콘 */} +
+
+ - YouTube에서 보기 - +
+
+ + {/* 텍스트 */} +
+
+ + 영상 준비 중 +
+

곧 업로드될 예정입니다

); @@ -75,8 +120,29 @@ function VideoInfo({ schedule, isShorts }) { function YoutubeSection({ schedule }) { const videoId = schedule.videoId; const isShorts = schedule.videoType === 'shorts'; + const isScheduled = !videoId; // videoId가 없으면 예정 일정 - if (!videoId) return null; + // 예정 일정: 세로 레이아웃 (Placeholder + 정보) + if (isScheduled) { + return ( +
+ {/* 예정 Placeholder */} + + + + + {/* 영상 정보 카드 */} + + + +
+ ); + } // 숏츠: 가로 레이아웃 (영상 + 정보) if (isShorts) {