forum: drop Recent Threads widget, surface last post inline on category cards

Per Ryan — category drill-down already shows newest-first ordering so
the standalone Recent Threads list was redundant. Each category card now
shows "Last post: <title> · <relative time>" below the description so
glanceable activity stays on the landing page. Categories API joins one
latest thread per category in a single round-trip (in_ + limit + group
in memory) instead of N+1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ryan Salazar
2026-05-28 22:14:50 +00:00
parent 52d5029eed
commit 077f146eda
2 changed files with 46 additions and 34 deletions

View File

@@ -4,13 +4,42 @@ import { createClient } from '@/lib/supabase/server';
export async function GET() {
try {
const supabase = await createClient();
const { data, error } = await supabase
const { data: cats, error } = await supabase
.from('forum_categories')
.select('*')
.order('display_order', { ascending: true });
if (error) throw error;
return NextResponse.json({ categories: data });
// Latest thread per category — joined client-side so we keep one
// round-trip per category instead of N+1. Each cat ends up with
// last_thread_title + last_activity_at attached.
const catIds = (cats || []).map((c: any) => c.id);
let lastByCat: Record<string, { title: string; at: string }> = {};
if (catIds.length) {
const { data: latest } = await supabase
.from('forum_threads')
.select('id, category_id, title, last_reply_at, created_at')
.in('category_id', catIds)
.order('last_reply_at', { ascending: false, nullsFirst: false })
.limit(2000);
for (const t of latest || []) {
const k = t.category_id as string;
if (!lastByCat[k]) {
lastByCat[k] = {
title: t.title,
at: t.last_reply_at || t.created_at,
};
}
}
}
const enriched = (cats || []).map((c: any) => ({
...c,
last_thread_title: lastByCat[c.id]?.title || null,
last_activity_at: lastByCat[c.id]?.at || null,
}));
return NextResponse.json({ categories: enriched });
} catch (err: any) {
return NextResponse.json({ error: err.message }, { status: 500 });
}