Skip to content

Commit d001be0

Browse files
yoen-veltclaude
andcommitted
fix: resolve Velt auth timing issue in master-sample-app iframes
On first load, demo iframes would get stuck because Velt SDK tried to connect before authentication completed (~8s). This fix waits for auth to complete, then refreshes the iframes. Subsequent visits skip the delay by checking a localStorage flag per demo origin. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 5435b69 commit d001be0

File tree

3 files changed

+390
-47
lines changed

3 files changed

+390
-47
lines changed

apps/master-sample-app/app/[[...slug]]/page.tsx

Lines changed: 135 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,73 @@ import { Sidebar } from "@/components/sidebar"
55
import { SampleViewer } from "@/components/viewer/sample-viewer"
66
import { getDefaultSample, getSampleById, getAllSamples } from "@/samples"
77

8+
// Enable debug logging
9+
const DEBUG = true
10+
11+
// Debug helper to log localStorage state
12+
function logStorageState(context: string) {
13+
if (!DEBUG || typeof window === 'undefined') return
14+
15+
const keys = Object.keys(localStorage).filter(k =>
16+
k.includes('document') || k.includes('sample') || k.includes('demo')
17+
)
18+
const state: Record<string, string | null> = {}
19+
keys.forEach(k => state[k] = localStorage.getItem(k))
20+
21+
console.log(`[Page] localStorage (${context}):`, state)
22+
}
23+
824
export default function Page() {
925
const [sidebarOpen, setSidebarOpen] = useState(true)
1026
// Always initialize with default to match server render
1127
const [currentSampleId, setCurrentSampleId] = useState<string>(getDefaultSample().metadata.id)
1228
const [documentId, setDocumentId] = useState<string>('')
1329
const [isMounted, setIsMounted] = useState(false)
1430
const isInitialized = useRef(false)
15-
31+
const renderCount = useRef(0)
32+
33+
renderCount.current++
34+
1635
const currentSample = getSampleById(currentSampleId) || getDefaultSample()
1736

37+
// Debug: Track renders
38+
useEffect(() => {
39+
if (DEBUG) {
40+
console.log(`[Page] Render #${renderCount.current}`, {
41+
currentSampleId,
42+
documentId,
43+
isMounted,
44+
isInitialized: isInitialized.current,
45+
})
46+
}
47+
})
48+
1849
// Helper function to get document ID for a specific demo
1950
const getDocumentIdForDemo = useCallback((demoId: string): string => {
2051
if (typeof window === 'undefined') return ''
21-
22-
// Check if there's a stored document ID for this demo
23-
const stored = localStorage.getItem(`demo-${demoId}-document-id`)
52+
53+
const storageKey = `demo-${demoId}-document-id`
54+
const stored = localStorage.getItem(storageKey)
55+
56+
if (DEBUG) {
57+
console.log(`[Page] getDocumentIdForDemo("${demoId}")`, {
58+
storageKey,
59+
storedValue: stored,
60+
})
61+
}
62+
2463
if (stored) {
2564
return stored
2665
}
27-
66+
2867
// Generate a new document ID for this demo
2968
const newDocId = `doc-${demoId}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`
30-
localStorage.setItem(`demo-${demoId}-document-id`, newDocId)
69+
localStorage.setItem(storageKey, newDocId)
70+
71+
if (DEBUG) {
72+
console.log(`[Page] Generated new documentId:`, newDocId)
73+
}
74+
3175
return newDocId
3276
}, [])
3377

@@ -36,6 +80,12 @@ export default function Page() {
3680
if (isInitialized.current) return
3781
if (typeof window === 'undefined') return
3882

83+
if (DEBUG) {
84+
console.log('[Page] === INITIALIZATION START ===')
85+
console.log('[Page] URL:', window.location.href)
86+
logStorageState('before init')
87+
}
88+
3989
try {
4090
// 1. Determine which sample to load based on URL path
4191
const currentPath = window.location.pathname
@@ -44,6 +94,13 @@ export default function Page() {
4494

4595
let targetSampleId = getDefaultSample().metadata.id
4696

97+
if (DEBUG) {
98+
console.log('[Page] Path resolution:', {
99+
currentPath,
100+
sampleFromPath: sampleFromPath?.metadata.id,
101+
})
102+
}
103+
47104
// Priority order: URL path > localStorage > default
48105
if (sampleFromPath) {
49106
targetSampleId = sampleFromPath.metadata.id
@@ -58,43 +115,82 @@ export default function Page() {
58115
}
59116
}
60117

118+
if (DEBUG) {
119+
console.log('[Page] Target sample:', targetSampleId)
120+
}
121+
61122
// Store the selection for persistence
62123
localStorage.setItem('last-selected-sample-id', targetSampleId)
63124

64125
// 2. Check URL for documentId parameter
65126
const urlParams = new URLSearchParams(window.location.search)
66127
let docId = urlParams.get('documentId')
67128

129+
if (DEBUG) {
130+
console.log('[Page] URL documentId param:', docId)
131+
}
132+
68133
if (docId) {
69134
// Use document ID from URL (shareable link)
70135
localStorage.setItem(`demo-${targetSampleId}-document-id`, docId)
136+
if (DEBUG) {
137+
console.log('[Page] Using documentId from URL:', docId)
138+
}
71139
} else {
72140
// Get or generate document ID for this specific demo
73141
docId = getDocumentIdForDemo(targetSampleId)
142+
if (DEBUG) {
143+
console.log('[Page] Got/generated documentId:', docId)
144+
}
74145
}
75146

76147
// Mark as initialized BEFORE setting state to prevent sample change effect from running
77148
isInitialized.current = true
78149

150+
if (DEBUG) {
151+
console.log('[Page] Setting state:', { targetSampleId, docId })
152+
logStorageState('after init')
153+
}
154+
79155
// Update state atomically - both sampleId and documentId together
80156
// This ensures the iframe never renders with mismatched sample/document
81157
if (targetSampleId !== currentSampleId) {
82158
setCurrentSampleId(targetSampleId)
83159
}
84160
setDocumentId(docId)
85161
setIsMounted(true)
162+
163+
if (DEBUG) {
164+
console.log('[Page] === INITIALIZATION COMPLETE ===')
165+
}
86166
} catch (error) {
87167
console.error('Error initializing:', error)
88168
setIsMounted(true)
89169
}
90170
}, [])
91171

172+
// Debug: Periodic storage check
173+
useEffect(() => {
174+
if (!DEBUG || !isMounted) return
175+
176+
const interval = setInterval(() => {
177+
logStorageState('periodic check')
178+
}, 5000) // Every 5 seconds
179+
180+
return () => clearInterval(interval)
181+
}, [isMounted])
182+
92183
// Handle sample selection: atomically update both sample and document ID
93184
// to prevent race conditions where iframe renders with mismatched data
94185
const handleSampleSelect = useCallback((newSampleId: string) => {
95186
if (newSampleId === currentSampleId) return
96187
if (typeof window === 'undefined') return
97188

189+
if (DEBUG) {
190+
console.log('[Page] === SAMPLE SELECT ===', newSampleId)
191+
logStorageState('before sample select')
192+
}
193+
98194
try {
99195
const sample = getSampleById(newSampleId)
100196
if (!sample) return
@@ -105,6 +201,10 @@ export default function Page() {
105201
// Get or generate document ID for this demo BEFORE updating state
106202
const docId = getDocumentIdForDemo(newSampleId)
107203

204+
if (DEBUG) {
205+
console.log('[Page] Sample select - setting state:', { newSampleId, docId })
206+
}
207+
108208
// ATOMIC UPDATE: Set both sample and document ID together
109209
// This prevents the iframe from rendering with mismatched data
110210
setCurrentSampleId(newSampleId)
@@ -113,41 +213,61 @@ export default function Page() {
113213
// Update URL after state update
114214
const routePath = sample.metadata.routePath || window.location.pathname
115215
const newUrl = `${routePath}?documentId=${docId}`
116-
216+
117217
if (window.location.href !== window.location.origin + newUrl) {
118218
window.history.pushState({}, '', newUrl)
219+
if (DEBUG) {
220+
console.log('[Page] Updated URL to:', newUrl)
221+
}
222+
}
223+
224+
if (DEBUG) {
225+
logStorageState('after sample select')
119226
}
120227
} catch (error) {
121228
console.error('Error changing sample:', error)
122229
}
123230
}, [currentSampleId, getDocumentIdForDemo])
124231

125-
// Note: URL updates are now handled directly in handleSampleSelect and handleReset
126-
// This effect is removed to prevent duplicate history entries
127-
128232
// Handle reset: generate new document ID for current demo
129233
const handleReset = useCallback(() => {
130234
if (typeof window === 'undefined') return
131235

236+
if (DEBUG) {
237+
console.log('[Page] === RESET ===')
238+
logStorageState('before reset')
239+
}
240+
132241
try {
133242
const sample = getSampleById(currentSampleId)
134243
if (!sample) return
135244

136245
// Generate a new document ID for this specific demo
137246
const newDocId = `doc-${currentSampleId}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`
138-
247+
248+
if (DEBUG) {
249+
console.log('[Page] Generated new documentId for reset:', newDocId)
250+
}
251+
139252
// Update localStorage for this demo
140253
localStorage.setItem(`demo-${currentSampleId}-document-id`, newDocId)
141-
254+
142255
// Update state
143256
setDocumentId(newDocId)
144-
257+
145258
// Update URL
146259
const routePath = sample.metadata.routePath || window.location.pathname
147260
const newUrl = `${routePath}?documentId=${newDocId}`
148-
261+
149262
if (window.location.href !== window.location.origin + newUrl) {
150263
window.history.pushState({}, '', newUrl)
264+
if (DEBUG) {
265+
console.log('[Page] Updated URL to:', newUrl)
266+
}
267+
}
268+
269+
if (DEBUG) {
270+
logStorageState('after reset')
151271
}
152272
} catch (error) {
153273
console.error('Error resetting document:', error)
@@ -174,7 +294,7 @@ export default function Page() {
174294
/>
175295

176296
{/* Main Content */}
177-
<SampleViewer
297+
<SampleViewer
178298
sample={currentSample}
179299
sidebarOpen={sidebarOpen}
180300
onSidebarToggle={() => setSidebarOpen(!sidebarOpen)}
@@ -184,4 +304,3 @@ export default function Page() {
184304
</div>
185305
)
186306
}
187-

0 commit comments

Comments
 (0)