import { auth } from '$lib/auth'; import { error, json } from '@sveltejs/kit'; import { db } from '$lib/server/db'; import { user, promoCode, promoCodeRedemption } from '$lib/server/db/schema'; import { eq, and, count } from 'drizzle-orm'; import type { RequestHandler } from './$types'; export const POST: RequestHandler = async ({ request }) => { const session = await auth.api.getSession({ headers: request.headers }); if (!session?.user) { throw error(401, 'Not authenticated'); } const { code } = await request.json(); if (!code || typeof code !== 'string' || code.trim().length === 0) { return json({ error: 'Promo code is required' }, { status: 400 }); } const normalizedCode = code.trim().toUpperCase(); const userId = Number(session.user.id); return await db.transaction(async (tx) => { const [promoData] = await tx .select({ id: promoCode.id, code: promoCode.code, rewardAmount: promoCode.rewardAmount, maxUses: promoCode.maxUses, expiresAt: promoCode.expiresAt, isActive: promoCode.isActive, description: promoCode.description }) .from(promoCode) .where(eq(promoCode.code, normalizedCode)) .for('update') .limit(1); if (!promoData) { return json({ error: 'Invalid promo code' }, { status: 400 }); } if (!promoData.isActive) { return json({ error: 'This promo code is no longer active' }, { status: 400 }); } if (promoData.expiresAt && new Date() > promoData.expiresAt) { return json({ error: 'This promo code has expired' }, { status: 400 }); } const [existingRedemption] = await tx .select({ id: promoCodeRedemption.id }) .from(promoCodeRedemption) .where(and( eq(promoCodeRedemption.userId, userId), eq(promoCodeRedemption.promoCodeId, promoData.id) )) .limit(1); if (existingRedemption) { return json({ error: 'You have already used this promo code' }, { status: 400 }); } if (promoData.maxUses !== null) { const [{ totalUses }] = await tx .select({ totalUses: count() }) .from(promoCodeRedemption) .where(eq(promoCodeRedemption.promoCodeId, promoData.id)); if (totalUses >= promoData.maxUses) { return json({ error: 'This promo code has reached its usage limit' }, { status: 400 }); } } const [userData] = await tx .select({ baseCurrencyBalance: user.baseCurrencyBalance }) .from(user) .where(eq(user.id, userId)) .for('update') .limit(1); if (!userData) { throw error(404, 'User not found'); } const currentBalance = Number(userData.baseCurrencyBalance || 0); const rewardAmount = Number(promoData.rewardAmount); const newBalance = currentBalance + rewardAmount; await tx .update(user) .set({ baseCurrencyBalance: newBalance.toFixed(8), updatedAt: new Date() }) .where(eq(user.id, userId)); await tx .insert(promoCodeRedemption) .values({ userId, promoCodeId: promoData.id, rewardAmount: rewardAmount.toFixed(8) }); return json({ success: true, message: promoData.description || `Promo code redeemed! You received $${rewardAmount.toFixed(2)}`, rewardAmount, newBalance, code: promoData.code }); }); };