Block 8 complete: streaks, notifications, referrals, premium identity, gamification

This commit is contained in:
root
2026-06-15 10:32:10 +02:00
parent 6423430275
commit 5e73d1d7ad
24 changed files with 1565 additions and 38 deletions
@@ -0,0 +1,45 @@
import { requireAuth } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import { NextResponse } from "next/server";
// GET /api/gamification/achievements — get all achievements with unlock status
export async function GET(request: Request) {
const jwt = await requireAuth(request);
if (!jwt) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const userId = jwt.userId;
const achievements = await prisma.achievement.findMany({
where: { userId },
orderBy: { unlockedAt: "desc" },
});
// Define all possible achievement types so the frontend can show locked ones too
const allAchievementTypes = [
{ type: "first_chat", title: "First Words", description: "Send your first message to Nur AI", icon: "💬" },
{ type: "streak_7", title: "Week Warrior", description: "Maintain a 7-day streak", icon: "🔥" },
{ type: "streak_30", title: "Monthly Master", description: "Maintain a 30-day streak", icon: "🏆" },
{ type: "level_5", title: "Rising Star", description: "Reach level 5", icon: "⭐" },
{ type: "first_purchase", title: "First Shopper", description: "Make your first marketplace purchase", icon: "🛍️" },
{ type: "first_post", title: "Forum Newbie", description: "Make your first forum post", icon: "📝" },
];
const unlocked = new Set(achievements.map((a) => a.type));
const allAchievements = allAchievementTypes.map((def) => {
const unlockedAchievement = achievements.find((a) => a.type === def.type);
return {
...def,
unlocked: unlocked.has(def.type),
unlockedAt: unlockedAchievement?.unlockedAt ?? null,
};
});
return NextResponse.json({
achievements: allAchievements,
unlockedCount: achievements.length,
totalCount: allAchievementTypes.length,
});
}