// ─── 스튜디오 위저드 상태 관리 훅 ─────────────────────────────────────────── // DEMO/src/components/studio/StudioWizard.tsx 의 상태 로직에서 이전 // TODO: Phase 2 — Zustand store 로 전환 import { useState } from "react"; import type { StudioState, StudioChannel, ContentFormat, ContentPillarId, AssetSourceType, SoundSettings, GenerateOutputType } from "@/features/studio/types/studio"; import { getStepsForChannel } from "@/features/studio/config/studioSteps"; const DEFAULT_SOUND: SoundSettings = { genre: 'calm', trackId: null, narrationEnabled: false, narrationLanguage: 'ko', narrationVoice: 'female', subtitleEnabled: true, }; const INITIAL_STATE: StudioState = { channel: null, format: null, pillarId: null, assetSources: [], sound: DEFAULT_SOUND, outputType: 'video', }; export function useStudioWizard() { const [state, setState] = useState(INITIAL_STATE); const [currentStepIndex, setCurrentStepIndex] = useState(0); const steps = getStepsForChannel(state.channel); const currentStep = steps[currentStepIndex]; const isFirstStep = currentStepIndex === 0; const isLastStep = currentStepIndex === steps.length - 1; // ── 스텝별 진행 가능 여부 ───────────────────────────────────────────────── // TODO: 각 스텝 구현 후 세부 유효성 검사 추가 function canProceed(): boolean { switch (currentStep.key) { case 'channel-format': return state.channel !== null && state.format !== null; case 'strategy-source': return state.pillarId !== null && state.assetSources.length > 0; case 'sound': return true; case 'generate': return true; case 'blog-editor': return true; default: return false; } } // ── 스텝 이동 ───────────────────────────────────────────────────────────── function goNext() { if (!isLastStep && canProceed()) setCurrentStepIndex((i) => i + 1); } function goPrev() { if (!isFirstStep) setCurrentStepIndex((i) => i - 1); } function goToStep(index: number) { if (index < currentStepIndex) setCurrentStepIndex(index); } // ── 상태 업데이트 핸들러 ────────────────────────────────────────────────── function setChannel(channel: StudioChannel) { // 채널 변경 시 format 초기화 + blog 채널은 outputType을 image로 고정 setState((prev) => ({ ...prev, channel, format: null, outputType: channel === 'naver_blog' ? 'image' : 'video', })); setCurrentStepIndex(0); } function setFormat(format: ContentFormat) { setState((prev) => ({ ...prev, format })); } function setPillar(pillarId: ContentPillarId) { setState((prev) => ({ ...prev, pillarId })); } function toggleAssetSource(source: AssetSourceType) { setState((prev) => { const exists = prev.assetSources.includes(source); return { ...prev, assetSources: exists ? prev.assetSources.filter((s) => s !== source) : [...prev.assetSources, source], }; }); } function setSound(sound: Partial) { setState((prev) => ({ ...prev, sound: { ...prev.sound, ...sound } })); } function setOutputType(outputType: GenerateOutputType) { setState((prev) => ({ ...prev, outputType })); } return { state, steps, currentStep, currentStepIndex, isFirstStep, isLastStep, canProceed, goNext, goPrev, goToStep, setChannel, setFormat, setPillar, toggleAssetSource, setSound, setOutputType, }; }