111 lines
3.7 KiB
TypeScript
111 lines
3.7 KiB
TypeScript
|
|
import { NextRequest, NextResponse } from "next/server";
|
||
|
|
import { prisma } from "@/lib/prisma";
|
||
|
|
|
||
|
|
// Decode a base62 referral code back to a userId prefix for lookup
|
||
|
|
function decodeBase62Lookup(code: string): number {
|
||
|
|
const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||
|
|
let hash = 0;
|
||
|
|
for (const ch of code) {
|
||
|
|
const idx = chars.indexOf(ch);
|
||
|
|
if (idx === -1) return -1;
|
||
|
|
hash = hash * 62 + idx;
|
||
|
|
}
|
||
|
|
return hash >>> 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function POST(req: NextRequest) {
|
||
|
|
try {
|
||
|
|
const body = await req.json();
|
||
|
|
const { code } = body;
|
||
|
|
|
||
|
|
if (!code || typeof code !== "string") {
|
||
|
|
return NextResponse.json(
|
||
|
|
{ error: "Referral code is required" },
|
||
|
|
{ status: 400 }
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// In a real system, you'd look up the referrer by their stored referral code.
|
||
|
|
// For simplicity, we encode the userId in the code. We need to find the user
|
||
|
|
// whose userId produces this code. Since encodeBase62 uses a hash, we
|
||
|
|
// can't reverse it perfectly. Instead, we iterate active users.
|
||
|
|
// A production approach: store referral codes in a dedicated table or column.
|
||
|
|
// For now, we'll iterate through users and find a match.
|
||
|
|
const users = await prisma.user.findMany({
|
||
|
|
select: { id: true },
|
||
|
|
});
|
||
|
|
|
||
|
|
// Recreate the encode logic to find the matching user
|
||
|
|
function encodeForMatch(id: string): string {
|
||
|
|
const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||
|
|
let hash = 0;
|
||
|
|
for (let i = 0; i < Math.min(id.length, 10); i++) {
|
||
|
|
hash = (hash * 31 + id.charCodeAt(i)) >>> 0;
|
||
|
|
}
|
||
|
|
let result = "";
|
||
|
|
let h = hash;
|
||
|
|
while (result.length < 6) {
|
||
|
|
result = chars[h % 62] + result;
|
||
|
|
h = Math.floor(h / 62);
|
||
|
|
if (h === 0 && result.length < 6) {
|
||
|
|
h = Math.floor(Math.random() * 62 ** (6 - result.length));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
let referrerId: string | null = null;
|
||
|
|
for (const u of users) {
|
||
|
|
if (encodeForMatch(u.id) === code) {
|
||
|
|
referrerId = u.id;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!referrerId) {
|
||
|
|
return NextResponse.json(
|
||
|
|
{ error: "Invalid referral code" },
|
||
|
|
{ status: 400 }
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Save the referral code in a cookie/localStorage so when user registers,
|
||
|
|
// the newly created user can be linked. For now, we just create a placeholder
|
||
|
|
// "pending" referral. The actual linking happens when the user registers
|
||
|
|
// and passes the referral code again (to be paired via the referred user's ID).
|
||
|
|
// Since we don't have a "referredId" yet, we store a temporary token.
|
||
|
|
const tempToken = `pending_${referrerId}_${Date.now()}`;
|
||
|
|
|
||
|
|
// Check if this referrer already has a pending referral with this temp token
|
||
|
|
const existing = await prisma.referral.findFirst({
|
||
|
|
where: { referrerId, status: "pending" },
|
||
|
|
orderBy: { createdAt: "desc" },
|
||
|
|
});
|
||
|
|
|
||
|
|
// Store in a lightweight way — we'll use the Referral model with a placeholder referredId
|
||
|
|
// The referredId will be updated when registration completes.
|
||
|
|
// For production, a ReferralClaimToken model would be better.
|
||
|
|
const referral = await prisma.referral.create({
|
||
|
|
data: {
|
||
|
|
referrerId,
|
||
|
|
referredId: `pending_${tempToken}`, // placeholder, will be updated on registration
|
||
|
|
status: "pending",
|
||
|
|
rewardFlh: 0,
|
||
|
|
},
|
||
|
|
});
|
||
|
|
|
||
|
|
return NextResponse.json({
|
||
|
|
success: true,
|
||
|
|
message: "Referral code applied! You'll get 1000 FLH when you sign up.",
|
||
|
|
referralId: referral.id,
|
||
|
|
tempToken,
|
||
|
|
});
|
||
|
|
} catch (error) {
|
||
|
|
console.error("Referral claim error:", error);
|
||
|
|
return NextResponse.json(
|
||
|
|
{ error: "Failed to claim referral" },
|
||
|
|
{ status: 500 }
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|