feat: daily visit quest with streak bonus
This commit is contained in:
parent
abfca19833
commit
e399805d14
106
server/api/quests/daily-visit.post.ts
Normal file
106
server/api/quests/daily-visit.post.ts
Normal file
|
|
@ -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<number> {
|
||||
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<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 = 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,
|
||||
};
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user