diff --git a/nest-front/src/App.tsx b/nest-front/src/App.tsx index 8af3f33..751d5ec 100644 --- a/nest-front/src/App.tsx +++ b/nest-front/src/App.tsx @@ -1,6 +1,7 @@ import { lazy, Suspense } from 'react'; import { Routes, Route } from 'react-router-dom'; import { AuthProvider } from './contexts/AuthContext'; +import { SettingsProvider, useSettings } from './contexts/SettingsContext'; import { ProtectedRoute } from './components/shared/ProtectedRoute'; import { PublicLayout } from './components/layout/PublicLayout'; import { PageLoader } from './components/shared/PageLoader'; @@ -19,36 +20,49 @@ const LoginPage = lazy(() => import('./pages/public/LoginPage')); const RegisterPage = lazy(() => import('./pages/public/RegisterPage')); const NotFoundPage = lazy(() => import('./pages/public/NotFoundPage')); +// ── Routes (needs SettingsContext) ──────────────────────────────────────────── + +function AppRoutes() { + const { forumEnabled, bugsEnabled, loaded } = useSettings(); + + if (!loaded) return ; + + return ( + }> + + }> + } /> + } /> + } /> + : } /> + : } /> + : } /> + : } /> + + + + } + /> + } /> + } /> + } /> + + + + ); +} + // ── App ──────────────────────────────────────────────────────────────────────── export default function App() { return ( - }> - - {/* Public Routes */} - }> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - - - } - /> - } /> - } /> - } /> - - - + + + ); } diff --git a/nest-front/src/pages/public/BugDetailPage.tsx b/nest-front/src/pages/public/BugDetailPage.tsx index 9e03630..3908774 100644 --- a/nest-front/src/pages/public/BugDetailPage.tsx +++ b/nest-front/src/pages/public/BugDetailPage.tsx @@ -88,7 +88,7 @@ export default function BugDetailPage() { }, [id]); const alreadyVoted = useMemo( - () => !!user && !!bug && bug.meTooBugs.includes(user.id), + () => !!user && !!bug && (bug.meTooBugs ?? []).includes(user.id), [user, bug] ); const isOwnReport = useMemo( @@ -100,7 +100,7 @@ export default function BugDetailPage() { if (!user || !bug || alreadyVoted || isOwnReport) return; try { await bugsApi.toggleMeToo(bug.id); - setBug((prev) => prev ? { ...prev, meTooBugs: [...prev.meTooBugs, user.id] } : prev); + setBug((prev) => prev ? { ...prev, meTooBugs: [...(prev.meTooBugs ?? []), user.id] } : prev); } catch { // silently ignore } @@ -137,7 +137,7 @@ export default function BugDetailPage() { return ; } - const metooCount = bug.meTooBugs.length; + const metooCount = (bug.meTooBugs ?? []).length; return (
diff --git a/nest-front/src/pages/public/BugReportPage.tsx b/nest-front/src/pages/public/BugReportPage.tsx index 2cf538b..2604b52 100644 --- a/nest-front/src/pages/public/BugReportPage.tsx +++ b/nest-front/src/pages/public/BugReportPage.tsx @@ -1,6 +1,6 @@ import { useState, useMemo, useCallback, useEffect } from 'react'; import { Link, useNavigate } from 'react-router-dom'; -import { bugsApi, settingsApi } from '../../utils/api'; +import { bugsApi } from '../../utils/api'; import { useAuth } from '../../contexts/AuthContext'; import { timeAgo } from '../../utils/format'; import type { BugReport, BugSeverity, BugStatus, BugReportFormData } from '../../types'; @@ -78,7 +78,7 @@ function BugCard({ bug, highlight }: BugCardProps) { borderRadius: '3px', }} > - ▶ {bug.meTooBugs.length} {bug.meTooBugs.length === 1 ? 'user' : 'users'} have this + ▶ {(bug.meTooBugs ?? []).length} {(bug.meTooBugs ?? []).length === 1 ? 'user' : 'users'} have this
@@ -278,19 +278,14 @@ export default function BugReportPage() { const { user, isAuthenticated } = useAuth(); const [bugs, setBugs] = useState([]); const [loading, setLoading] = useState(true); - const [bugsEnabled, setBugsEnabled] = useState(true); const [statusFilter, setStatusFilter] = useState('all'); const [severityFilter, setSeverityFilter] = useState('all'); const [showForm, setShowForm] = useState(false); - useEffect(() => { - settingsApi.get().then((s) => setBugsEnabled(s.bugsEnabled)).catch(() => {}); - }, []); - const fetchBugs = useCallback(() => { setLoading(true); bugsApi.getBugs({ status: statusFilter, severity: severityFilter, limit: 100 }) - .then((res) => setBugs(res.data)) + .then((res) => setBugs(Array.isArray(res?.data) ? res.data : [])) .catch(() => setBugs([])) .finally(() => setLoading(false)); }, [statusFilter, severityFilter]); @@ -300,7 +295,7 @@ export default function BugReportPage() { const { myBugs, otherBugs } = useMemo(() => { const my: BugReport[] = []; const other: BugReport[] = []; - bugs.forEach((b) => { + (bugs ?? []).forEach((b) => { if (user && b.submittedById === user.id) my.push(b); else other.push(b); }); @@ -317,20 +312,6 @@ export default function BugReportPage() { const inProgressCount = bugs.filter((b) => b.status === 'in_progress').length; const resolvedCount = bugs.filter((b) => b.status === 'resolved').length; - if (!bugsEnabled) { - return ( -
-
Issue Tracker
-

- BUG REPORTS UNAVAILABLE -

-

- Bug reporting has been temporarily disabled by an administrator. -

-
- ); - } - return (
{/* Header */} diff --git a/nest-front/src/pages/public/ForumPage.tsx b/nest-front/src/pages/public/ForumPage.tsx index 705499c..530f5d2 100644 --- a/nest-front/src/pages/public/ForumPage.tsx +++ b/nest-front/src/pages/public/ForumPage.tsx @@ -1,6 +1,6 @@ import { useEffect, useMemo, useState } from 'react'; import { Link } from 'react-router-dom'; -import { forumApi, settingsApi } from '../../utils/api'; +import { forumApi } from '../../utils/api'; import { timeAgo } from '../../utils/format'; import type { ForumCategory, ForumThread } from '../../types'; @@ -132,20 +132,17 @@ export default function ForumPage() { const [threads, setThreads] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); - const [forumEnabled, setForumEnabled] = useState(true); useEffect(() => { let cancelled = false; setLoading(true); Promise.all([ - settingsApi.get(), forumApi.getCategories(), forumApi.getThreads({ limit: 200 }), ]) - .then(([settings, cats, threadRes]) => { + .then(([cats, threadRes]) => { if (cancelled) return; - setForumEnabled(settings.forumEnabled); setCategories(cats); setThreads(threadRes.data); }) @@ -169,20 +166,6 @@ export default function ForumPage() { ); }, [search, categories, threads]); - if (!loading && !forumEnabled) { - return ( -
-
Community
-

- FORUM UNAVAILABLE -

-

- The forum has been temporarily disabled by an administrator. -

-
- ); - } - return (
{/* Header */}