/** * POST /api/comments/[id]/vote { vote: 1 | -1 | 0 } * * Up/down/clear vote on an article comment. Uses the existing * polymorphic forum_votes table (target_type='comment'). * * 0 → remove your existing vote (toggle). */ import { NextRequest, NextResponse } from "next/server"; import { createClient } from "@/lib/supabase/server"; export async function POST(req: NextRequest, ctx: { params: Promise<{ id: string }> }) { const { id } = await ctx.params; const sb = await createClient(); const { data: { user } } = await sb.auth.getUser(); if (!user) return NextResponse.json({ error: "Sign in to vote" }, { status: 401 }); let body: { vote?: number }; try { body = await req.json(); } catch { return NextResponse.json({ error: "Invalid JSON" }, { status: 400 }); } const v = body.vote === 1 ? 1 : body.vote === -1 ? -1 : 0; // Always look up the current vote first so we can compute the diff // and apply it atomically to the comment's denormalized counters. const { data: existing } = await sb .from("forum_votes") .select("id, vote_value") .eq("user_id", user.id) .eq("target_type", "comment") .eq("target_id", id) .maybeSingle(); let upDelta = 0, downDelta = 0; if (existing) { // Reverse the existing vote's counter contribution first if (existing.vote_value === 1) upDelta -= 1; else if (existing.vote_value === -1) downDelta -= 1; if (v === 0) { await sb.from("forum_votes").delete().eq("id", existing.id); } else { await sb.from("forum_votes") .update({ vote_value: v, updated_at: new Date().toISOString() }) .eq("id", existing.id); if (v === 1) upDelta += 1; else downDelta += 1; } } else if (v !== 0) { await sb.from("forum_votes").insert({ user_id: user.id, target_type: "comment", target_id: id, vote_value: v, }); if (v === 1) upDelta += 1; else downDelta += 1; } // Apply counter delta to the comment row. Use rpc/raw fragment to add // integers atomically (supabase-js doesn't expose increment; we read & // write — racy under heavy concurrency but acceptable for forum scale). const { data: cur } = await sb .from("article_comments") .select("upvotes, downvotes") .eq("id", id) .maybeSingle(); if (cur) { const upvotes = Math.max(0, (cur.upvotes || 0) + upDelta); const downvotes = Math.max(0, (cur.downvotes || 0) + downDelta); await sb.from("article_comments").update({ upvotes, downvotes, vote_score: upvotes - downvotes, }).eq("id", id); } return NextResponse.json({ ok: true, vote: v }); }