Spaces:
Running
Running
File size: 2,746 Bytes
be54038 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | import { useEffect, useState } from 'react'
import { useNavigate, useParams } from 'react-router-dom'
import { api } from './api'
import { ReviewDashboard } from './ReviewDashboard'
import { useStore } from './store'
/**
* Route: /session/:sessionId
*
* Loads session data from the API on mount so the page survives a hard refresh
* or a direct link (e.g. from a blog post). If the session ID is not found the
* user is redirected back to the upload page with a clear error message.
*/
export function SessionPage() {
const { sessionId } = useParams<{ sessionId: string }>()
const navigate = useNavigate()
const setSession = useStore((s) => s.setSession)
const sessionData = useStore((s) => s.sessionData)
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
if (!sessionId) {
navigate('/')
return
}
// If the store already has data for this exact session (just navigated from
// the upload page), skip the API call.
if (sessionData?.session_id === sessionId) return
setLoading(true)
api.getSession(sessionId)
.then((data) => {
setSession(data)
setLoading(false)
})
.catch(() => {
setError(`Session "${sessionId.slice(0, 8)}…" not found or has expired.`)
setLoading(false)
})
}, [sessionId]) // eslint-disable-line react-hooks/exhaustive-deps
if (loading) {
return (
<div className="min-h-screen flex items-center justify-center" style={{ backgroundColor: '#f8fafc' }}>
<div className="text-center space-y-3">
<svg className="animate-spin h-8 w-8 mx-auto" viewBox="0 0 24 24" fill="none"
style={{ color: '#008080' }}>
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8z" />
</svg>
<p className="text-sm text-gray-500">Loading session…</p>
</div>
</div>
)
}
if (error) {
return (
<div className="min-h-screen flex items-center justify-center" style={{ backgroundColor: '#f8fafc' }}>
<div className="text-center space-y-4 max-w-sm">
<p className="text-sm text-red-600 bg-red-50 border border-red-200 rounded-xl px-4 py-3">
{error}
</p>
<button
onClick={() => navigate('/')}
className="text-sm font-medium underline"
style={{ color: '#2563EB' }}
>
← Back to upload
</button>
</div>
</div>
)
}
if (!sessionId) return null
return <ReviewDashboard sessionId={sessionId} />
}
|