import { CloudUploadOutlined, CloseOutlined, FileImageOutlined, LoadingOutlined, QuestionCircleOutlined, ReloadOutlined, SettingOutlined, } from "@ant-design/icons"; import { createPortal } from "react-dom"; import type { CSSProperties, ChangeEvent, DragEvent, MutableRefObject, RefObject } from "react"; import { useState } from "react"; type ProductSetOutputKey = "set" | "detail" | "model" | "video"; type CloneOutputKey = ProductSetOutputKey | "hot"; type CloneSetCountKey = "selling" | "white" | "scene"; type CloneModelPanelTab = "scene" | "model"; type CloneReferenceMode = "upload" | "link"; type CloneReplicateLevelKey = "style" | "high"; type CloneVideoQualityKey = "standard" | "high" | "ultra"; type CloneBasicSelectKey = "platform" | "market" | "language" | "ratio"; type CloneModelSelectKey = "gender" | "age" | "ethnicity" | "body"; interface CloneImageItem { id: string; src: string; name: string; } interface CloneBasicSelectItem { key: CloneBasicSelectKey; label: string; value: string; options: string[]; onChange: (value: string) => void; } interface CloneModelSelectItem { key: CloneModelSelectKey; label: string; value: string; options: string[]; onChange: (value: string) => void; } interface CloneSetCountOption { key: CloneSetCountKey; title: string; desc: string; } interface CloneOutputOption { key: CloneOutputKey; label: string; } interface CloneReplicateLevelOption { key: CloneReplicateLevelKey; title: string; desc: string; } interface CloneVideoQualityOption { key: CloneVideoQualityKey; label: string; desc: string; } interface CloneDetailModule { id: string; title: string; desc: string; } interface EcommerceClonePanelProps { productInputRef: RefObject; cloneReferenceInputRef: RefObject; productImages: CloneImageItem[]; isProductUploadDragging: boolean; cloneOutput: CloneOutputKey; cloneOutputOptions: CloneOutputOption[]; cloneBasicSelects: CloneBasicSelectItem[]; openCloneBasicSelect: CloneBasicSelectKey | null; cloneReferenceMode: CloneReferenceMode; cloneReferenceImages: CloneImageItem[]; maxCloneReferenceImages: number; cloneReplicateLevel: CloneReplicateLevelKey; cloneReplicateLevelOptions: CloneReplicateLevelOption[]; cloneSetCounts: Record; cloneSetCountOptions: CloneSetCountOption[]; cloneSetTotal: number; minCloneSetTotal: number; maxCloneSetTotal: number; selectedCloneDetailModules: string[]; cloneDetailModules: CloneDetailModule[]; cloneModelPanelTab: CloneModelPanelTab; tryOnScenes: string[]; selectedCloneModelScenes: string[]; cloneModelCustomScene: string; cloneModelSelects: CloneModelSelectItem[]; openCloneModelSelect: CloneModelSelectKey | null; cloneModelSelectDropUp: boolean; cloneVideoQuality: CloneVideoQualityKey; cloneVideoQualityOptions: CloneVideoQualityOption[]; cloneVideoDuration: number; cloneVideoDurationMin: number; cloneVideoDurationMax: number; cloneVideoDurationStyle: CSSProperties; cloneVideoSmart: boolean; canGenerate: boolean; status: string; lastFailedActionRef: MutableRefObject<(() => void) | null>; setIsProductUploadDragging: (value: boolean) => void; handleProductDrop: (event: DragEvent) => void; removeProductImage: (id: string) => void; handleProductUpload: (event: ChangeEvent) => void; handleCloneOutputChange: (value: CloneOutputKey) => void; setOpenCloneBasicSelect: (value: CloneBasicSelectKey | null) => void; setCloneReferenceMode: (value: CloneReferenceMode) => void; handleCloneReferenceUpload: (event: ChangeEvent) => void; isCloneReferenceDragging: boolean; handleCloneReferenceDragOver: (event: DragEvent) => void; handleCloneReferenceDragLeave: (event: DragEvent) => void; handleCloneReferenceDrop: (event: DragEvent) => void; setCloneReplicateLevel: (value: CloneReplicateLevelKey) => void; startCloneSetCountHold: (key: CloneSetCountKey, delta: -1 | 1, disabled: boolean) => void; clearCloneSetCountHold: () => void; toggleCloneDetailModule: (id: string) => void; setCloneModelPanelTab: (value: CloneModelPanelTab) => void; toggleCloneModelScene: (scene: string) => void; setCloneModelCustomScene: (value: string) => void; setOpenCloneModelSelect: (value: CloneModelSelectKey | null) => void; setCloneModelSelectDropUp: (value: boolean) => void; setCloneVideoQuality: (value: CloneVideoQualityKey) => void; setCloneVideoDuration: (value: number) => void; clampCloneVideoDuration: (value: number) => number; setCloneVideoSmart: (updater: (current: boolean) => boolean) => void; handleGenerate: () => void; onCancelGenerate: () => void; formatRatioDisplayValue: (value: string) => string; onStartVideoPlan?: () => void; } export default function EcommerceClonePanel({ productInputRef, cloneReferenceInputRef, productImages, isProductUploadDragging, cloneOutput, cloneOutputOptions, cloneBasicSelects, openCloneBasicSelect, cloneReferenceMode, cloneReferenceImages, maxCloneReferenceImages, cloneReplicateLevel, cloneReplicateLevelOptions, cloneSetCounts, cloneSetCountOptions, cloneSetTotal, minCloneSetTotal, maxCloneSetTotal, selectedCloneDetailModules, cloneDetailModules, cloneModelPanelTab, tryOnScenes, selectedCloneModelScenes, cloneModelCustomScene, cloneModelSelects, openCloneModelSelect, cloneModelSelectDropUp, cloneVideoQuality, cloneVideoQualityOptions, cloneVideoDuration, cloneVideoDurationMin, cloneVideoDurationMax, cloneVideoDurationStyle, cloneVideoSmart, canGenerate, status, lastFailedActionRef, setIsProductUploadDragging, handleProductDrop, removeProductImage, handleProductUpload, handleCloneOutputChange, setOpenCloneBasicSelect, setCloneReferenceMode, handleCloneReferenceUpload, isCloneReferenceDragging, handleCloneReferenceDragOver, handleCloneReferenceDragLeave, handleCloneReferenceDrop, setCloneReplicateLevel, startCloneSetCountHold, clearCloneSetCountHold, toggleCloneDetailModule, setCloneModelPanelTab, toggleCloneModelScene, setCloneModelCustomScene, setOpenCloneModelSelect, setCloneModelSelectDropUp, setCloneVideoQuality, setCloneVideoDuration, clampCloneVideoDuration, setCloneVideoSmart, handleGenerate, onCancelGenerate, formatRatioDisplayValue, onStartVideoPlan, }: EcommerceClonePanelProps) { const [zoomImage, setZoomImage] = useState<{ src: string; x: number; y: number } | null>(null); const handleFileMouseEnter = (src: string, event: React.MouseEvent) => { const rect = event.currentTarget.getBoundingClientRect(); setZoomImage({ src, x: rect.left + rect.width / 2, y: rect.top }); }; const handleFileMouseLeave = () => setZoomImage(null); const platformSelect = cloneBasicSelects.find((item) => item.key === "platform"); const languageSelects = cloneBasicSelects.filter((item) => item.key === "market" || item.key === "language"); const ratioSelect = cloneBasicSelects.find((item) => item.key === "ratio"); const renderBasicSelect = (item: CloneBasicSelectItem) => { const hasMultipleOptions = item.options.length > 1; const isOpen = hasMultipleOptions && openCloneBasicSelect === item.key; return (