feat: enhance error handling in DashboardPage and add retry functionality
Some checks failed
Frontend CI / lint (push) Failing after 29s
Frontend CI / build (push) Has been skipped

This commit is contained in:
JSC
2025-08-19 21:49:46 +02:00
parent b76b34ea4f
commit 77f24ea4ff
3 changed files with 58 additions and 27 deletions

View File

@@ -145,7 +145,7 @@ function App() {
<AuthProvider> <AuthProvider>
<SocketProvider> <SocketProvider>
<AppRoutes /> <AppRoutes />
<Toaster richColors /> <Toaster richColors position='top-right' />
</SocketProvider> </SocketProvider>
</AuthProvider> </AuthProvider>
</ThemeProvider> </ThemeProvider>

View File

@@ -56,7 +56,7 @@ export function LoadingSkeleton() {
) )
} }
export function ErrorState({ error }: { error: string }) { export function ErrorState({ error, onRetry }: { error: string; onRetry: () => void }) {
return ( return (
<AppLayout <AppLayout
breadcrumb={{ breadcrumb={{
@@ -64,7 +64,7 @@ export function ErrorState({ error }: { error: string }) {
}} }}
> >
<div className="flex-1 rounded-xl bg-muted/50 p-4"> <div className="flex-1 rounded-xl bg-muted/50 p-4">
<DashboardHeader onRefresh={() => {}} isRefreshing={false} /> <DashboardHeader onRefresh={onRetry} isRefreshing={false} />
<div className="border-2 border-dashed border-destructive/25 rounded-lg p-4"> <div className="border-2 border-dashed border-destructive/25 rounded-lg p-4">
<p className="text-destructive">Error loading statistics: {error}</p> <p className="text-destructive">Error loading statistics: {error}</p>
</div> </div>

View File

@@ -46,26 +46,38 @@ export function DashboardPage() {
const fetchStatistics = useCallback(async () => { const fetchStatistics = useCallback(async () => {
try { try {
const [soundboardResponse, trackResponse] = await Promise.all([ setError(null) // Clear previous errors
fetch('/api/v1/dashboard/soundboard-statistics', {
credentials: 'include',
}),
fetch('/api/v1/dashboard/track-statistics', { credentials: 'include' }),
])
if (!soundboardResponse.ok || !trackResponse.ok) { // Fetch soundboard statistics
throw new Error('Failed to fetch statistics') const soundboardResponse = await fetch('/api/v1/dashboard/soundboard-statistics', {
credentials: 'include',
})
if (!soundboardResponse.ok) {
const errorText = await soundboardResponse.text()
throw new Error(`Failed to fetch soundboard statistics: ${errorText}`)
} }
const [soundboardData, trackData] = await Promise.all([ const soundboardData = await soundboardResponse.json()
soundboardResponse.json(),
trackResponse.json(),
])
setSoundboardStatistics(soundboardData) setSoundboardStatistics(soundboardData)
// Fetch track statistics separately to avoid Promise.all failures
const trackResponse = await fetch('/api/v1/dashboard/track-statistics', {
credentials: 'include'
})
if (!trackResponse.ok) {
const errorText = await trackResponse.text()
throw new Error(`Failed to fetch track statistics: ${errorText}`)
}
const trackData = await trackResponse.json()
setTrackStatistics(trackData) setTrackStatistics(trackData)
} catch (err) { } catch (err) {
console.error('Dashboard statistics error:', err)
setError(err instanceof Error ? err.message : 'An error occurred') setError(err instanceof Error ? err.message : 'An error occurred')
// Don't reset the statistics to null on error, keep previous data if available
} }
}, []) }, [])
@@ -125,12 +137,26 @@ export function DashboardPage() {
const refreshAll = useCallback(async () => { const refreshAll = useCallback(async () => {
setRefreshing(true) setRefreshing(true)
try { try {
await Promise.all([fetchStatistics(), fetchTopSounds()]) // Fetch statistics and top sounds sequentially to avoid Promise.all issues
await fetchStatistics()
await fetchTopSounds()
} catch (err) {
console.error('Error during refresh:', err)
} finally { } finally {
setRefreshing(false) setRefreshing(false)
} }
}, [fetchStatistics, fetchTopSounds]) }, [fetchStatistics, fetchTopSounds])
const retryFromError = useCallback(async () => {
setLoading(true)
setError(null)
try {
await fetchStatistics()
} finally {
setLoading(false)
}
}, [fetchStatistics])
useEffect(() => { useEffect(() => {
const loadInitialData = async () => { const loadInitialData = async () => {
setLoading(true) setLoading(true)
@@ -144,14 +170,17 @@ export function DashboardPage() {
loadInitialData() loadInitialData()
}, []) }, [])
// Auto-refresh every 5 seconds // Auto-refresh every 30 seconds (reduced frequency to avoid issues)
useEffect(() => { useEffect(() => {
const interval = setInterval(() => { const interval = setInterval(() => {
// Only auto-refresh if not currently loading or in error state
if (!loading && !refreshing && (!error || (soundboardStatistics && trackStatistics))) {
refreshAll() refreshAll()
}, 5000) }
}, 30000) // Increased to 30 seconds
return () => clearInterval(interval) return () => clearInterval(interval)
}, [refreshAll]) }, [refreshAll, loading, refreshing, error, soundboardStatistics, trackStatistics])
useEffect(() => { useEffect(() => {
fetchTopSounds(true) // Show loading on initial load and filter changes fetchTopSounds(true) // Show loading on initial load and filter changes
@@ -161,8 +190,8 @@ export function DashboardPage() {
return <LoadingSkeleton /> return <LoadingSkeleton />
} }
if (error || !soundboardStatistics || !trackStatistics) { if (error && (!soundboardStatistics || !trackStatistics)) {
return <ErrorState error={error || 'Failed to load statistics'} /> return <ErrorState error={error} onRetry={retryFromError} />
} }
return ( return (
@@ -175,10 +204,12 @@ export function DashboardPage() {
<DashboardHeader onRefresh={refreshAll} isRefreshing={refreshing} /> <DashboardHeader onRefresh={refreshAll} isRefreshing={refreshing} />
<div className="space-y-6"> <div className="space-y-6">
{soundboardStatistics && trackStatistics && (
<StatisticsGrid <StatisticsGrid
soundboardStatistics={soundboardStatistics} soundboardStatistics={soundboardStatistics}
trackStatistics={trackStatistics} trackStatistics={trackStatistics}
/> />
)}
<TopSoundsSection <TopSoundsSection
topSounds={topSounds} topSounds={topSounds}