import { auth } from "@/lib/auth"; import { prisma } from "@/lib/prisma"; interface LikedEntry { assetId: string; filePath: string; fileName: string; dimensions: string | null; platform: string | null; style: string | null; // "with-people" | "without-people" | null timestamp: string; } interface DislikedEntry { assetId: string; reason: string; fileName: string; dimensions: string | null; platform: string | null; style: string | null; timestamp: string; } interface StylePreferences { liked: LikedEntry[]; disliked: DislikedEntry[]; } function parsePreferences(raw: string | null): StylePreferences { if (!raw) return { liked: [], disliked: [] }; try { const parsed = JSON.parse(raw); return { liked: Array.isArray(parsed.liked) ? parsed.liked : [], disliked: Array.isArray(parsed.disliked) ? parsed.disliked : [], }; } catch { return { liked: [], disliked: [] }; } } export async function GET( _request: Request, { params }: { params: Promise<{ id: string }> } ) { const session = await auth(); if (!session) return new Response("Unauthorized", { status: 401 }); const { id } = await params; const asset = await prisma.asset.findUnique({ where: { id }, include: { campaign: { include: { app: true } } }, }); if (!asset) return Response.json({ error: "Not found" }, { status: 404 }); const app = asset.campaign?.app; if (!app) return Response.json({ vote: null }); const prefs = parsePreferences(app.stylePreferences); const isLiked = prefs.liked.some((e) => e.assetId === id); const isDisliked = prefs.disliked.some((e) => e.assetId === id); return Response.json({ vote: isLiked ? "up" : isDisliked ? "down" : null }); } export async function POST( request: Request, { params }: { params: Promise<{ id: string }> } ) { const session = await auth(); if (!session) return new Response("Unauthorized", { status: 401 }); const { id } = await params; const body = await request.json(); const { vote, reason } = body as { vote: "up" | "down"; reason?: string }; if (vote !== "up" && vote !== "down") { return Response.json({ error: "vote must be 'up' or 'down'" }, { status: 400 }); } const asset = await prisma.asset.findUnique({ where: { id }, include: { campaign: { include: { app: true } } }, }); if (!asset) return Response.json({ error: "Not found" }, { status: 404 }); const app = asset.campaign?.app; if (!app) { return Response.json({ error: "Asset has no associated app" }, { status: 400 }); } // Extract style from asset metadata (set by ad_manifest.json during generation) let assetStyle: string | null = null; if (asset.metadata) { try { const meta = JSON.parse(asset.metadata); if (meta.style === "with-people" || meta.style === "without-people") { assetStyle = meta.style; } } catch { /* metadata isn't JSON or has no style */ } } const prefs = parsePreferences(app.stylePreferences); // Remove from both lists first (clean slate for this asset) prefs.liked = prefs.liked.filter((e) => e.assetId !== id); prefs.disliked = prefs.disliked.filter((e) => e.assetId !== id); // Check if this was already the active vote (toggle off) const wasLiked = parsePreferences(app.stylePreferences).liked.some((e) => e.assetId === id); const wasDisliked = parsePreferences(app.stylePreferences).disliked.some((e) => e.assetId === id); const isToggleOff = (vote === "up" && wasLiked) || (vote === "down" && wasDisliked); if (!isToggleOff) { if (vote === "up") { prefs.liked.push({ assetId: id, filePath: asset.filePath, fileName: asset.fileName, dimensions: asset.dimensions || null, platform: asset.platform || null, style: assetStyle, timestamp: new Date().toISOString(), }); // Keep max ~10 liked if (prefs.liked.length > 10) { prefs.liked = prefs.liked.slice(-10); } } else { prefs.disliked.push({ assetId: id, reason: reason || "Not preferred", fileName: asset.fileName, dimensions: asset.dimensions || null, platform: asset.platform || null, style: assetStyle, timestamp: new Date().toISOString(), }); // Keep max ~20 disliked if (prefs.disliked.length > 20) { prefs.disliked = prefs.disliked.slice(-20); } } } await prisma.app.update({ where: { id: app.id }, data: { stylePreferences: JSON.stringify(prefs) }, }); const newVote = isToggleOff ? null : vote; return Response.json({ vote: newVote }); }