diff --git a/src/components/studio/GeneratePreviewStep.tsx b/src/components/studio/GeneratePreviewStep.tsx index aa89a2c..1ac9e60 100644 --- a/src/components/studio/GeneratePreviewStep.tsx +++ b/src/components/studio/GeneratePreviewStep.tsx @@ -3,6 +3,7 @@ import { motion } from 'motion/react'; import { VideoFilled, FileTextFilled } from '../icons/FilledIcons'; import { CHANNEL_OPTIONS, MUSIC_TRACKS, type StudioState, type GenerateOutputType } from '../../types/studio'; import { generateImage, type GenerateResult } from '../../services/geminiImageGen'; +import { generateVideo, type VideoResult } from '../../services/creatomateVideoGen'; interface Props { studioState: StudioState; @@ -15,6 +16,7 @@ type GenerateStatus = 'idle' | 'generating' | 'done' | 'error'; export default function GeneratePreviewStep({ studioState, outputType, onOutputTypeChange }: Props) { const [status, setStatus] = useState('idle'); const [result, setResult] = useState(null); + const [videoResult, setVideoResult] = useState(null); const [errorMsg, setErrorMsg] = useState(''); const downloadRef = useRef(null); @@ -37,24 +39,38 @@ export default function GeneratePreviewStep({ studioState, outputType, onOutputT setStatus('error'); } } else { - // Video: placeholder (Creatomate integration needed) - setTimeout(() => setStatus('done'), 4000); + try { + const res = await generateVideo(studioState); + setVideoResult(res); + setStatus('done'); + } catch (err) { + setErrorMsg(err instanceof Error ? err.message : '영상 생성에 실패했습니다'); + setStatus('error'); + } } }, [studioState, outputType]); const handleReset = useCallback(() => { setStatus('idle'); setResult(null); + setVideoResult(null); setErrorMsg(''); }, []); const handleDownload = useCallback(() => { - if (!result?.imageDataUrl || !downloadRef.current) return; + if (!downloadRef.current) return; const link = downloadRef.current; - link.href = result.imageDataUrl; - link.download = `INFINITH_${activeChannel?.label ?? 'content'}_${activeFormat?.key ?? 'image'}.png`; - link.click(); - }, [result, activeChannel, activeFormat]); + + if (result?.imageDataUrl) { + link.href = result.imageDataUrl; + link.download = `INFINITH_${activeChannel?.label ?? 'content'}_${activeFormat?.key ?? 'image'}.png`; + link.click(); + } else if (videoResult?.videoUrl) { + link.href = videoResult.videoUrl; + link.download = `INFINITH_${activeChannel?.label ?? 'content'}_${activeFormat?.key ?? 'video'}.mp4`; + link.click(); + } + }, [result, videoResult, activeChannel, activeFormat]); const aspectClass = activeFormat?.aspectRatio === '9:16' ? 'w-[240px] h-[426px]' : @@ -126,7 +142,7 @@ export default function GeneratePreviewStep({ studioState, outputType, onOutputT {status === 'done' && (
- {result?.imageDataUrl && ( + {(result?.imageDataUrl || videoResult?.videoUrl) && (