import { useCallback, useEffect, useState } from 'react' import { ArrowLeft, Sparkles, Film } from 'lucide-react' import { useProjects } from '../contexts/ProjectContext' import { useView } from '../contexts/ViewContext' import { LtxLogo } from '../components/LtxLogo' import { Button } from '../components/ui/button' import { GenSpace } from './GenSpace' import { VideoEditor } from './VideoEditor' import type { ProjectTab } from '../types/project-model' import { hasVisualAssetMetadataForMigration, runVisualAssetMetadataMigration, } from '../lib/project-asset-metadata-migration' export function Project() { const { activeProject, currentTab, setProject, setCurrentTab, updateAsset, pendingRetakeUpdate, setPendingRetakeUpdate, pendingIcLoraUpdate, setPendingIcLoraUpdate, } = useProjects() const { goHome } = useView() const [assetMetadataMigrationProgress, setAssetMetadataMigrationProgress] = useState({ running: false, total: 0, completed: 0 }) const [upgradePassProjectId, setUpgradePassProjectId] = useState(null) const activeProjectId = activeProject?.id ?? null const activeProjectAssets = activeProject?.assets ?? null const needsAssetMetadataMigration = activeProjectAssets ? hasVisualAssetMetadataForMigration(activeProjectAssets) : false const handleSaveActiveProject = useCallback((project: typeof activeProject extends null ? never : NonNullable) => { if (!activeProjectId) return setProject(activeProjectId, project) }, [activeProjectId, setProject]) useEffect(() => { if (!activeProjectId || !activeProjectAssets || !needsAssetMetadataMigration) return let cancelled = false const runAssetMetadataMigration = async () => { for await (const event of runVisualAssetMetadataMigration(activeProjectAssets, window.electronAPI)) { if (cancelled) return if (event.kind === 'progress') { setAssetMetadataMigrationProgress({ running: true, total: event.total, completed: event.completed }) continue } for (const update of event.updates) { updateAsset(activeProjectId, update.assetId, update.updates) } setAssetMetadataMigrationProgress({ running: false, total: 0, completed: 0 }) setUpgradePassProjectId(activeProjectId) } } void runAssetMetadataMigration() return () => { cancelled = true } }, [activeProjectAssets, activeProjectId, needsAssetMetadataMigration, updateAsset]) useEffect(() => { if (currentTab !== 'video-editor') return if (pendingRetakeUpdate) setPendingRetakeUpdate(null) if (pendingIcLoraUpdate) setPendingIcLoraUpdate(null) }, [ currentTab, pendingRetakeUpdate, setPendingRetakeUpdate, pendingIcLoraUpdate, setPendingIcLoraUpdate, ]) if (!activeProject) { return (

Project not found

) } const tabs: { id: ProjectTab; label: string; icon: React.ReactNode }[] = [ { id: 'gen-space', label: 'Gen Space', icon: }, { id: 'video-editor', label: 'Video Editor', icon: }, ] const shouldShowAssetMetadataMigrationProgressScreen = assetMetadataMigrationProgress.running || (upgradePassProjectId !== activeProjectId && needsAssetMetadataMigration) if (shouldShowAssetMetadataMigrationProgressScreen) { const progressPct = assetMetadataMigrationProgress.total > 0 ? (assetMetadataMigrationProgress.completed / assetMetadataMigrationProgress.total) * 100 : 0 return (

Preparing your project assets...

) } return (
{/* Header */}
{/* Back button and logo */} {/* Project name */} {activeProject.name}
{/* Center - Tabs */}
{tabs.map(tab => ( ))}
{/* Right spacer - equal to left to keep tabs centered */}
{currentTab === 'gen-space' ? ( ) : ( )}
) }