← back to Wine Finder Next
app/api/affiliate/track/route.ts
123 lines
import { NextRequest, NextResponse } from 'next/server';
const googleSheets = require('@/lib/services/googleSheets');
// In-memory storage for development (replace with database in production)
const clicksStorage: any[] = [];
export async function POST(request: NextRequest) {
try {
const body = await request.json();
// Get client IP and user agent
const ip = request.headers.get('x-forwarded-for') ||
request.headers.get('x-real-ip') ||
'unknown';
const userAgent = request.headers.get('user-agent') || 'unknown';
if (body.bulk) {
// Bulk tracking
const clicks = body.clicks.map((click: any) => ({
...click,
ipAddress: ip,
userAgent: userAgent
}));
clicksStorage.push(...clicks);
// Log to Google Sheets asynchronously
googleSheets.logAffiliateClicks(clicks).catch((err: Error) => {
console.error('Failed to log bulk clicks to sheets:', err.message);
});
return NextResponse.json({
success: true,
tracked: clicks.length
});
} else {
// Single click tracking
const click = {
...body,
ipAddress: ip,
userAgent: userAgent
};
clicksStorage.push(click);
// Log to Google Sheets asynchronously
googleSheets.logAffiliateClick(click).catch((err: Error) => {
console.error('Failed to log click to sheets:', err.message);
});
return NextResponse.json({
success: true,
clickId: clicksStorage.length
});
}
} catch (error: any) {
console.error('Error tracking affiliate click:', error);
return NextResponse.json(
{ error: 'Failed to track click', message: error.message },
{ status: 500 }
);
}
}
export async function GET(request: NextRequest) {
try {
const searchParams = request.nextUrl.searchParams;
const partnerId = searchParams.get('partnerId');
const startDate = searchParams.get('startDate');
const endDate = searchParams.get('endDate');
let filteredClicks = clicksStorage;
// Filter by partner
if (partnerId) {
filteredClicks = filteredClicks.filter(c => c.partnerId === partnerId);
}
// Filter by date range
if (startDate) {
filteredClicks = filteredClicks.filter(c => c.timestamp >= startDate);
}
if (endDate) {
filteredClicks = filteredClicks.filter(c => c.timestamp <= endDate);
}
// Calculate stats
const now = new Date();
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const weekAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000);
const monthAgo = new Date(today.getTime() - 30 * 24 * 60 * 60 * 1000);
const stats = {
total: filteredClicks.length,
today: filteredClicks.filter(c => new Date(c.timestamp) >= today).length,
thisWeek: filteredClicks.filter(c => new Date(c.timestamp) >= weekAgo).length,
thisMonth: filteredClicks.filter(c => new Date(c.timestamp) >= monthAgo).length,
byPartner: {} as Record<string, number>
};
// Group by partner
filteredClicks.forEach(click => {
if (!stats.byPartner[click.partnerId]) {
stats.byPartner[click.partnerId] = 0;
}
stats.byPartner[click.partnerId]++;
});
return NextResponse.json({
success: true,
stats,
clicks: filteredClicks.slice(-100) // Last 100 clicks
});
} catch (error: any) {
console.error('Error getting affiliate stats:', error);
return NextResponse.json(
{ error: 'Failed to get stats', message: error.message },
{ status: 500 }
);
}
}