diff --git a/frontend/src/pages/constructor.tsx b/frontend/src/pages/constructor.tsx index 40796d5..dc268a6 100644 --- a/frontend/src/pages/constructor.tsx +++ b/frontend/src/pages/constructor.tsx @@ -392,18 +392,7 @@ const resolveDurationWithFallback = async ( } try { - const requestUrl = - playbackUrl.startsWith('http://') || playbackUrl.startsWith('https://') - ? playbackUrl - : playbackUrl.replace(/^\/api(?=\/)/, ''); - - const token = - typeof window !== 'undefined' ? localStorage.getItem('token') || '' : ''; - const response = await axios.get(requestUrl, { - responseType: 'blob', - headers: token ? { Authorization: `Bearer ${token}` } : undefined, - }); - + const response = await axios.get(playbackUrl, { responseType: 'blob' }); const blobUrl = URL.createObjectURL(response.data); try { const blobDuration = await readMediaDuration(blobUrl, mediaType); @@ -549,6 +538,7 @@ const createDefaultElement = ( navType: getNavigationButtonKind(type), iconUrl: '', transitionReverseMode: 'auto_reverse', + transitionDurationSec: 0.7, }; } @@ -749,7 +739,6 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => { useState('none'); const [transitionPreview, setTransitionPreview] = useState(null); - const [pendingNavigationPageId, setPendingNavigationPageId] = useState(''); const [isLoading, setIsLoading] = useState(true); const [isSaving, setIsSaving] = useState(false); @@ -759,6 +748,7 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => { const [newTransitionVideoUrl, setNewTransitionVideoUrl] = useState(''); const [newTransitionSupportsReverse, setNewTransitionSupportsReverse] = useState(true); + const [newTransitionDurationSec, setNewTransitionDurationSec] = useState(0.7); const [errorMessage, setErrorMessage] = useState(''); const [successMessage, setSuccessMessage] = useState(''); const [resolvedDurationBySource, setResolvedDurationBySource] = useState< @@ -994,28 +984,8 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => { }); } - if (newTransitionVideoUrl) { - targets.push({ source: newTransitionVideoUrl, mediaType: 'video' }); - } - - elements.forEach((element) => { - if (!isNavigationElementType(element.type)) return; - if (element.transitionVideoUrl) { - targets.push({ source: element.transitionVideoUrl, mediaType: 'video' }); - } - if (element.reverseVideoUrl) { - targets.push({ source: element.reverseVideoUrl, mediaType: 'video' }); - } - }); - return targets; - }, [ - backgroundAudioUrl, - backgroundVideoUrl, - elements, - newTransitionVideoUrl, - selectedElement, - ]); + }, [backgroundAudioUrl, backgroundVideoUrl, selectedElement]); useEffect(() => { let isCancelled = false; @@ -1080,19 +1050,6 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => { getKnownDurationForSource(selectedElement.mediaUrl || ''), ); }, [getKnownDurationForSource, selectedElement]); - const newTransitionDurationNote = useMemo( - () => formatDurationNote(getKnownDurationForSource(newTransitionVideoUrl)), - [getKnownDurationForSource, newTransitionVideoUrl], - ); - const selectedTransitionDurationNote = useMemo(() => { - if (!selectedElement || !isNavigationElementType(selectedElement.type)) { - return 'Duration: unknown'; - } - - return formatDurationNote( - getKnownDurationForSource(selectedElement.transitionVideoUrl || ''), - ); - }, [getKnownDurationForSource, selectedElement]); useEffect(() => { if (newTransitionVideoUrl) return; @@ -1100,32 +1057,6 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => { setNewTransitionVideoUrl(transitionVideoAssetOptions[0].value); }, [newTransitionVideoUrl, transitionVideoAssetOptions]); - useEffect(() => { - setElements((prev) => { - let hasChanges = false; - const next = prev.map((element) => { - if (!isNavigationElementType(element.type)) return element; - - const resolvedDuration = getKnownDurationForSource( - element.transitionVideoUrl || '', - ); - const nextDuration = - Number.isFinite(resolvedDuration) && Number(resolvedDuration) > 0 - ? Number(resolvedDuration) - : undefined; - if (element.transitionDurationSec === nextDuration) return element; - - hasChanges = true; - return { - ...element, - transitionDurationSec: nextDuration, - }; - }); - - return hasChanges ? next : prev; - }); - }, [getKnownDurationForSource]); - const loadData = useCallback(async () => { if (!projectId || !router.isReady || !isAuthReady) return; @@ -1712,13 +1643,7 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => { const sanitizedName = String(newTransitionName || '').trim() || `Transition ${Date.now().toString().slice(-4)}`; - const resolvedDurationSec = getKnownDurationForSource(sanitizedVideoUrl); - if (!resolvedDurationSec) { - setErrorMessage( - 'Could not resolve transition video duration yet. Please wait a moment and try again.', - ); - return; - } + const parsedDuration = Number(newTransitionDurationSec); try { setIsCreatingTransition(true); @@ -1734,7 +1659,10 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => { video_url: sanitizedVideoUrl, audio_url: '', supports_reverse: Boolean(newTransitionSupportsReverse), - duration_sec: resolvedDurationSec, + duration_sec: + Number.isFinite(parsedDuration) && parsedDuration > 0 + ? parsedDuration + : 0.7, }; await axios.post('/transitions', { data: payload }); @@ -1752,7 +1680,7 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => { } }, [ activePage?.environment, - getKnownDurationForSource, + newTransitionDurationSec, newTransitionName, newTransitionSupportsReverse, newTransitionVideoUrl, @@ -1996,44 +1924,6 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => { element.navType === 'back' || element.type === 'navigation_prev' ? 'back' : 'forward'; - const configuredTargetId = String(element.targetPageId || '').trim(); - const fallbackTargetId = (() => { - const currentPageIndex = pages.findIndex( - (page) => page.id === activePageId, - ); - if (currentPageIndex < 0) return ''; - - const nextPageIndex = - direction === 'back' ? currentPageIndex - 1 : currentPageIndex + 1; - const nextPage = pages[nextPageIndex]; - return nextPage ? String(nextPage.id || '').trim() : ''; - })(); - const targetPageId = configuredTargetId || fallbackTargetId; - - if (!targetPageId) { - setErrorMessage('No target page available for this navigation button.'); - return; - } - - const hasPlayableTransition = - Boolean(element.transitionVideoUrl) && - !( - direction === 'back' && - element.transitionReverseMode === 'separate_video' && - !element.reverseVideoUrl - ); - - if (!hasPlayableTransition) { - setPendingNavigationPageId(''); - setTransitionPreview(null); - setActivePageId(targetPageId); - setSelectedElementId(''); - setSelectedMenuItem('none'); - setErrorMessage(''); - return; - } - - setPendingNavigationPageId(targetPageId); openTransitionPreviewForElement(element, direction); } return; @@ -2376,16 +2266,6 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => { const finishPreview = () => { cleanupReverseFrame(); setTransitionPreview(null); - setPendingNavigationPageId((pendingPageId) => { - const nextPageId = String(pendingPageId || '').trim(); - if (nextPageId) { - setActivePageId(nextPageId); - setSelectedElementId(''); - setSelectedMenuItem('none'); - setErrorMessage(''); - } - return ''; - }); }; const configuredDurationMs = @@ -2820,10 +2700,6 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => { ))} -

- Transition duration is automatic from video metadata.{' '} - {newTransitionDurationNote} -

+ + setNewTransitionDurationSec( + Number(event.target.value || 0.7), + ) + } + />