diff --git a/web-next/app/[locale]/forum/topic/[topicId]/page.tsx b/web-next/app/[locale]/forum/topic/[topicId]/page.tsx
index 3f9271b..2f5a5df 100644
--- a/web-next/app/[locale]/forum/topic/[topicId]/page.tsx
+++ b/web-next/app/[locale]/forum/topic/[topicId]/page.tsx
@@ -1,7 +1,7 @@
import { notFound } from 'next/navigation'
import { getTranslations, setRequestLocale } from 'next-intl/server'
import { Link } from '@/i18n/navigation'
-import { getTopic, getPosts, countPosts } from '@/lib/forum'
+import { getTopic, getPosts, countPosts, listForumsForMove } from '@/lib/forum'
import { getSession } from '@/lib/session'
import { forumIsModerator, canEditPost } from '@/lib/forum-perm'
import { ReplyForm } from '@/components/ReplyForm'
@@ -33,6 +33,7 @@ export default async function TopicPage({
const posts = await getPosts(id, (page - 1) * PER_PAGE, PER_PAGE)
const session = await getSession()
const isMod = await forumIsModerator(session)
+ const moveForums = isMod ? (await listForumsForMove()).filter((f) => f.id !== topic!.forum_id) : []
const canReply = Boolean(session.username) && (!topic!.locked || isMod)
return (
@@ -48,7 +49,9 @@ export default async function TopicPage({
{topic!.name}
- {isMod && }
+ {isMod && (
+
+ )}
{posts.map((post) => (
diff --git a/web-next/app/api/forum/moderate/route.ts b/web-next/app/api/forum/moderate/route.ts
index f742eee..f395dec 100644
--- a/web-next/app/api/forum/moderate/route.ts
+++ b/web-next/app/api/forum/moderate/route.ts
@@ -1,9 +1,9 @@
import { getSession } from '@/lib/session'
-import { getTopic } from '@/lib/forum'
-import { setTopicFlag } from '@/lib/forum-write'
+import { getTopic, getForum } from '@/lib/forum'
+import { setTopicFlag, moveTopic } from '@/lib/forum-write'
import { forumIsModerator } from '@/lib/forum-perm'
-type Action = 'lock' | 'unlock' | 'sticky' | 'unsticky' | 'delete'
+type Action = 'lock' | 'unlock' | 'sticky' | 'unsticky' | 'delete' | 'move'
/** Moderación de temas: bloquear, fijar, borrar. Solo moderadores. */
export async function POST(request: Request) {
@@ -36,6 +36,17 @@ export async function POST(request: Request) {
case 'delete':
await setTopicFlag(topicId, 'deleted', true)
return Response.json({ success: true, forumId: topic.forum_id })
+ case 'move': {
+ const newForumId = Number(b.forumId)
+ if (!newForumId || newForumId === topic.forum_id) {
+ return Response.json({ success: false, error: 'invalidRequest' }, { status: 400 })
+ }
+ if (!(await getForum(newForumId))) {
+ return Response.json({ success: false, error: 'invalidForum' }, { status: 400 })
+ }
+ await moveTopic(topicId, newForumId)
+ return Response.json({ success: true })
+ }
default:
return Response.json({ success: false, error: 'invalidRequest' }, { status: 400 })
}
diff --git a/web-next/components/TopicModBar.tsx b/web-next/components/TopicModBar.tsx
index eb155af..d0240b1 100644
--- a/web-next/components/TopicModBar.tsx
+++ b/web-next/components/TopicModBar.tsx
@@ -8,16 +8,18 @@ export function TopicModBar({
topicId,
locked,
sticky,
+ moveForums = [],
}: {
topicId: number
locked: boolean
sticky: boolean
+ moveForums?: { id: number; name: string }[]
}) {
const t = useTranslations('Forum')
const router = useRouter()
const [busy, setBusy] = useState(false)
- async function act(action: string, confirmMsg?: string) {
+ async function act(action: string, extra?: Record, confirmMsg?: string) {
if (busy) return
if (confirmMsg && !confirm(confirmMsg)) return
setBusy(true)
@@ -26,11 +28,13 @@ export function TopicModBar({
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'same-origin',
- body: JSON.stringify({ topicId, action }),
+ body: JSON.stringify({ topicId, action, ...extra }),
})
const data: { success?: boolean; forumId?: number } = await res.json()
if (data.success && action === 'delete' && data.forumId) {
router.push(`/forum/${data.forumId}`)
+ } else if (data.success && action === 'move') {
+ router.push(`/forum/${extra?.forumId}`)
} else {
router.refresh()
}
@@ -58,9 +62,31 @@ export function TopicModBar({
>
{sticky ? t('unpin') : t('pin')}
+ {moveForums.length > 0 && (
+
+ )}