import React from 'react'; import { useTranslation } from 'react-i18next'; import { SCEN, Scen, scenName } from './ssulData'; /** 생성 잡의 현재 상태. GenerationFlow 가 폴링해 내려준다 */ export interface SsulJob { taskId: number; scenario: Scen; status: 'queued' | 'running' | 'done' | 'error'; /** 0~4. 0=준비, 4=영상 합성 완료 */ step: number; error: string | null; } interface SsulMakingContentProps { job: SsulJob | null; /** 실패 후 처음부터 다시 */ onRetry: () => void; } /** 백엔드 generator 가 뱉는 4단계. `ssul_content.step` 과 1:1 대응 */ const TOTAL_STEPS = 4; const STEP_LABEL_KEYS = [ 'ssulbox.making.step1', 'ssulbox.making.step2', 'ssulbox.making.step3', 'ssulbox.making.step4', ] as const; /** * 썰박스 생성 진행 화면. * * 원본은 SSE 로 진행률만 받아 막대 하나를 그렸지만, castad 는 폴링으로 * `step`(0~4)을 받으므로 **지금 무슨 작업 중인지 단계명까지** 보여준다. * 수 분~십수 분이 걸리는 작업이라 진행바만 있으면 멈춘 것처럼 보인다. * * 잡 소유는 GenerationFlow 다. 이 컴포넌트는 표시만 하므로 * 사이드바로 이동해 언마운트돼도 폴링이 끊기지 않는다. * 그래서 "백그라운드로 전환" 버튼을 두지 않는다 — 사이드바로 그냥 이동하면 * 되고, 버튼이 있으면 마치 전환해야 계속 도는 것처럼 오해를 준다. */ const SsulMakingContent: React.FC = ({ job, onRetry }) => { const { t } = useTranslation(); if (!job) return null; const palette = SCEN[job.scenario]; const failed = job.status === 'error'; // step 은 "완료한 단계 수"라 진행률은 step/4. queued(0) 면 0% const percent = Math.round((Math.min(job.step, TOTAL_STEPS) / TOTAL_STEPS) * 100); // 진행 중인 단계는 완료 수 + 1 (마지막 단계 완료 시엔 더 올리지 않음) const currentIndex = Math.min(job.step, TOTAL_STEPS - 1); return (
{t(scenName(job.scenario))} {failed ? ( <>

{t('ssulbox.making.failTitle')}

{job.error || t('ssulbox.making.failDefault')}

{/* 백엔드가 실패 시 크레딧을 환불한다 — 사용자가 손해 보지 않았음을 알린다 */}

{t('ssulbox.making.refunded')}

) : ( <>

{t('ssulbox.making.title')}

{/* 단계 사이 구간에서는 진행바가 멈춰 있어 고장처럼 보인다. 스피너는 "살아 있다"는 신호 전용이라 진행률을 표현하지 않는다. 색은 시나리오 대표색을 따른다(민트 고정이면 삼국지·오디세이와 부딪힌다). */}