Skip to content

Commit de7dbcf

Browse files
committed
Merge branch 'main' of github.com:velt-js/sample-apps into rg/action-composer-modal
2 parents 84eedcc + e78ea41 commit de7dbcf

File tree

20 files changed

+141
-114
lines changed

20 files changed

+141
-114
lines changed

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

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,24 @@ export default function Page() {
1212
const [documentId, setDocumentId] = useState<string>('')
1313
const [isMounted, setIsMounted] = useState(false)
1414
const isInitialized = useRef(false)
15-
15+
1616
const currentSample = getSampleById(currentSampleId) || getDefaultSample()
1717

1818
// Helper function to get document ID for a specific demo
1919
const getDocumentIdForDemo = useCallback((demoId: string): string => {
2020
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`)
21+
22+
const storageKey = `demo-${demoId}-document-id`
23+
const stored = localStorage.getItem(storageKey)
24+
2425
if (stored) {
2526
return stored
2627
}
27-
28+
2829
// Generate a new document ID for this demo
2930
const newDocId = `doc-${demoId}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`
30-
localStorage.setItem(`demo-${demoId}-document-id`, newDocId)
31+
localStorage.setItem(storageKey, newDocId)
32+
3133
return newDocId
3234
}, [])
3335

@@ -113,7 +115,7 @@ export default function Page() {
113115
// Update URL after state update
114116
const routePath = sample.metadata.routePath || window.location.pathname
115117
const newUrl = `${routePath}?documentId=${docId}`
116-
118+
117119
if (window.location.href !== window.location.origin + newUrl) {
118120
window.history.pushState({}, '', newUrl)
119121
}
@@ -122,9 +124,6 @@ export default function Page() {
122124
}
123125
}, [currentSampleId, getDocumentIdForDemo])
124126

125-
// Note: URL updates are now handled directly in handleSampleSelect and handleReset
126-
// This effect is removed to prevent duplicate history entries
127-
128127
// Handle reset: generate new document ID for current demo
129128
const handleReset = useCallback(() => {
130129
if (typeof window === 'undefined') return
@@ -135,17 +134,17 @@ export default function Page() {
135134

136135
// Generate a new document ID for this specific demo
137136
const newDocId = `doc-${currentSampleId}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`
138-
137+
139138
// Update localStorage for this demo
140139
localStorage.setItem(`demo-${currentSampleId}-document-id`, newDocId)
141-
140+
142141
// Update state
143142
setDocumentId(newDocId)
144-
143+
145144
// Update URL
146145
const routePath = sample.metadata.routePath || window.location.pathname
147146
const newUrl = `${routePath}?documentId=${newDocId}`
148-
147+
149148
if (window.location.href !== window.location.origin + newUrl) {
150149
window.history.pushState({}, '', newUrl)
151150
}
@@ -174,7 +173,7 @@ export default function Page() {
174173
/>
175174

176175
{/* Main Content */}
177-
<SampleViewer
176+
<SampleViewer
178177
sample={currentSample}
179178
sidebarOpen={sidebarOpen}
180179
onSidebarToggle={() => setSidebarOpen(!sidebarOpen)}
@@ -184,4 +183,3 @@ export default function Page() {
184183
</div>
185184
)
186185
}
187-
Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client"
22

3-
import { useState } from "react"
3+
import { useState, useRef } from "react"
44

55
interface IframePairProps {
66
url?: string
@@ -15,11 +15,12 @@ export function IframePair({
1515
height = "982px",
1616
displayMode = 'dual'
1717
}: IframePairProps) {
18-
const [isLoading1, setIsLoading1] = useState(true)
19-
const [isLoading2, setIsLoading2] = useState(true)
2018
const [error1, setError1] = useState(false)
2119
const [error2, setError2] = useState(false)
2220

21+
const iframe1Ref = useRef<HTMLIFrameElement>(null)
22+
const iframe2Ref = useRef<HTMLIFrameElement>(null)
23+
2324
// Safety check: don't render if URL is not provided
2425
if (!url) {
2526
return (
@@ -31,22 +32,10 @@ export function IframePair({
3132

3233
const finalSecondUrl = secondUrl || url
3334

34-
const handleIframeLoad = (iframeNum: number) => {
35-
if (iframeNum === 1) {
36-
setIsLoading1(false)
37-
setError1(false)
38-
} else {
39-
setIsLoading2(false)
40-
setError2(false)
41-
}
42-
}
43-
4435
const handleIframeError = (iframeNum: number) => {
4536
if (iframeNum === 1) {
46-
setIsLoading1(false)
4737
setError1(true)
4838
} else {
49-
setIsLoading2(false)
5039
setError2(true)
5140
}
5241
}
@@ -56,23 +45,18 @@ export function IframePair({
5645
return (
5746
<div className="h-full relative">
5847
<div className="rounded-lg border border-border bg-card overflow-hidden h-full">
59-
{isLoading1 && !error1 && (
60-
<div className="absolute inset-0 flex items-center justify-center bg-background/80 z-10">
61-
<div className="text-muted-foreground">Loading demo...</div>
62-
</div>
63-
)}
6448
{error1 && (
6549
<div className="absolute inset-0 flex items-center justify-center bg-background/80 z-10">
6650
<div className="text-destructive">Failed to load demo</div>
6751
</div>
6852
)}
6953
<iframe
54+
ref={iframe1Ref}
7055
src={url}
7156
className="w-full h-full"
7257
style={{ maxHeight: height }}
7358
title="Demo"
7459
sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"
75-
onLoad={() => handleIframeLoad(1)}
7660
onError={() => handleIframeError(1)}
7761
/>
7862
</div>
@@ -84,48 +68,37 @@ export function IframePair({
8468
return (
8569
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 h-full">
8670
<div className="rounded-lg border border-border bg-card overflow-hidden relative">
87-
{isLoading1 && !error1 && (
88-
<div className="absolute inset-0 flex items-center justify-center bg-background/80 z-10">
89-
<div className="text-muted-foreground text-sm">Loading demo 1...</div>
90-
</div>
91-
)}
9271
{error1 && (
9372
<div className="absolute inset-0 flex items-center justify-center bg-background/80 z-10">
9473
<div className="text-destructive text-sm">Failed to load demo 1</div>
9574
</div>
9675
)}
9776
<iframe
77+
ref={iframe1Ref}
9878
src={url}
9979
className="w-full h-full"
10080
style={{ maxHeight: height }}
10181
title="Demo 1"
10282
sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"
103-
onLoad={() => handleIframeLoad(1)}
10483
onError={() => handleIframeError(1)}
10584
/>
10685
</div>
10786
<div className="rounded-lg border border-border bg-card overflow-hidden relative">
108-
{isLoading2 && !error2 && (
109-
<div className="absolute inset-0 flex items-center justify-center bg-background/80 z-10">
110-
<div className="text-muted-foreground text-sm">Loading demo 2...</div>
111-
</div>
112-
)}
11387
{error2 && (
11488
<div className="absolute inset-0 flex items-center justify-center bg-background/80 z-10">
11589
<div className="text-destructive text-sm">Failed to load demo 2</div>
11690
</div>
11791
)}
11892
<iframe
93+
ref={iframe2Ref}
11994
src={finalSecondUrl}
12095
className="w-full h-full"
12196
style={{ maxHeight: height }}
12297
title="Demo 2"
12398
sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"
124-
onLoad={() => handleIframeLoad(2)}
12599
onError={() => handleIframeError(2)}
126100
/>
127101
</div>
128102
</div>
129103
)
130104
}
131-

apps/master-sample-app/components/viewer/sample-viewer.tsx

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ export function SampleViewer({ sample, sidebarOpen, onSidebarToggle, documentId,
3737
// Don't render iframes until documentId is ready AND URLs are computed
3838
const isReady = !!documentId && !!iframeUrl
3939

40+
// IMPORTANT: Key should NOT include documentId to prevent remounts
41+
// Only remount when sample changes, not when documentId changes
42+
const iframeKey = sample.metadata.id
43+
4044
return (
4145
<div
4246
className="flex flex-1 flex-col transition-all duration-150 ease-in-out"
@@ -45,18 +49,18 @@ export function SampleViewer({ sample, sidebarOpen, onSidebarToggle, documentId,
4549
}}
4650
>
4751
{/* Top Bar */}
48-
<TopBar
49-
mode={mode}
50-
onModeChange={setMode}
51-
sidebarOpen={sidebarOpen}
52-
onSidebarToggle={onSidebarToggle}
53-
title={sample.metadata.title}
54-
githubUrl={sample.metadata.githubUrl}
55-
routePath={sample.metadata.routePath}
56-
documentId={documentId}
57-
onReset={onReset}
58-
iframeUrl={iframeUrl}
59-
/>
52+
<TopBar
53+
mode={mode}
54+
onModeChange={setMode}
55+
sidebarOpen={sidebarOpen}
56+
onSidebarToggle={onSidebarToggle}
57+
title={sample.metadata.title}
58+
githubUrl={sample.metadata.githubUrl}
59+
routePath={sample.metadata.routePath}
60+
documentId={documentId}
61+
onReset={onReset}
62+
iframeUrl={iframeUrl}
63+
/>
6064

6165
{/* Content Area */}
6266
<main className="flex-1 overflow-hidden p-4">
@@ -70,7 +74,7 @@ export function SampleViewer({ sample, sidebarOpen, onSidebarToggle, documentId,
7074
secondUrl={iframeUrl2}
7175
height="calc(100vh - 88px)"
7276
displayMode={sample.metadata.displayMode || 'dual'}
73-
key={`${sample.metadata.id}-${documentId}`}
77+
key={iframeKey}
7478
/>
7579
) : (
7680
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 h-full">
@@ -86,12 +90,11 @@ export function SampleViewer({ sample, sidebarOpen, onSidebarToggle, documentId,
8690
secondUrl={iframeUrl2}
8791
height="100%"
8892
displayMode={sample.metadata.displayMode || 'dual'}
89-
key={`${sample.metadata.id}-${documentId}`}
93+
key={`${iframeKey}-code`}
9094
/>
9195
</div>
9296
)}
9397
</main>
9498
</div>
9599
)
96100
}
97-
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22
import { useEffect } from 'react';
3-
import { useSetDocuments } from '@veltdev/react';
3+
import { useSetDocuments, useCurrentUser } from '@veltdev/react';
44
import { useCurrentDocument } from '@/app/document/useCurrentDocument';
55
import { useAppUser } from '@/app/userAuth/useAppUser';
66

@@ -11,13 +11,16 @@ export default function VeltInitializeDocument() {
1111
// [Velt] Get document setter hook
1212
const { setDocuments } = useSetDocuments();
1313

14+
// [Velt] Wait for Velt user to be authenticated before setting document
15+
const veltUser = useCurrentUser();
16+
1417
// [Velt] Set document in Velt. This is the resource where all Velt collaboration data will be scoped.
1518
useEffect(() => {
16-
if (!user || !documentId || !documentName) return;
19+
if (!veltUser || !user || !documentId || !documentName) return;
1720
setDocuments([
1821
{ id: documentId, metadata: { documentName: documentName || 'Untitled' } },
1922
]);
20-
}, [user, setDocuments, documentId, documentName]);
23+
}, [veltUser, user, setDocuments, documentId, documentName]);
2124

2225
return null;
2326
}
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22
import { useEffect } from 'react';
3-
import { useSetDocuments } from '@veltdev/react';
3+
import { useSetDocuments, useCurrentUser } from '@veltdev/react';
44
import { useCurrentDocument } from '@/app/document/useCurrentDocument';
55

66
export default function VeltInitializeDocument() {
@@ -9,14 +9,17 @@ export default function VeltInitializeDocument() {
99
// [Velt] Get document setter hook
1010
const { setDocuments } = useSetDocuments();
1111

12+
// [Velt] Wait for Velt user to be authenticated before setting document
13+
const veltUser = useCurrentUser();
14+
1215
// [Velt] Set document in Velt. This is the resource where all Velt collaboration data will be scoped.
1316
useEffect(() => {
14-
if (!documentId || !documentName) return;
17+
if (!veltUser || !documentId || !documentName) return;
1518

1619
setDocuments([
1720
{ id: documentId, metadata: { documentName: documentName } },
1821
]);
19-
}, [setDocuments, documentId, documentName]);
22+
}, [veltUser, setDocuments, documentId, documentName]);
2023

2124
return null;
2225
}
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
"use client";
22
import { useEffect } from 'react';
3-
import { useSetDocuments } from '@veltdev/react';
3+
import { useSetDocuments, useCurrentUser } from '@veltdev/react';
44
import { useJobs, JOBS_LIST_DOCUMENT_ID, JOBS_LIST_DOCUMENT_NAME } from '@/app/document/JobsContext';
55

66
export default function VeltInitializeDocument() {
77
// [Velt] Get document setter hook
88
const { setDocuments } = useSetDocuments();
99

10+
// [Velt] Wait for Velt user to be authenticated before setting document
11+
const veltUser = useCurrentUser();
12+
1013
// [Velt] Get the selected job and page state
1114
const { selectedJob, isOnJobsListPage } = useJobs();
1215

1316
// [Velt] Set document in Velt based on current page
1417
useEffect(() => {
18+
if (!veltUser) return;
1519
if (isOnJobsListPage) {
1620
setDocuments([
1721
{ id: JOBS_LIST_DOCUMENT_ID, metadata: { documentName: JOBS_LIST_DOCUMENT_NAME } },
@@ -21,7 +25,7 @@ export default function VeltInitializeDocument() {
2125
{ id: selectedJob.id, metadata: { documentName: selectedJob.jobName } },
2226
]);
2327
}
24-
}, [setDocuments, isOnJobsListPage, selectedJob]);
28+
}, [veltUser, setDocuments, isOnJobsListPage, selectedJob]);
2529

2630
return null;
2731
}
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
"use client";
22
import { useEffect } from 'react';
3-
import { useSetDocuments } from '@veltdev/react';
3+
import { useSetDocuments, useCurrentUser } from '@veltdev/react';
44
import { useJobs, JOBS_LIST_DOCUMENT_ID, JOBS_LIST_DOCUMENT_NAME } from '@/app/document/JobsContext';
55

66
export default function VeltInitializeDocument() {
77
// [Velt] Get document setter hook
88
const { setDocuments } = useSetDocuments();
99

10+
// [Velt] Wait for Velt user to be authenticated before setting document
11+
const veltUser = useCurrentUser();
12+
1013
// [Velt] Get the selected job and page state
1114
const { selectedJob, isOnJobsListPage } = useJobs();
1215

1316
// [Velt] Set document in Velt based on current page
1417
useEffect(() => {
18+
if (!veltUser) return;
1519
if (isOnJobsListPage) {
1620
setDocuments([
1721
{ id: JOBS_LIST_DOCUMENT_ID, metadata: { documentName: JOBS_LIST_DOCUMENT_NAME } },
@@ -21,7 +25,7 @@ export default function VeltInitializeDocument() {
2125
{ id: selectedJob.id, metadata: { documentName: selectedJob.jobName } },
2226
]);
2327
}
24-
}, [setDocuments, isOnJobsListPage, selectedJob]);
28+
}, [veltUser, setDocuments, isOnJobsListPage, selectedJob]);
2529

2630
return null;
2731
}

0 commit comments

Comments
 (0)