Files
resolutionflow/frontend/src/components/common/ErrorBoundary.tsx
chihlasm 48f2b3faaf fix: stale chunk auto-reload + image paste upload UX
- Add lazyWithRetry wrapper for all lazy-loaded routes to auto-reload
  on stale chunk errors after deploys (prevents ErrorBoundary flash)
- Show toast notification when image paste/upload fails due to storage
  not configured (503), instead of silent tiny error thumbnails
- Remove failed uploads from thumbnail strip on 503 (was showing
  confusing retry icon)
- Pass completed upload IDs in navigation state from dashboard input
- Suppress Sentry dialog for chunk load errors (deploy artifacts)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 04:21:41 +00:00

88 lines
2.6 KiB
TypeScript

import * as Sentry from '@sentry/react'
import { type ReactNode, useEffect, useRef } from 'react'
import { Button } from '@/components/ui/Button'
interface FallbackProps {
error: Error
resetError: () => void
}
function isChunkLoadError(error: Error): boolean {
const msg = error.message || ''
return (
msg.includes('dynamically imported module') ||
msg.includes('Loading chunk') ||
msg.includes('Failed to fetch') ||
error.name === 'ChunkLoadError'
)
}
function DefaultFallback({ error, resetError }: FallbackProps) {
const reloadingRef = useRef(false)
// Auto-reload on stale chunk errors (happens after deployments)
useEffect(() => {
if (!isChunkLoadError(error)) return
const key = 'rf_boundary_chunk_reload'
const lastReload = sessionStorage.getItem(key)
const now = Date.now()
if (!lastReload || now - Number(lastReload) > 10_000) {
sessionStorage.setItem(key, String(now))
reloadingRef.current = true
window.location.reload()
}
}, [error])
return (
<div className="flex min-h-[400px] flex-col items-center justify-center p-8">
<div className="max-w-md text-center">
<h2 className="mb-2 text-xl font-semibold text-red-400">
Something went wrong
</h2>
<p className="mb-4 text-muted-foreground">
An unexpected error occurred. Please try refreshing the page.
</p>
<pre className="mb-4 overflow-auto rounded-xl bg-white/5 border border-border p-3 text-left text-xs text-red-400">
{error.message}
</pre>
<div className="flex justify-center gap-3">
<Button variant="secondary" onClick={resetError}>
Try Again
</Button>
<Button onClick={() => window.location.reload()}>
Refresh Page
</Button>
</div>
</div>
</div>
)
}
interface Props {
children: ReactNode
fallback?: ReactNode
}
export function ErrorBoundary({ children, fallback }: Props) {
return (
<Sentry.ErrorBoundary
fallback={({ error, resetError }) => {
if (fallback) return fallback as React.ReactElement
return <DefaultFallback error={error as Error} resetError={resetError} />
}}
beforeCapture={(scope, error) => {
// Don't report chunk load errors to Sentry — they're deploy artifacts, not bugs
if (error && isChunkLoadError(error as Error)) {
scope.setLevel('info')
scope.setTag('chunk_load_error', 'true')
}
}}
showDialog={false}
>
{children}
</Sentry.ErrorBoundary>
)
}
export default ErrorBoundary