import { NextResponse } from "next/server"; import { createClient } from "@supabase/supabase-js"; export const runtime = "nodejs"; export const revalidate = 120; const SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL!; const SUPABASE_ANON = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!; const SCHEMA = process.env.NEXT_PUBLIC_SUPABASE_SCHEMA || "av"; function client() { return createClient(SUPABASE_URL, SUPABASE_ANON, { db: { schema: SCHEMA as "public" }, auth: { persistSession: false }, }); } export async function GET( _req: Request, { params }: { params: Promise<{ username: string }> }, ) { const { username } = await params; const sb = client(); const decoded = decodeURIComponent(username); let { data: profile } = await sb .from("forum_user_profiles") .select("*") .eq("username", decoded) .maybeSingle(); if (!profile) { const r2 = await sb .from("forum_user_profiles") .select("*") .eq("display_name", decoded) .order("created_at", { ascending: true }) .limit(1); profile = (r2.data && r2.data[0]) || null; } if (!profile) { return NextResponse.json({ error: "not found" }, { status: 404 }); } const displayName = profile.display_name as string; const [ { count: threadCount }, { count: replyCount }, { data: threads }, { data: replies }, ] = await Promise.all([ sb .from("forum_threads") .select("*", { count: "exact", head: true }) .eq("author_name", displayName), sb .from("forum_replies") .select("*", { count: "exact", head: true }) .eq("author_name", displayName), sb .from("forum_threads") .select( "id,title,reply_count,view_count,vote_score,created_at,category_id,forum_categories(name,slug)", ) .eq("author_name", displayName) .order("created_at", { ascending: false }) .limit(50), sb .from("forum_replies") .select("id,thread_id,body,vote_score,created_at") .eq("author_name", displayName) .order("created_at", { ascending: false }) .limit(20), ]); const threadIds = [...new Set((replies || []).map((r) => r.thread_id).filter(Boolean))]; let titleByThread: Record = {}; if (threadIds.length > 0) { const { data: threadTitles } = await sb .from("forum_threads") .select("id,title") .in("id", threadIds); titleByThread = Object.fromEntries( (threadTitles || []).map((t) => [t.id, t.title]), ); } const repliesWithTitles = (replies || []).map((r) => ({ ...r, forum_threads: { title: titleByThread[r.thread_id] || "(thread)" }, })); const totalThreads = threadCount ?? 0; const totalReplies = replyCount ?? 0; return NextResponse.json({ profile: { username: profile.username, display_name: profile.display_name, bio: profile.bio || null, avatar_url: profile.avatar_url || null, role_title: profile.role_title || null, company: profile.company || null, location_city: profile.location_city || null, location_country: profile.location_country || null, years_experience: profile.years_experience || null, expertise_level: profile.expertise_level || null, expertise_tags: profile.expertise_tags || [], signature: profile.signature || null, join_date: profile.join_date || null, last_seen_at: profile.last_seen_at || null, thread_count: totalThreads, reply_count: totalReplies, post_count: totalThreads + totalReplies, }, threads: threads || [], replies: repliesWithTitles, }); }