habits.andr33v.ru/server/api/quests/daily-visit.post.ts

110 lines
2.5 KiB
TypeScript

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<DailyVisitResponse> => {
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,
};
});