import { getUserIdFromSession } from '../../utils/auth'; import { REWARDS } from '../../utils/economy'; import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); interface DailyVisitResponse { message: string; reward: { coins: number; streakBonus: boolean; }; updatedCoins: number; } /** * Creates a Date object for the start of a given day in UTC. */ function getStartOfDay(date: Date): Date { const startOfDay = new Date(date); startOfDay.setUTCHours(0, 0, 0, 0); return startOfDay; } export default defineEventHandler(async (event): Promise => { const userId = await getUserIdFromSession(event); const today = getStartOfDay(new Date()); // 1. Check if the user has already claimed the reward today const existingVisit = await prisma.dailyVisit.findUnique({ where: { userId_date: { userId, date: today, }, }, }); if (existingVisit) { throw createError({ statusCode: 409, statusMessage: 'Daily visit reward has already been claimed today.', }); } // 2. Check for a 5-day consecutive streak (i.e., visits on the 4 previous days) const previousDates = Array.from({ length: 4 }, (_, i) => { const d = new Date(today); d.setUTCDate(d.getUTCDate() - (i + 1)); return d; }); const priorVisitsCount = await prisma.dailyVisit.count({ where: { userId, date: { in: previousDates, }, }, }); const hasStreak = priorVisitsCount === 4; // 3. Calculate rewards and update the database in a transaction let totalReward = REWARDS.QUESTS.DAILY_VISIT.BASE.coins; let message = 'Daily visit claimed!'; if (hasStreak) { totalReward += REWARDS.QUESTS.DAILY_VISIT.STREAK_BONUS.coins; message = 'Daily visit and streak bonus claimed!'; } const village = await prisma.village.findUnique({ where: { userId } }); const [, updatedUser] = await prisma.$transaction([ prisma.dailyVisit.create({ data: { userId, date: today, }, }), prisma.user.update({ where: { id: userId }, data: { coins: { increment: totalReward, }, }, }), ...(village ? [prisma.villageEvent.create({ data: { villageId: village.id, type: 'QUEST_DAILY_VISIT', message, coins: totalReward, exp: 0, } })] : []), ]); // 4. Return the response return { message, reward: { coins: totalReward, streakBonus: hasStreak, }, updatedCoins: updatedUser.coins, }; });