habits.andr33v.ru/server/api/habits/[id]/complete.post.ts

110 lines
3.1 KiB
TypeScript

import { getUserIdFromSession } from '../../../utils/auth';
import { REWARDS } from '../../../utils/economy';
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
interface CompletionResponse {
message: string;
reward: {
coins: number;
exp: number; // Added
};
updatedCoins: number;
updatedExp: number; // Added
}
/**
* Creates a Date object for the start of a given day in UTC.
* This is duplicated here as per the instruction not to create new shared utilities.
*/
function getStartOfDay(date: Date): Date {
const startOfDay = new Date(date);
startOfDay.setUTCHours(0, 0, 0, 0);
return startOfDay;
}
export default defineEventHandler(async (event): Promise<CompletionResponse> => {
const userId = await getUserIdFromSession(event);
const habitId = parseInt(event.context.params?.id || '', 10);
if (isNaN(habitId)) {
throw createError({ statusCode: 400, statusMessage: 'Invalid habit ID.' });
}
const habit = await prisma.habit.findFirst({
where: { id: habitId, userId },
});
if (!habit) {
throw createError({ statusCode: 404, statusMessage: 'Habit not found.' });
}
const today = new Date();
const jsDayOfWeek = today.getDay(); // 0 (Sunday) to 6 (Saturday)
// Convert JS day (Sun=0) to the application's convention (Mon=0, Sun=6)
const appDayOfWeek = (jsDayOfWeek === 0) ? 6 : jsDayOfWeek - 1;
if (!(habit.daysOfWeek as number[]).includes(appDayOfWeek)) {
throw createError({ statusCode: 400, statusMessage: 'Habit is not active today.' });
}
// Normalize date to the beginning of the day for consistent checks
const startOfToday = getStartOfDay(new Date()); // Correctly get a Date object
const existingCompletion = await prisma.habitCompletion.findFirst({
where: {
habitId: habitId,
date: startOfToday, // Use precise equality check
},
});
if (existingCompletion) {
throw createError({ statusCode: 409, statusMessage: 'Habit already completed today.' });
}
const rewardCoins = REWARDS.HABITS.COMPLETION.coins;
const rewardExp = REWARDS.HABITS.COMPLETION.exp; // Added
const village = await prisma.village.findUnique({ where: { userId } });
const [, updatedUser] = await prisma.$transaction([
prisma.habitCompletion.create({
data: {
habitId: habitId,
date: startOfToday, // Save the normalized date
},
}),
prisma.user.update({
where: { id: userId },
data: {
coins: {
increment: rewardCoins,
},
exp: { // Added
increment: rewardExp, // Added
},
},
}),
...(village ? [prisma.villageEvent.create({
data: {
villageId: village.id,
type: 'HABIT_COMPLETION',
message: `Completed habit: "${habit.name}"`,
coins: rewardCoins,
exp: rewardExp, // Changed from 0 to rewardExp
}
})] : []),
]);
return {
message: 'Habit completed successfully!',
reward: {
coins: rewardCoins,
exp: rewardExp, // Added
},
updatedCoins: updatedUser.coins,
updatedExp: updatedUser.exp, // Added
};
});