diff --git a/webapp/src/App.tsx b/webapp/src/App.tsx index 9801c63..2bd34db 100644 --- a/webapp/src/App.tsx +++ b/webapp/src/App.tsx @@ -30,7 +30,7 @@ import { parseSignalRTextFrames, readInviteCodeFromUrl, } from '@/lib/app-support'; -import { preloadAuthenticatedWorkspace } from '@/lib/app-preload'; +import { preloadAuthenticatedWorkspace, preloadDemoExperience } from '@/lib/app-preload'; import { bootstrapAppSession, type CompletedLogin, @@ -960,6 +960,11 @@ export default function App() { staleTime: 30_000, }); + useEffect(() => { + if (!IS_DEMO_MODE) return; + return preloadDemoExperience(); + }, []); + useEffect(() => { if (IS_DEMO_MODE) return; if (phase !== 'app' || !vaultInitialDecryptDone) return; diff --git a/webapp/src/lib/app-preload.ts b/webapp/src/lib/app-preload.ts index 780c2a2..2b448b6 100644 --- a/webapp/src/lib/app-preload.ts +++ b/webapp/src/lib/app-preload.ts @@ -1,5 +1,6 @@ let workspacePreload: Promise | null = null; let adminPreload: Promise | null = null; +let demoExperiencePreloadStarted = false; export function preloadAuthenticatedWorkspace(isAdmin: boolean): Promise { if (!workspacePreload) { @@ -25,3 +26,48 @@ export function preloadAuthenticatedWorkspace(isAdmin: boolean): Promise void { + if (demoExperiencePreloadStarted || typeof window === 'undefined') { + return () => undefined; + } + + demoExperiencePreloadStarted = true; + let cancelled = false; + let timerId: number | null = null; + + const tasks = [ + () => import('@/components/VaultPage'), + () => import('@/components/SendsPage'), + () => import('@/components/TotpCodesPage'), + () => import('@/components/SettingsPage'), + () => import('@/components/SecurityDevicesPage'), + () => import('@/components/AdminPage'), + () => import('@/components/BackupCenterPage'), + () => import('@/components/ImportPage'), + ]; + + const wait = (ms: number) => new Promise((resolve) => { + timerId = window.setTimeout(() => { + timerId = null; + resolve(); + }, ms); + }); + + void (async () => { + await wait(120); + for (const task of tasks) { + if (cancelled) return; + await task().catch(() => undefined); + await wait(180); + } + })(); + + return () => { + cancelled = true; + if (timerId !== null) { + window.clearTimeout(timerId); + timerId = null; + } + }; +}