fix: Demo navigation via history API and route sync.
Replace unreliable pathname assignment with pushState and central route syncing so the demo opens from the login screen and responds to browser back/forward. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+31
-7
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect, useCallback } from 'react'
|
||||||
import './App.css'
|
import './App.css'
|
||||||
import { DialogProvider } from './components/ModalDialog.tsx'
|
import { DialogProvider } from './components/ModalDialog.tsx'
|
||||||
import AuthOnboarding from './components/AuthOnboarding.tsx'
|
import AuthOnboarding from './components/AuthOnboarding.tsx'
|
||||||
@@ -59,7 +59,7 @@ function App() {
|
|||||||
const [shareKey, setShareKey] = useState('')
|
const [shareKey, setShareKey] = useState('')
|
||||||
|
|
||||||
// Public demo mode (no account required)
|
// Public demo mode (no account required)
|
||||||
const [isDemoMode, setIsDemoMode] = useState(false)
|
const [isDemoMode, setIsDemoMode] = useState(() => window.location.pathname === '/demo')
|
||||||
|
|
||||||
const syncQueueCount = useLiveQuery(
|
const syncQueueCount = useLiveQuery(
|
||||||
() => activeLogbookId ? db.syncQueue.where({ logbookId: activeLogbookId }).count() : db.syncQueue.count(),
|
() => activeLogbookId ? db.syncQueue.where({ logbookId: activeLogbookId }).count() : db.syncQueue.count(),
|
||||||
@@ -138,26 +138,37 @@ function App() {
|
|||||||
}
|
}
|
||||||
}, [isAuthenticated])
|
}, [isAuthenticated])
|
||||||
|
|
||||||
useEffect(() => {
|
const syncRouteFromLocation = useCallback(() => {
|
||||||
const params = new URLSearchParams(window.location.search)
|
const params = new URLSearchParams(window.location.search)
|
||||||
const hashParams = new URLSearchParams(window.location.hash.substring(1))
|
const hashParams = new URLSearchParams(window.location.hash.substring(1))
|
||||||
|
const path = window.location.pathname
|
||||||
|
|
||||||
if (window.location.pathname === '/demo') {
|
if (path === '/demo') {
|
||||||
setIsDemoMode(true)
|
setIsDemoMode(true)
|
||||||
|
setIsViewerMode(false)
|
||||||
|
setIsAcceptingInvite(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.location.pathname === '/share' && params.has('token') && hashParams.has('key')) {
|
setIsDemoMode(false)
|
||||||
|
|
||||||
|
if (path === '/share' && params.has('token') && hashParams.has('key')) {
|
||||||
setShareToken(params.get('token') || '')
|
setShareToken(params.get('token') || '')
|
||||||
setShareKey(hashParams.get('key') || '')
|
setShareKey(hashParams.get('key') || '')
|
||||||
setIsViewerMode(true)
|
setIsViewerMode(true)
|
||||||
|
setIsAcceptingInvite(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setIsViewerMode(false)
|
||||||
|
|
||||||
if (params.has('token')) {
|
if (params.has('token')) {
|
||||||
setIsAcceptingInvite(true)
|
setIsAcceptingInvite(true)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setIsAcceptingInvite(false)
|
||||||
|
|
||||||
const savedUser = localStorage.getItem('active_username')
|
const savedUser = localStorage.getItem('active_username')
|
||||||
const key = getActiveMasterKey()
|
const key = getActiveMasterKey()
|
||||||
if (savedUser && key) {
|
if (savedUser && key) {
|
||||||
@@ -171,6 +182,19 @@ function App() {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
syncRouteFromLocation()
|
||||||
|
window.addEventListener('popstate', syncRouteFromLocation)
|
||||||
|
return () => window.removeEventListener('popstate', syncRouteFromLocation)
|
||||||
|
}, [syncRouteFromLocation])
|
||||||
|
|
||||||
|
const openDemo = useCallback(() => {
|
||||||
|
window.history.pushState({}, document.title, '/demo')
|
||||||
|
setIsDemoMode(true)
|
||||||
|
setIsViewerMode(false)
|
||||||
|
setIsAcceptingInvite(false)
|
||||||
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
registerNavigation({
|
registerNavigation({
|
||||||
setActiveTab,
|
setActiveTab,
|
||||||
@@ -245,7 +269,7 @@ function App() {
|
|||||||
|
|
||||||
const handleExitDemo = () => {
|
const handleExitDemo = () => {
|
||||||
window.history.replaceState({}, document.title, '/')
|
window.history.replaceState({}, document.title, '/')
|
||||||
setIsDemoMode(false)
|
syncRouteFromLocation()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDemoMode) {
|
if (isDemoMode) {
|
||||||
@@ -288,7 +312,7 @@ function App() {
|
|||||||
if (!isAuthenticated) {
|
if (!isAuthenticated) {
|
||||||
return (
|
return (
|
||||||
<div className="auth-screen">
|
<div className="auth-screen">
|
||||||
<AuthOnboarding onAuthenticated={handleAuthenticated} />
|
<AuthOnboarding onAuthenticated={handleAuthenticated} onOpenDemo={openDemo} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,10 @@ import RegistrationDisclaimer from './RegistrationDisclaimer.tsx'
|
|||||||
|
|
||||||
interface AuthOnboardingProps {
|
interface AuthOnboardingProps {
|
||||||
onAuthenticated: () => void
|
onAuthenticated: () => void
|
||||||
|
onOpenDemo?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AuthOnboarding({ onAuthenticated }: AuthOnboardingProps) {
|
export default function AuthOnboarding({ onAuthenticated, onOpenDemo }: AuthOnboardingProps) {
|
||||||
const { t, i18n } = useTranslation()
|
const { t, i18n } = useTranslation()
|
||||||
const [username, setUsername] = useState('')
|
const [username, setUsername] = useState('')
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
@@ -526,7 +527,7 @@ export default function AuthOnboarding({ onAuthenticated }: AuthOnboardingProps)
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn secondary"
|
className="btn secondary"
|
||||||
onClick={() => { window.location.pathname = '/demo' }}
|
onClick={() => onOpenDemo?.()}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user