fix admin exit not redirecting, my posts crash, add error boundary
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
import { useState, useEffect, useRef, Component, type ReactNode, type ErrorInfo } from 'react'
|
||||
import { BrowserRouter, Routes, Route, useLocation, useNavigate, Link } from 'react-router-dom'
|
||||
import { IconShieldCheck, IconArrowRight, IconX, IconSearch, IconChevronUp, IconMessageCircle, IconBug, IconBulb, IconCommand, IconArrowNarrowRight } from '@tabler/icons-react'
|
||||
import { AuthProvider, useAuthState } from './hooks/useAuth'
|
||||
@@ -45,6 +45,26 @@ import ProfilePage from './pages/ProfilePage'
|
||||
import RecoverPage from './pages/RecoverPage'
|
||||
import EmbedBoard from './pages/EmbedBoard'
|
||||
import { api } from './lib/api'
|
||||
|
||||
class ErrorBoundary extends Component<{ children: ReactNode }, { error: Error | null }> {
|
||||
state = { error: null as Error | null }
|
||||
static getDerivedStateFromError(error: Error) { return { error } }
|
||||
componentDidCatch(error: Error, info: ErrorInfo) { console.error('React error:', error, info) }
|
||||
render() {
|
||||
if (this.state.error) {
|
||||
return (
|
||||
<div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'var(--bg)', padding: 24 }}>
|
||||
<div style={{ textAlign: 'center', maxWidth: 400 }}>
|
||||
<h1 style={{ fontFamily: 'var(--font-heading)', fontSize: '1.5rem', color: 'var(--text)', marginBottom: 8 }}>Something went wrong</h1>
|
||||
<p style={{ color: 'var(--text-secondary)', fontSize: '0.875rem', marginBottom: 16 }}>{this.state.error.message}</p>
|
||||
<button onClick={() => { this.setState({ error: null }); window.location.href = '/' }} className="btn btn-primary">Go home</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return this.props.children
|
||||
}
|
||||
}
|
||||
import BoardIcon from './components/BoardIcon'
|
||||
import StatusBadge from './components/StatusBadge'
|
||||
import Avatar from './components/Avatar'
|
||||
@@ -348,16 +368,16 @@ function SearchPage() {
|
||||
}
|
||||
|
||||
function RequireAdmin({ children }: { children: React.ReactNode }) {
|
||||
const [ok, setOk] = useState<boolean | null>(null)
|
||||
const admin = useAdmin()
|
||||
const nav = useNavigate()
|
||||
|
||||
useEffect(() => {
|
||||
api.get('/admin/boards')
|
||||
.then(() => setOk(true))
|
||||
.catch(() => nav('/admin/login', { replace: true }))
|
||||
}, [nav])
|
||||
if (!admin.loading && !admin.isAdmin) {
|
||||
nav('/', { replace: true })
|
||||
}
|
||||
}, [admin.loading, admin.isAdmin, nav])
|
||||
|
||||
if (!ok) return null
|
||||
if (admin.loading || !admin.isAdmin) return null
|
||||
return <>{children}</>
|
||||
}
|
||||
|
||||
@@ -407,7 +427,7 @@ function AdminBanner() {
|
||||
Admin panel <IconArrowRight size={11} stroke={2.5} />
|
||||
</Link>
|
||||
<button
|
||||
onClick={admin.exitAdminMode}
|
||||
onClick={() => { admin.exitAdminMode(); window.location.href = '/' }}
|
||||
className="inline-flex items-center gap-1 px-2.5 py-1 rounded"
|
||||
style={{
|
||||
color: 'var(--text-tertiary)',
|
||||
@@ -545,6 +565,7 @@ export default function App() {
|
||||
}, [auth.user?.isPasskeyUser])
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<BrandingProvider>
|
||||
<ToastProvider>
|
||||
<ConfirmProvider>
|
||||
@@ -565,5 +586,6 @@ export default function App() {
|
||||
</ConfirmProvider>
|
||||
</ToastProvider>
|
||||
</BrandingProvider>
|
||||
</ErrorBoundary>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -41,8 +41,8 @@ export default function MySubmissions() {
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
api.get<Post[]>('/me/posts')
|
||||
.then(setPosts)
|
||||
api.get<{ posts: Post[] }>('/me/posts')
|
||||
.then((r) => setPosts(r.posts ?? []))
|
||||
.catch(() => {})
|
||||
.finally(() => setLoading(false))
|
||||
}, [])
|
||||
|
||||
Reference in New Issue
Block a user