diff --git a/nest-intra/nginx.conf b/nest-intra/nginx.conf
index bf22cad..471887c 100644
--- a/nest-intra/nginx.conf
+++ b/nest-intra/nginx.conf
@@ -8,7 +8,7 @@ server {
set $api_upstream http://api:3000;
location /api/ {
- proxy_pass $api_upstream/api/;
+ proxy_pass $api_upstream;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
diff --git a/nest-intra/src/components/layout/IntranetLayout.tsx b/nest-intra/src/components/layout/IntranetLayout.tsx
index f9067bf..ca5973e 100644
--- a/nest-intra/src/components/layout/IntranetLayout.tsx
+++ b/nest-intra/src/components/layout/IntranetLayout.tsx
@@ -8,7 +8,7 @@ const INTRANET_LINKS = [
{ to: '/intranet/feed', label: 'Team Feed', icon: '[~]', end: false },
{ to: '/intranet/events', label: 'Events', icon: '[E]', end: false },
{ to: '/intranet/users', label: 'Users', icon: '[U]', end: false },
- { to: '/intranet/moderation', label: 'Moderation', icon: '[M]', end: false },
+ { to: '/intranet/moderation', label: 'Forum Mod', icon: '[M]', end: false },
{ to: '/intranet/services', label: 'Services', icon: '[S]', end: false },
];
diff --git a/nest-intra/src/pages/intranet/IntranetBugs.tsx b/nest-intra/src/pages/intranet/IntranetBugs.tsx
index 8894848..e2392dc 100644
--- a/nest-intra/src/pages/intranet/IntranetBugs.tsx
+++ b/nest-intra/src/pages/intranet/IntranetBugs.tsx
@@ -1,6 +1,7 @@
-import { useState, useMemo, useCallback } from 'react';
+import { useState, useMemo, useCallback, useEffect } from 'react';
import { useAuth } from '../../contexts/AuthContext';
import { formatDate, formatDateTime } from '../../utils/format';
+import { settingsApi } from '../../utils/api';
import type { BugReport, BugSeverity, BugStatus, BugReportNote } from '../../types';
function StatusBadge({ status }: { status: BugStatus }) {
@@ -27,6 +28,19 @@ export default function IntranetBugs() {
const [assignedFilter, setAssignedFilter] = useState('all');
const [noteText, setNoteText] = useState('');
const [isEnabled, setIsEnabled] = useState(true);
+ const [toggling, setToggling] = useState(false);
+
+ useEffect(() => {
+ settingsApi.get().then((s) => setIsEnabled(s.bugsEnabled)).catch(() => {});
+ }, []);
+
+ const handleToggle = useCallback((enabled: boolean) => {
+ setToggling(true);
+ settingsApi.update({ bugsEnabled: enabled })
+ .then(() => setIsEnabled(enabled))
+ .catch(() => {})
+ .finally(() => setToggling(false));
+ }, []);
const openCount = bugs.filter((b) => b.status === 'open').length;
const criticalCount = bugs.filter((b) => b.severity === 'critical').length;
@@ -82,7 +96,8 @@ export default function IntranetBugs() {
FUNCTIONALITY DISABLED
Bug Reports feature is currently disabled
setIsEnabled(false)}
+ onClick={() => handleToggle(false)}
+ disabled={toggling}
style={{
background: 'transparent',
border: '1px solid var(--color-red)',
@@ -91,10 +108,11 @@ export default function IntranetModeration() {
padding: '0.3rem 0.7rem',
fontFamily: 'var(--font-mono)',
fontSize: '0.65rem',
- cursor: 'pointer',
+ cursor: toggling ? 'not-allowed' : 'pointer',
textTransform: 'uppercase',
letterSpacing: '0.08em',
height: 'fit-content',
+ opacity: toggling ? 0.6 : 1,
}}
title="Disable this feature"
>
diff --git a/nest-intra/src/utils/api.ts b/nest-intra/src/utils/api.ts
new file mode 100644
index 0000000..eceb8cb
--- /dev/null
+++ b/nest-intra/src/utils/api.ts
@@ -0,0 +1,35 @@
+import { getToken } from '../contexts/AuthContext';
+
+export const API_BASE = (import.meta.env.VITE_API_URL as string | undefined) ?? '/api';
+
+async function apiFetch(path: string, options: RequestInit = {}): Promise {
+ const token = getToken();
+ const headers: Record = {
+ 'Content-Type': 'application/json',
+ ...(options.headers as Record ?? {}),
+ };
+ if (token) headers['Authorization'] = `Bearer ${token}`;
+
+ const res = await fetch(`${API_BASE}${path}`, { ...options, headers });
+
+ if (!res.ok) {
+ const body = await res.json().catch(() => ({})) as { error?: unknown };
+ const message = typeof body.error === 'string' ? body.error : `Request failed (${res.status})`;
+ throw new Error(message);
+ }
+
+ if (res.status === 204) return undefined as T;
+ return res.json() as Promise;
+}
+
+export type SiteSettings = { forumEnabled: boolean; bugsEnabled: boolean };
+
+export const settingsApi = {
+ get: () => apiFetch('/settings'),
+
+ update: (data: Partial) =>
+ apiFetch('/settings', {
+ method: 'PATCH',
+ body: JSON.stringify(data),
+ }),
+};