Add consented social milestone posting

This commit is contained in:
2026-08-14 09:03:10 +02:00
parent 14c429ff30
commit f7d82aa5bd
14 changed files with 613 additions and 3 deletions

View File

@@ -0,0 +1,41 @@
import { NextRequest, NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { getSessionUserId } from '@/lib/session';
import { buildMilestoneCard, buildMilestonePost, milestoneThreshold, socialLocale } from '@/lib/social-milestones';
export const dynamic = 'force-dynamic';
// Returns at most one item. A missing response is treated as no consent, never as approval.
export async function GET(request: NextRequest) {
const userId = getSessionUserId();
if (!userId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
const user = await db.user.findUnique({
where: { id: userId }, select: { socialPromptOptOut: true, xHandle: true, primaryUseCase: true },
});
if (!user || user.socialPromptOptOut) return NextResponse.json({ milestone: null });
const milestone = await db.socialMilestone.findFirst({
where: { userId, status: { in: ['detected', 'shown'] } },
orderBy: { detectedAt: 'asc' },
include: { qr: { select: { title: true } } },
});
if (!milestone) return NextResponse.json({ milestone: null });
if (milestone.status === 'detected') {
await db.socialMilestone.update({ where: { id: milestone.id }, data: { status: 'shown', shownAt: new Date() } });
}
const threshold = milestoneThreshold(milestone.kind);
if (!threshold) return NextResponse.json({ milestone: null });
const locale = socialLocale(request.nextUrl.searchParams.get('locale'));
return NextResponse.json({
milestone: {
id: milestone.id, qrTitle: milestone.qr.title, threshold,
defaultXHandle: user.xHandle,
language: locale,
preview: buildMilestonePost(user.primaryUseCase, threshold, null, locale),
card: buildMilestoneCard(user.primaryUseCase, threshold, locale),
},
});
}