diff --git a/server/api/quests/daily-visit.post.ts b/server/api/quests/daily-visit.post.ts new file mode 100644 index 0000000..6667381 --- /dev/null +++ b/server/api/quests/daily-visit.post.ts @@ -0,0 +1,106 @@ +import { useSession } from 'h3'; + +interface DailyVisitResponse { + message: string; + reward: { + coins: number; + streakBonus: boolean; + }; + updatedCoins: number; +} + +/** + * A helper function to safely get the authenticated user's ID from the session. + */ +async function getUserIdFromSession(event: any): Promise { + const session = await useSession(event, { + password: process.env.SESSION_PASSWORD, + }); + const userId = session.data?.user?.id; + if (!userId) { + throw createError({ statusCode: 401, statusMessage: 'Unauthorized' }); + } + return userId; +} + +/** + * 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 = 1; // Base reward + if (hasStreak) { + totalReward += 10; // Streak bonus + } + + const [, updatedUser] = await prisma.$transaction([ + prisma.dailyVisit.create({ + data: { + userId, + date: today, + }, + }), + prisma.user.update({ + where: { id: userId }, + data: { + coins: { + increment: totalReward, + }, + }, + }), + ]); + + // 4. Return the response + return { + message: hasStreak ? 'Daily visit and streak bonus claimed!' : 'Daily visit claimed!', + reward: { + coins: totalReward, + streakBonus: hasStreak, + }, + updatedCoins: updatedUser.coins, + }; +});