/** * YouTube 봇 추가/수정 다이얼로그 */ import { useState, useEffect, useRef } from 'react'; import { createPortal } from 'react-dom'; import { motion, AnimatePresence } from 'framer-motion'; import { Youtube, Search, X, ChevronDown, ChevronUp, Clock } from 'lucide-react'; // 동기화 간격 옵션 const INTERVAL_OPTIONS = [ { value: 1, label: '1분' }, { value: 2, label: '2분' }, { value: 5, label: '5분' }, { value: 10, label: '10분' }, { value: 30, label: '30분' }, { value: 60, label: '1시간' }, ]; // 요일 옵션 const DAY_OPTIONS = [ { value: 0, label: '일요일' }, { value: 1, label: '월요일' }, { value: 2, label: '화요일' }, { value: 3, label: '수요일' }, { value: 4, label: '목요일' }, { value: 5, label: '금요일' }, { value: 6, label: '토요일' }, ]; // 시간 옵션 (00:00 ~ 23:00) const TIME_OPTIONS = Array.from({ length: 24 }, (_, i) => ({ value: `${String(i).padStart(2, '0')}:00`, label: `${String(i).padStart(2, '0')}:00`, })); /** * 커스텀 드롭다운 컴포넌트 */ function Dropdown({ value, options, onChange, placeholder = '선택', className = '' }) { const [isOpen, setIsOpen] = useState(false); const dropdownRef = useRef(null); useEffect(() => { const handleClickOutside = (event) => { if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { setIsOpen(false); } }; if (isOpen) { document.addEventListener('mousedown', handleClickOutside); } return () => document.removeEventListener('mousedown', handleClickOutside); }, [isOpen]); const selectedOption = options.find((opt) => opt.value === value); return (
{isOpen && ( {options.map((opt) => ( ))} )}
); } function YouTubeBotDialog({ isOpen, onClose, bot = null, onSubmit }) { const isEdit = !!bot; // 폼 상태 const [handle, setHandle] = useState(''); const [channelInfo, setChannelInfo] = useState(null); const [lookupLoading, setLookupLoading] = useState(false); const [interval, setInterval] = useState(2); // 예정 일정 설정 const [autoScheduleEnabled, setAutoScheduleEnabled] = useState(false); const [scheduleDayOfWeek, setScheduleDayOfWeek] = useState(4); const [scheduleTime, setScheduleTime] = useState('18:00'); const [titleTemplate, setTitleTemplate] = useState('{channelName} {episode}화'); const [deadlineDayOfWeek, setDeadlineDayOfWeek] = useState(5); // 고급 설정 const [showAdvanced, setShowAdvanced] = useState(false); const [titleFilter, setTitleFilter] = useState(''); const [extractMembers, setExtractMembers] = useState(false); // 수정 모드일 때 기존 데이터 로드 useEffect(() => { if (bot) { setHandle(bot.channel_handle || ''); setChannelInfo({ channelId: bot.channel_id, title: bot.channel_name, }); setInterval(bot.cron_interval || 2); if (bot.auto_schedule_config) { const config = typeof bot.auto_schedule_config === 'string' ? JSON.parse(bot.auto_schedule_config) : bot.auto_schedule_config; setAutoScheduleEnabled(true); setScheduleDayOfWeek(config.dayOfWeek ?? 4); setScheduleTime(config.time?.slice(0, 5) || '18:00'); setTitleTemplate(config.titleTemplate || '{channelName} {episode}화'); setDeadlineDayOfWeek(config.deadlineDayOfWeek ?? 5); } setTitleFilter(bot.title_filter || ''); setExtractMembers(bot.extract_members_from_desc || false); } }, [bot]); // 다이얼로그 닫힐 때 초기화 useEffect(() => { if (!isOpen) { setHandle(''); setChannelInfo(null); setInterval(2); setAutoScheduleEnabled(false); setScheduleDayOfWeek(4); setScheduleTime('18:00'); setTitleTemplate('{channelName} {episode}화'); setDeadlineDayOfWeek(5); setShowAdvanced(false); setTitleFilter(''); setExtractMembers(false); } }, [isOpen]); // 채널 조회 const handleLookup = async () => { if (!handle.trim()) return; setLookupLoading(true); // TODO: API 호출 setTimeout(() => { setChannelInfo({ channelId: 'UC_EXAMPLE_ID', title: '예시 채널명', thumbnailUrl: null, }); setLookupLoading(false); }, 1000); }; // 제출 const handleSubmit = (e) => { e.preventDefault(); // TODO: onSubmit 호출 onClose(); }; return createPortal( {isOpen && ( e.stopPropagation()} > {/* 헤더 */}

{isEdit ? 'YouTube 봇 수정' : 'YouTube 봇 추가'}

{/* 본문 */}
{/* 채널 핸들 */}
@ setHandle(e.target.value)} placeholder="studiofromis_9" disabled={isEdit} className="w-full pl-8 pr-4 py-2.5 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-red-500/20 focus:border-red-500 disabled:bg-gray-50 disabled:text-gray-500" />
{!isEdit && ( )}
{/* 채널 정보 표시 */} {channelInfo && (

{channelInfo.title}

{channelInfo.channelId}

)}
{/* 동기화 간격 */}
{/* 예정 일정 자동 생성 */}
setAutoScheduleEnabled(!autoScheduleEnabled)} >

예정 일정 자동 생성

매주 특정 요일에 임시 일정을 미리 생성합니다

{autoScheduleEnabled && (
{/* 요일 & 시간 */}
{/* 제목 템플릿 */}
setTitleTemplate(e.target.value)} placeholder="{channelName} {episode}화" className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-red-500/20 focus:border-red-500" />

{'{channelName}'}: 채널명, {'{episode}'}: 회차 번호

{/* 마감 요일 */}

이 요일까지 영상이 없으면 예정 일정을 삭제합니다

)}
{/* 고급 설정 */}
{showAdvanced && (
{/* 제목 필터 */}
setTitleFilter(e.target.value)} placeholder="특정 키워드가 포함된 영상만 추가" className="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-red-500/20 focus:border-red-500" />
{/* 멤버 추출 */}
setExtractMembers(!extractMembers)} >

설명에서 멤버 추출

영상 설명에서 멤버 이름을 찾아 자동 연결

)}
{/* 푸터 */}
)} , document.body ); } export default YouTubeBotDialog;