diff --git a/apps/master-sample-app/app/[[...slug]]/page.tsx b/apps/master-sample-app/app/[[...slug]]/page.tsx index 7a31a077..3c1b2a15 100644 --- a/apps/master-sample-app/app/[[...slug]]/page.tsx +++ b/apps/master-sample-app/app/[[...slug]]/page.tsx @@ -12,22 +12,24 @@ export default function Page() { const [documentId, setDocumentId] = useState('') const [isMounted, setIsMounted] = useState(false) const isInitialized = useRef(false) - + const currentSample = getSampleById(currentSampleId) || getDefaultSample() // Helper function to get document ID for a specific demo const getDocumentIdForDemo = useCallback((demoId: string): string => { if (typeof window === 'undefined') return '' - - // Check if there's a stored document ID for this demo - const stored = localStorage.getItem(`demo-${demoId}-document-id`) + + const storageKey = `demo-${demoId}-document-id` + const stored = localStorage.getItem(storageKey) + if (stored) { return stored } - + // Generate a new document ID for this demo const newDocId = `doc-${demoId}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}` - localStorage.setItem(`demo-${demoId}-document-id`, newDocId) + localStorage.setItem(storageKey, newDocId) + return newDocId }, []) @@ -113,7 +115,7 @@ export default function Page() { // Update URL after state update const routePath = sample.metadata.routePath || window.location.pathname const newUrl = `${routePath}?documentId=${docId}` - + if (window.location.href !== window.location.origin + newUrl) { window.history.pushState({}, '', newUrl) } @@ -122,9 +124,6 @@ export default function Page() { } }, [currentSampleId, getDocumentIdForDemo]) - // Note: URL updates are now handled directly in handleSampleSelect and handleReset - // This effect is removed to prevent duplicate history entries - // Handle reset: generate new document ID for current demo const handleReset = useCallback(() => { if (typeof window === 'undefined') return @@ -135,17 +134,17 @@ export default function Page() { // Generate a new document ID for this specific demo const newDocId = `doc-${currentSampleId}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}` - + // Update localStorage for this demo localStorage.setItem(`demo-${currentSampleId}-document-id`, newDocId) - + // Update state setDocumentId(newDocId) - + // Update URL const routePath = sample.metadata.routePath || window.location.pathname const newUrl = `${routePath}?documentId=${newDocId}` - + if (window.location.href !== window.location.origin + newUrl) { window.history.pushState({}, '', newUrl) } @@ -174,7 +173,7 @@ export default function Page() { /> {/* Main Content */} - setSidebarOpen(!sidebarOpen)} @@ -184,4 +183,3 @@ export default function Page() { ) } - diff --git a/apps/master-sample-app/components/viewer/iframe-pair.tsx b/apps/master-sample-app/components/viewer/iframe-pair.tsx index c036570d..7ba78353 100644 --- a/apps/master-sample-app/components/viewer/iframe-pair.tsx +++ b/apps/master-sample-app/components/viewer/iframe-pair.tsx @@ -1,6 +1,32 @@ "use client" -import { useState } from "react" +import { useState, useRef, useEffect } from "react" + +// Time to wait for Velt SDK auth to complete before refreshing +// validateclient takes ~7-8 seconds, add buffer +const VELT_AUTH_WAIT_MS = 8000 + +// Check if a demo origin has been initialized (Velt auth cached) +function isDemoInitialized(url: string): boolean { + try { + const origin = new URL(url).origin + const key = `velt-initialized-${origin}` + return localStorage.getItem(key) === 'true' + } catch { + return false + } +} + +// Mark a demo origin as initialized +function markDemoInitialized(url: string): void { + try { + const origin = new URL(url).origin + const key = `velt-initialized-${origin}` + localStorage.setItem(key, 'true') + } catch { + // ignore + } +} interface IframePairProps { url?: string @@ -19,6 +45,25 @@ export function IframePair({ const [isLoading2, setIsLoading2] = useState(true) const [error1, setError1] = useState(false) const [error2, setError2] = useState(false) + // If demo was already initialized, skip the wait/refresh cycle + const [hasRefreshed1, setHasRefreshed1] = useState(() => url ? isDemoInitialized(url) : false) + const [hasRefreshed2, setHasRefreshed2] = useState(() => { + const targetUrl = secondUrl || url + return targetUrl ? isDemoInitialized(targetUrl) : false + }) + + const iframe1Ref = useRef(null) + const iframe2Ref = useRef(null) + const refreshTimer1 = useRef(null) + const refreshTimer2 = useRef(null) + + // Cleanup timers on unmount + useEffect(() => { + return () => { + if (refreshTimer1.current) clearTimeout(refreshTimer1.current) + if (refreshTimer2.current) clearTimeout(refreshTimer2.current) + } + }, []) // Safety check: don't render if URL is not provided if (!url) { @@ -33,11 +78,45 @@ export function IframePair({ const handleIframeLoad = (iframeNum: number) => { if (iframeNum === 1) { - setIsLoading1(false) setError1(false) + + if (!hasRefreshed1) { + // First load: wait for Velt auth to complete, then refresh + refreshTimer1.current = setTimeout(() => { + if (iframe1Ref.current && url) { + setHasRefreshed1(true) + // Force refresh by resetting src + iframe1Ref.current.src = url + } + }, VELT_AUTH_WAIT_MS) + } else { + // Second load (after refresh): Velt auth should be cached, ready to show + setIsLoading1(false) + // Mark this demo origin as initialized for future visits + if (url) markDemoInitialized(url) + } } else { - setIsLoading2(false) setError2(false) + + if (!hasRefreshed2) { + // First load: wait for Velt auth to complete, then refresh + refreshTimer2.current = setTimeout(() => { + if (iframe2Ref.current) { + const refreshUrl = secondUrl || url + if (refreshUrl) { + setHasRefreshed2(true) + // Force refresh by resetting src + iframe2Ref.current.src = refreshUrl + } + } + }, VELT_AUTH_WAIT_MS) + } else { + // Second load (after refresh): Velt auth should be cached, ready to show + setIsLoading2(false) + // Mark this demo origin as initialized for future visits + const targetUrl = secondUrl || url + if (targetUrl) markDemoInitialized(targetUrl) + } } } @@ -56,9 +135,9 @@ export function IframePair({ return (
- {isLoading1 && !error1 && ( -
-
Loading demo...
+ {!hasRefreshed1 && ( +
+
Initializing...
)} {error1 && ( @@ -67,6 +146,7 @@ export function IframePair({
)}