'use client' import React, { useMemo, useEffect, useState } from 'react' import { motion, AnimatePresence } from 'framer-motion' import { Heart, Camera, Film, Scissors, type LucideIcon } from 'lucide-react' import { TaskObject } from '@/api/DTO/movieEdit' interface H5ProgressBarProps { taskObject: TaskObject scriptData: any /** Loading text for stage detection */ currentLoadingText: string className?: string } /** Stage configuration map */ const stageIconMap: Record = { 0: { icon: Heart, color: '#6bf5f9', label: 'Script' }, 1: { icon: Camera, color: '#88bafb', label: 'Roles & Scenes' }, 2: { icon: Film, color: '#a285fd', label: 'Shots' }, 3: { icon: Scissors, color: '#c73dff', label: 'Final' } } const H5ProgressBar: React.FC = ({ taskObject, scriptData, currentLoadingText, className }) => { /** Calculate current stage based on taskObject state */ const currentStage = useMemo(() => { /** Check if roles & scenes are completed */ const rolesCompleted = taskObject.roles?.total_count > 0 && taskObject.roles?.data?.filter(v => v.status !== 0).length === taskObject.roles?.total_count const scenesCompleted = taskObject.scenes?.total_count > 0 && taskObject.scenes?.data?.filter(v => v.status !== 0).length === taskObject.scenes?.total_count const rolesAndScenesCompleted = rolesCompleted && scenesCompleted /** Check if videos are completed or nearly completed */ const videosCount = taskObject.videos?.data?.filter(v => v.video_status !== 0).length || 0 const videosTotal = taskObject.videos?.total_count || 0 const videosCompleted = videosTotal > 0 && videosCount === videosTotal const videosNearlyComplete = videosTotal > 0 && videosCount >= videosTotal * 0.9 /** 90% complete */ /** Check if final video exists */ const finalVideoExists = !!taskObject.final?.url /** Determine stage based on conditions */ if (finalVideoExists) { return 4 /** Completed - all done */ } /** Enter final video stage when videos are completed or nearly complete, or stage is explicitly set */ if (videosCompleted || videosNearlyComplete || taskObject.currentStage === 'final_video') { return 3 /** Final video stage */ } if (rolesAndScenesCompleted || taskObject.currentStage === 'video') { return 2 /** Shots/video stage */ } if (scriptData || taskObject.currentStage === 'character' || taskObject.currentStage === 'scene') { return 1 /** Roles & scenes stage */ } if (taskObject.currentStage === 'script') { return 0 /** Script stage */ } return 0 /** Default to script stage */ }, [ taskObject.currentStage, taskObject.roles?.data, taskObject.roles?.total_count, taskObject.scenes?.data, taskObject.scenes?.total_count, taskObject.videos?.data, taskObject.videos?.total_count, taskObject.final?.url, scriptData ]) /** Generate progress segments */ const segments = useMemo(() => { /** Calculate progress for each stage */ const calculateStageProgress = (stage: number): number => { const isCompleted = stage < currentStage const isCurrent = stage === currentStage const isNext = stage === currentStage + 1 /** Completed stages are always 100% */ if (isCompleted) { return 100 } /** Non-current and non-next stages are 0% */ if (!isCurrent && !isNext) { return 0 } /** Calculate current stage progress */ switch (stage) { case 0: /** Script stage */ /** If scriptData exists or moved to next stage, show 100% */ if (scriptData || currentStage > 0) { return 100 } return 40 case 1: /** Roles & Scenes stage */ const rolesCount = taskObject.roles?.data?.filter(v => v.status !== 0).length || 0 const rolesTotal = taskObject.roles?.total_count || 0 const scenesCount = taskObject.scenes?.data?.filter(v => v.status !== 0).length || 0 const scenesTotal = taskObject.scenes?.total_count || 0 const totalItems = rolesTotal + scenesTotal if (totalItems === 0) { return 40 } const completedItems = rolesCount + scenesCount return Math.min(Math.round((completedItems / totalItems) * 100), 95) case 2: /** Shots/Video stage */ const videosCount = taskObject.videos?.data?.filter(v => v.video_status !== 0).length || 0 const videosTotal = taskObject.videos?.total_count || 0 if (videosTotal === 0) { return 40 } return Math.min(Math.round((videosCount / videosTotal) * 100), 95) case 3: /** Final video stage */ /** If final.url exists, show 100% */ if (taskObject.final?.url) { return 100 } /** If this is the next stage (not current), show initial progress */ if (isNext) { return 0 } /** Current stage in progress */ return 60 default: return 0 } } return [0, 1, 2, 3].map((stage) => { const config = stageIconMap[stage] const isCompleted = stage < currentStage const isCurrent = stage === currentStage const segmentProgress = calculateStageProgress(stage) return { stage, config, isCompleted, isCurrent, segmentProgress } }) }, [ currentStage, scriptData, taskObject.roles?.data, taskObject.roles?.total_count, taskObject.scenes?.data, taskObject.scenes?.total_count, taskObject.videos?.data, taskObject.videos?.total_count, taskObject.final?.url ]) return (
{segments.map(({ stage, config, isCompleted, isCurrent, segmentProgress }) => { const Icon = config.icon return (
{/* Progress fill */} {/* Animated icon for current stage only */} {isCurrent && !currentLoadingText.includes('Task completed') && segmentProgress < 100 && (
{/* */}
)}
{/* Glow effect for current stage */} {isCurrent && segmentProgress < 100 && ( )}
) })}
{/* Stage labels (optional) */} {/*
{segments.map(({ stage, config, isCurrent }) => ( {config.label} ))}
*/}
) } export default H5ProgressBar