138 lines
3.6 KiB
TypeScript
138 lines
3.6 KiB
TypeScript
/**
|
|
* POST /api/referrals/claim - Claim referral bonus
|
|
*/
|
|
|
|
import { NextRequest, NextResponse } from 'next/server';
|
|
import { requireAuth } from '@/app/lib/auth';
|
|
import { createReferral, findUser, getUserReferrals } from '@/app/lib/db/store';
|
|
import { awardReferralBonus } from '@/app/lib/points';
|
|
import { checkAndAwardBadges } from '@/app/lib/badges';
|
|
import { ApiResponse } from '@/app/lib/types';
|
|
|
|
interface ClaimReferralRequest {
|
|
referralCode: string;
|
|
}
|
|
|
|
const REFERRAL_BONUS = 50; // Points awarded for referrals
|
|
|
|
export async function POST(request: NextRequest) {
|
|
try {
|
|
// Authenticate user
|
|
const user = requireAuth(request);
|
|
|
|
// Parse request body
|
|
const body: ClaimReferralRequest = await request.json();
|
|
const { referralCode } = body;
|
|
|
|
if (!referralCode) {
|
|
return NextResponse.json<ApiResponse>(
|
|
{
|
|
success: false,
|
|
error: 'Referral code is required'
|
|
},
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
// Decode referral code to get referrer user ID
|
|
let referrerId: string;
|
|
try {
|
|
referrerId = Buffer.from(referralCode, 'base64').toString('utf-8');
|
|
} catch (error) {
|
|
return NextResponse.json<ApiResponse>(
|
|
{
|
|
success: false,
|
|
error: 'Invalid referral code'
|
|
},
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
// Check if referrer exists
|
|
const referrer = findUser(referrerId);
|
|
if (!referrer) {
|
|
return NextResponse.json<ApiResponse>(
|
|
{
|
|
success: false,
|
|
error: 'Referrer not found'
|
|
},
|
|
{ status: 404 }
|
|
);
|
|
}
|
|
|
|
// Prevent self-referral
|
|
if (referrerId === user.id) {
|
|
return NextResponse.json<ApiResponse>(
|
|
{
|
|
success: false,
|
|
error: 'You cannot refer yourself'
|
|
},
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
// Check if user was already referred
|
|
const allReferrals = getUserReferrals(referrerId);
|
|
const alreadyReferred = allReferrals.some(ref => ref.referredId === user.id);
|
|
|
|
if (alreadyReferred) {
|
|
return NextResponse.json<ApiResponse>(
|
|
{
|
|
success: false,
|
|
error: 'Referral bonus already claimed'
|
|
},
|
|
{ status: 409 }
|
|
);
|
|
}
|
|
|
|
// Create referral record
|
|
const referral = createReferral(referrerId, user.id, REFERRAL_BONUS);
|
|
|
|
// Award points to referrer
|
|
awardReferralBonus(referrerId, referral.id, REFERRAL_BONUS);
|
|
|
|
// Award smaller bonus to referred user
|
|
const referredBonus = Math.floor(REFERRAL_BONUS / 2); // 25 points
|
|
awardReferralBonus(user.id, referral.id, referredBonus);
|
|
|
|
// Check and award badges for both users
|
|
const referrerBadges = checkAndAwardBadges(referrerId);
|
|
const referredBadges = checkAndAwardBadges(user.id);
|
|
|
|
return NextResponse.json<ApiResponse>(
|
|
{
|
|
success: true,
|
|
data: {
|
|
referral,
|
|
referrerBonus: REFERRAL_BONUS,
|
|
referredBonus,
|
|
referrerName: referrer.name
|
|
},
|
|
message: `Referral claimed! You earned ${referredBonus} points, and ${referrer.name} earned ${REFERRAL_BONUS} points${
|
|
referredBadges.length > 0 ? `. You also earned ${referredBadges.length} new badge(s)!` : ''
|
|
}`
|
|
},
|
|
{ status: 201 }
|
|
);
|
|
} catch (error) {
|
|
if (error instanceof Error && error.message === 'Unauthorized') {
|
|
return NextResponse.json<ApiResponse>(
|
|
{
|
|
success: false,
|
|
error: 'Unauthorized'
|
|
},
|
|
{ status: 401 }
|
|
);
|
|
}
|
|
|
|
console.error('Claim referral error:', error);
|
|
return NextResponse.json<ApiResponse>(
|
|
{
|
|
success: false,
|
|
error: 'Internal server error'
|
|
},
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|