86 lines
2.4 KiB
TypeScript
86 lines
2.4 KiB
TypeScript
import { getAuthenticatedUserId } from '~/server/utils/auth';
|
|
import prisma from '~/server/utils/prisma'; // Ensure prisma is imported
|
|
|
|
const ONBOARDING_REWARD_COINS = 75;
|
|
|
|
interface OnboardingCompletionResponse {
|
|
message: string;
|
|
updatedCoins: number;
|
|
}
|
|
|
|
// Helper to get the start of the day in UTC
|
|
function getStartOfDay(date: Date): Date {
|
|
const d = new Date(date);
|
|
d.setUTCHours(0, 0, 0, 0);
|
|
return d;
|
|
}
|
|
|
|
/**
|
|
* A special endpoint for the onboarding funnel to complete a habit.
|
|
* This provides a fixed reward and has simpler logic than the main completion endpoint.
|
|
* ONLY callable by anonymous users.
|
|
*/
|
|
export default defineEventHandler(async (event): Promise<OnboardingCompletionResponse> => {
|
|
const userId = getAuthenticatedUserId(event);
|
|
const { habitId } = await readBody(event);
|
|
|
|
// Fetch the full user to check their anonymous status
|
|
const user = await prisma.user.findUnique({
|
|
where: { id: userId },
|
|
select: { id: true, isAnonymous: true }
|
|
});
|
|
|
|
// Ensure only anonymous users can use this endpoint
|
|
if (!user || !user.isAnonymous) {
|
|
throw createError({ statusCode: 403, statusMessage: 'Forbidden: This endpoint is for anonymous onboarding users only.' });
|
|
}
|
|
|
|
if (!habitId || typeof habitId !== 'number') {
|
|
throw createError({ statusCode: 400, statusMessage: 'Invalid habit ID.' });
|
|
}
|
|
|
|
const habit = await prisma.habit.findFirst({
|
|
where: { id: habitId, userId: userId }
|
|
});
|
|
|
|
if (!habit) {
|
|
throw createError({ statusCode: 404, statusMessage: 'Habit not found for this user.' });
|
|
}
|
|
|
|
const startOfToday = getStartOfDay(new Date());
|
|
|
|
const existingCompletion = await prisma.habitCompletion.findFirst({
|
|
where: {
|
|
habitId: habitId,
|
|
date: startOfToday,
|
|
},
|
|
});
|
|
|
|
if (existingCompletion) {
|
|
throw createError({ statusCode: 409, statusMessage: 'Habit already completed today.' });
|
|
}
|
|
|
|
// Use a transaction to ensure both operations succeed or fail together
|
|
const [, updatedUser] = await prisma.$transaction([
|
|
prisma.habitCompletion.create({
|
|
data: {
|
|
habitId: habitId,
|
|
date: startOfToday,
|
|
},
|
|
}),
|
|
prisma.user.update({
|
|
where: { id: userId },
|
|
data: {
|
|
coins: {
|
|
increment: ONBOARDING_REWARD_COINS,
|
|
},
|
|
},
|
|
}),
|
|
]);
|
|
|
|
return {
|
|
message: 'Onboarding habit completed successfully!',
|
|
updatedCoins: updatedUser.coins,
|
|
};
|
|
});
|