first commit
This commit is contained in:
56
app/api/dashboard/commissions/route.ts
Normal file
56
app/api/dashboard/commissions/route.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { auth } from '@/auth'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const session = await auth()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(request.url)
|
||||
const page = parseInt(searchParams.get('page') || '1')
|
||||
const limit = parseInt(searchParams.get('limit') || '10')
|
||||
const skip = (page - 1) * limit
|
||||
|
||||
const [commissions, total] = await Promise.all([
|
||||
prisma.commission.findMany({
|
||||
where: { userId: session.user.id },
|
||||
include: {
|
||||
fromUser: {
|
||||
select: {
|
||||
name: true,
|
||||
email: true
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
skip,
|
||||
take: limit
|
||||
}),
|
||||
prisma.commission.count({ where: { userId: session.user.id } })
|
||||
])
|
||||
|
||||
return NextResponse.json({
|
||||
commissions: commissions.map(commission => ({
|
||||
id: commission.id,
|
||||
amount: commission.amount,
|
||||
level: commission.level,
|
||||
type: commission.type,
|
||||
status: commission.status,
|
||||
createdAt: commission.createdAt,
|
||||
fromUser: commission.fromUser
|
||||
})),
|
||||
total,
|
||||
pages: Math.ceil(total / limit)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error fetching commissions:', error)
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch commissions' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
171
app/api/dashboard/genealogy/route.ts
Normal file
171
app/api/dashboard/genealogy/route.ts
Normal file
@@ -0,0 +1,171 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { auth } from '@/auth'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
|
||||
interface TeamMember {
|
||||
id: string
|
||||
name: string
|
||||
email: string
|
||||
joinedAt: string
|
||||
totalEarnings: number
|
||||
directReferrals: number
|
||||
level: number
|
||||
children?: TeamMember[]
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const session = await auth()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const userId = session.user.id
|
||||
|
||||
// Build genealogy tree
|
||||
const genealogyTree = await buildGenealogyTree(userId, 0)
|
||||
|
||||
// Calculate stats
|
||||
const teamSize = await calculateTeamSize(userId)
|
||||
const totalVolume = await calculateTeamVolume(userId)
|
||||
const levels = await calculateNetworkLevels(userId)
|
||||
|
||||
return NextResponse.json({
|
||||
user: genealogyTree,
|
||||
teamSize,
|
||||
totalVolume,
|
||||
levels
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error fetching genealogy data:', error)
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch genealogy data' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async function buildGenealogyTree(userId: string, level: number): Promise<TeamMember> {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id: userId },
|
||||
include: {
|
||||
wallet: true,
|
||||
referrals: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
joinedAt: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (!user) {
|
||||
throw new Error('User not found')
|
||||
}
|
||||
|
||||
// Get direct referrals count
|
||||
const directReferrals = await prisma.user.count({
|
||||
where: { referrerId: userId }
|
||||
})
|
||||
|
||||
const teamMember: TeamMember = {
|
||||
id: user.id,
|
||||
name: user.name || 'Unknown',
|
||||
email: user.email,
|
||||
joinedAt: user.joinedAt.toISOString(),
|
||||
totalEarnings: user.wallet?.totalEarnings || 0,
|
||||
directReferrals,
|
||||
level,
|
||||
children: []
|
||||
}
|
||||
|
||||
// Recursively build children (limit to 5 levels to prevent infinite recursion)
|
||||
if (level < 5 && user.referrals.length > 0) {
|
||||
for (const referral of user.referrals) {
|
||||
const childTree = await buildGenealogyTree(referral.id, level + 1)
|
||||
teamMember.children!.push(childTree)
|
||||
}
|
||||
}
|
||||
|
||||
return teamMember
|
||||
}
|
||||
|
||||
async function calculateTeamSize(userId: string): Promise<number> {
|
||||
const getAllTeamMembers = async (id: string): Promise<string[]> => {
|
||||
const directReferrals = await prisma.user.findMany({
|
||||
where: { referrerId: id },
|
||||
select: { id: true }
|
||||
})
|
||||
|
||||
let allMembers = directReferrals.map(r => r.id)
|
||||
|
||||
for (const referral of directReferrals) {
|
||||
const subTeam = await getAllTeamMembers(referral.id)
|
||||
allMembers = [...allMembers, ...subTeam]
|
||||
}
|
||||
|
||||
return allMembers
|
||||
}
|
||||
|
||||
const teamMembers = await getAllTeamMembers(userId)
|
||||
return teamMembers.length
|
||||
}
|
||||
|
||||
async function calculateTeamVolume(userId: string): Promise<number> {
|
||||
const getAllTeamMembers = async (id: string): Promise<string[]> => {
|
||||
const directReferrals = await prisma.user.findMany({
|
||||
where: { referrerId: id },
|
||||
select: { id: true }
|
||||
})
|
||||
|
||||
let allMembers = directReferrals.map(r => r.id)
|
||||
|
||||
for (const referral of directReferrals) {
|
||||
const subTeam = await getAllTeamMembers(referral.id)
|
||||
allMembers = [...allMembers, ...subTeam]
|
||||
}
|
||||
|
||||
return allMembers
|
||||
}
|
||||
|
||||
const teamMembers = await getAllTeamMembers(userId)
|
||||
|
||||
if (teamMembers.length === 0) return 0
|
||||
|
||||
const volume = await prisma.order.aggregate({
|
||||
where: {
|
||||
userId: { in: teamMembers },
|
||||
status: { in: ['PAID', 'SHIPPED', 'DELIVERED'] }
|
||||
},
|
||||
_sum: { total: true }
|
||||
})
|
||||
|
||||
return volume._sum.total || 0
|
||||
}
|
||||
|
||||
async function calculateNetworkLevels(userId: string): Promise<number> {
|
||||
const getMaxLevel = async (id: string, currentLevel: number): Promise<number> => {
|
||||
const directReferrals = await prisma.user.findMany({
|
||||
where: { referrerId: id },
|
||||
select: { id: true }
|
||||
})
|
||||
|
||||
if (directReferrals.length === 0) {
|
||||
return currentLevel
|
||||
}
|
||||
|
||||
let maxLevel = currentLevel + 1
|
||||
|
||||
for (const referral of directReferrals) {
|
||||
const level = await getMaxLevel(referral.id, currentLevel + 1)
|
||||
maxLevel = Math.max(maxLevel, level)
|
||||
}
|
||||
|
||||
return maxLevel
|
||||
}
|
||||
|
||||
return await getMaxLevel(userId, 0)
|
||||
}
|
||||
73
app/api/dashboard/payouts/route.ts
Normal file
73
app/api/dashboard/payouts/route.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { auth } from '@/auth'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const session = await auth()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const { amount, bankDetails } = await request.json()
|
||||
|
||||
// Check wallet balance
|
||||
const wallet = await prisma.wallet.findUnique({
|
||||
where: { userId: session.user.id }
|
||||
})
|
||||
|
||||
if (!wallet || wallet.balance < amount) {
|
||||
return NextResponse.json({ error: 'Insufficient balance' }, { status: 400 })
|
||||
}
|
||||
|
||||
// Create payout request
|
||||
const payout = await prisma.payout.create({
|
||||
data: {
|
||||
userId: session.user.id,
|
||||
amount,
|
||||
bankDetails,
|
||||
status: 'PENDING'
|
||||
}
|
||||
})
|
||||
|
||||
// Update wallet balance (deduct the requested amount)
|
||||
await prisma.wallet.update({
|
||||
where: { userId: session.user.id },
|
||||
data: {
|
||||
balance: { decrement: amount }
|
||||
}
|
||||
})
|
||||
|
||||
return NextResponse.json(payout)
|
||||
} catch (error) {
|
||||
console.error('Error creating payout request:', error)
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to create payout request' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const session = await auth()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const payouts = await prisma.payout.findMany({
|
||||
where: { userId: session.user.id },
|
||||
orderBy: { createdAt: 'desc' }
|
||||
})
|
||||
|
||||
return NextResponse.json(payouts)
|
||||
} catch (error) {
|
||||
console.error('Error fetching payouts:', error)
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch payouts' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
80
app/api/dashboard/profile/[id]/route.ts
Normal file
80
app/api/dashboard/profile/[id]/route.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { auth } from '@/auth'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
import { CommissionService } from '@/lib/commission'
|
||||
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const session = await auth()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const { id } = await params
|
||||
|
||||
// Get user profile
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id },
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
phone: true,
|
||||
address: true,
|
||||
joinedAt: true,
|
||||
role: true,
|
||||
referralCode: true,
|
||||
isActive: true
|
||||
}
|
||||
})
|
||||
|
||||
if (!user) {
|
||||
return NextResponse.json({ error: 'User not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
// Get team stats
|
||||
const stats = await CommissionService.getTeamStats(id)
|
||||
|
||||
// Get wallet info
|
||||
const wallet = await prisma.wallet.findUnique({
|
||||
where: { userId: id }
|
||||
})
|
||||
|
||||
// Get recent commissions
|
||||
const recentCommissions = await prisma.commission.findMany({
|
||||
where: { userId: id },
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 5,
|
||||
select: {
|
||||
id: true,
|
||||
amount: true,
|
||||
level: true,
|
||||
type: true,
|
||||
status: true,
|
||||
createdAt: true
|
||||
}
|
||||
})
|
||||
|
||||
const profile = {
|
||||
...user,
|
||||
stats: {
|
||||
...stats,
|
||||
totalEarnings: wallet?.totalEarnings || 0,
|
||||
walletBalance: wallet?.balance || 0
|
||||
},
|
||||
recentCommissions
|
||||
}
|
||||
|
||||
return NextResponse.json(profile)
|
||||
} catch (error) {
|
||||
console.error('Error fetching user profile:', error)
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch profile' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
70
app/api/dashboard/referrals/route.ts
Normal file
70
app/api/dashboard/referrals/route.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { auth } from '@/auth'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const session = await auth()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
// Get user's direct referrals
|
||||
const referrals = await prisma.user.findMany({
|
||||
where: {
|
||||
referrerId: session.user.id
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
phone: true,
|
||||
joinedAt: true,
|
||||
isActive: true,
|
||||
orders: {
|
||||
where: {
|
||||
status: { in: ['PAID', 'SHIPPED', 'DELIVERED'] }
|
||||
},
|
||||
select: {
|
||||
total: true
|
||||
}
|
||||
},
|
||||
// Get commissions earned from this referral
|
||||
commissionsFrom: {
|
||||
where: {
|
||||
userId: session.user.id,
|
||||
status: { in: ['APPROVED', 'PAID'] }
|
||||
},
|
||||
select: {
|
||||
amount: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const formattedReferrals = referrals.map(referral => ({
|
||||
id: referral.id,
|
||||
name: referral.name || 'User',
|
||||
email: referral.email,
|
||||
phone: referral.phone,
|
||||
joinedAt: referral.joinedAt,
|
||||
isActive: referral.isActive,
|
||||
totalOrders: referral.orders.length,
|
||||
totalSpent: referral.orders.reduce((sum, order) => sum + order.total, 0),
|
||||
commissionEarned: referral.commissionsFrom.reduce((sum, comm) => sum + comm.amount, 0),
|
||||
status: referral.isActive ? 'ACTIVE' : 'INACTIVE'
|
||||
}))
|
||||
|
||||
return NextResponse.json({
|
||||
referrals: formattedReferrals
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching referrals:', error)
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch referrals' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
89
app/api/dashboard/referrals/stats/route.ts
Normal file
89
app/api/dashboard/referrals/stats/route.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { auth } from '@/auth'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const session = await auth()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const userId = session.user.id
|
||||
|
||||
// Get total referrals
|
||||
const totalReferrals = await prisma.user.count({
|
||||
where: { referrerId: userId }
|
||||
})
|
||||
|
||||
// Get active referrals
|
||||
const activeReferrals = await prisma.user.count({
|
||||
where: {
|
||||
referrerId: userId,
|
||||
isActive: true
|
||||
}
|
||||
})
|
||||
|
||||
// Get pending referrals
|
||||
const pendingReferrals = await prisma.user.count({
|
||||
where: {
|
||||
referrerId: userId,
|
||||
isActive: false
|
||||
}
|
||||
})
|
||||
|
||||
// Get total commission earned from referrals
|
||||
const totalCommissionResult = await prisma.commission.aggregate({
|
||||
where: {
|
||||
userId,
|
||||
status: { in: ['APPROVED', 'PAID'] }
|
||||
},
|
||||
_sum: {
|
||||
amount: true
|
||||
}
|
||||
})
|
||||
|
||||
// Get this month's stats
|
||||
const now = new Date()
|
||||
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1)
|
||||
|
||||
const thisMonthReferrals = await prisma.user.count({
|
||||
where: {
|
||||
referrerId: userId,
|
||||
joinedAt: {
|
||||
gte: startOfMonth
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const thisMonthCommissionResult = await prisma.commission.aggregate({
|
||||
where: {
|
||||
userId,
|
||||
status: { in: ['APPROVED', 'PAID'] },
|
||||
createdAt: {
|
||||
gte: startOfMonth
|
||||
}
|
||||
},
|
||||
_sum: {
|
||||
amount: true
|
||||
}
|
||||
})
|
||||
|
||||
return NextResponse.json({
|
||||
totalReferrals,
|
||||
activeReferrals,
|
||||
pendingReferrals,
|
||||
totalCommissionEarned: totalCommissionResult._sum.amount || 0,
|
||||
thisMonthReferrals,
|
||||
thisMonthCommission: thisMonthCommissionResult._sum.amount || 0
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching referral stats:', error)
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch referral stats' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
159
app/api/dashboard/reports/route.ts
Normal file
159
app/api/dashboard/reports/route.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { auth } from '@/auth'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const session = await auth()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(request.url)
|
||||
const range = parseInt(searchParams.get('range') || '30')
|
||||
const type = searchParams.get('type') || 'all'
|
||||
|
||||
const userId = session.user.id
|
||||
const startDate = new Date()
|
||||
startDate.setDate(startDate.getDate() - range)
|
||||
|
||||
// Get commission data
|
||||
const commissions = await prisma.commission.findMany({
|
||||
where: {
|
||||
userId,
|
||||
createdAt: { gte: startDate }
|
||||
},
|
||||
include: {
|
||||
fromUser: {
|
||||
select: { name: true, email: true }
|
||||
}
|
||||
},
|
||||
orderBy: { createdAt: 'desc' }
|
||||
})
|
||||
|
||||
const totalCommissions = commissions.reduce((sum, c) => sum + c.amount, 0)
|
||||
|
||||
// Calculate commission growth
|
||||
const previousPeriodStart = new Date(startDate)
|
||||
previousPeriodStart.setDate(previousPeriodStart.getDate() - range)
|
||||
|
||||
const previousCommissions = await prisma.commission.findMany({
|
||||
where: {
|
||||
userId,
|
||||
createdAt: {
|
||||
gte: previousPeriodStart,
|
||||
lt: startDate
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const previousTotal = previousCommissions.reduce((sum, c) => sum + c.amount, 0)
|
||||
const growth = previousTotal > 0 ? ((totalCommissions - previousTotal) / previousTotal) * 100 : 0
|
||||
|
||||
// Commission by level
|
||||
const commissionsByLevel = commissions.reduce((acc, c) => {
|
||||
const existing = acc.find(item => item.level === c.level)
|
||||
if (existing) {
|
||||
existing.amount += c.amount
|
||||
existing.count += 1
|
||||
} else {
|
||||
acc.push({ level: c.level, amount: c.amount, count: 1 })
|
||||
}
|
||||
return acc
|
||||
}, [] as { level: number; amount: number; count: number }[])
|
||||
|
||||
// Get team data
|
||||
const directReferrals = await prisma.user.findMany({
|
||||
where: { referrerId: userId },
|
||||
select: {
|
||||
id: true,
|
||||
joinedAt: true,
|
||||
orders: {
|
||||
where: {
|
||||
createdAt: { gte: startDate },
|
||||
status: { in: ['PAID', 'SHIPPED', 'DELIVERED'] }
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Get all team members recursively
|
||||
const getAllTeamMembers = async (id: string): Promise<string[]> => {
|
||||
const refs = await prisma.user.findMany({
|
||||
where: { referrerId: id },
|
||||
select: { id: true }
|
||||
})
|
||||
|
||||
let allMembers = refs.map(r => r.id)
|
||||
|
||||
for (const ref of refs) {
|
||||
const subTeam = await getAllTeamMembers(ref.id)
|
||||
allMembers = [...allMembers, ...subTeam]
|
||||
}
|
||||
|
||||
return allMembers
|
||||
}
|
||||
|
||||
const allTeamMemberIds = await getAllTeamMembers(userId)
|
||||
|
||||
// Team metrics
|
||||
const activeMembers = directReferrals.filter(r => r.orders.length > 0).length
|
||||
const newThisMonth = directReferrals.filter(r =>
|
||||
new Date(r.joinedAt) >= new Date(new Date().getFullYear(), new Date().getMonth(), 1)
|
||||
).length
|
||||
|
||||
// Sales data
|
||||
const userOrders = await prisma.order.findMany({
|
||||
where: {
|
||||
userId,
|
||||
createdAt: { gte: startDate },
|
||||
status: { in: ['PAID', 'SHIPPED', 'DELIVERED'] }
|
||||
}
|
||||
})
|
||||
|
||||
const teamOrders = await prisma.order.findMany({
|
||||
where: {
|
||||
userId: { in: allTeamMemberIds },
|
||||
createdAt: { gte: startDate },
|
||||
status: { in: ['PAID', 'SHIPPED', 'DELIVERED'] }
|
||||
}
|
||||
})
|
||||
|
||||
const personalVolume = userOrders.reduce((sum, o) => sum + o.total, 0)
|
||||
const teamVolume = teamOrders.reduce((sum, o) => sum + o.total, 0)
|
||||
|
||||
const reportData = {
|
||||
commissions: {
|
||||
total: totalCommissions,
|
||||
thisMonth: commissions.filter(c =>
|
||||
new Date(c.createdAt) >= new Date(new Date().getFullYear(), new Date().getMonth(), 1)
|
||||
).reduce((sum, c) => sum + c.amount, 0),
|
||||
lastMonth: previousTotal,
|
||||
growth,
|
||||
byLevel: commissionsByLevel.sort((a, b) => a.level - b.level),
|
||||
recent: commissions.slice(0, 10)
|
||||
},
|
||||
team: {
|
||||
totalMembers: allTeamMemberIds.length,
|
||||
activeMembers,
|
||||
newThisMonth,
|
||||
byLevel: [{ level: 1, count: directReferrals.length }] // Simplified for now
|
||||
},
|
||||
sales: {
|
||||
totalVolume: personalVolume + teamVolume,
|
||||
personalVolume,
|
||||
teamVolume,
|
||||
ordersCount: userOrders.length + teamOrders.length
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json(reportData)
|
||||
} catch (error) {
|
||||
console.error('Error fetching reports:', error)
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch reports' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
119
app/api/dashboard/route.ts
Normal file
119
app/api/dashboard/route.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { auth } from '@/auth'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const session = await auth()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const userId = session.user.id
|
||||
|
||||
// Get user's wallet
|
||||
const wallet = await prisma.wallet.findUnique({
|
||||
where: { userId }
|
||||
})
|
||||
|
||||
// Get commission stats
|
||||
const [totalEarnings, pendingCommissions, thisMonthEarnings] = await Promise.all([
|
||||
prisma.commission.aggregate({
|
||||
where: {
|
||||
userId,
|
||||
status: { in: ['APPROVED', 'PAID'] }
|
||||
},
|
||||
_sum: { amount: true }
|
||||
}),
|
||||
prisma.commission.aggregate({
|
||||
where: {
|
||||
userId,
|
||||
status: 'PENDING'
|
||||
},
|
||||
_sum: { amount: true }
|
||||
}),
|
||||
prisma.commission.aggregate({
|
||||
where: {
|
||||
userId,
|
||||
status: { in: ['APPROVED', 'PAID'] },
|
||||
createdAt: {
|
||||
gte: new Date(new Date().getFullYear(), new Date().getMonth(), 1)
|
||||
}
|
||||
},
|
||||
_sum: { amount: true }
|
||||
})
|
||||
])
|
||||
|
||||
// Get referral stats
|
||||
const [totalReferrals, activeReferrals] = await Promise.all([
|
||||
prisma.user.count({
|
||||
where: { referrerId: userId }
|
||||
}),
|
||||
prisma.user.count({
|
||||
where: {
|
||||
referrerId: userId,
|
||||
isActive: true
|
||||
}
|
||||
})
|
||||
])
|
||||
|
||||
// Get order stats
|
||||
const totalOrders = await prisma.order.count({
|
||||
where: { userId }
|
||||
})
|
||||
|
||||
// Get recent commissions
|
||||
const recentCommissions = await prisma.commission.findMany({
|
||||
where: { userId },
|
||||
include: {
|
||||
fromUser: {
|
||||
select: {
|
||||
name: true,
|
||||
email: true
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 5
|
||||
})
|
||||
|
||||
// Get recent orders
|
||||
const recentOrders = await prisma.order.findMany({
|
||||
where: { userId },
|
||||
include: {
|
||||
orderItems: {
|
||||
include: {
|
||||
product: {
|
||||
select: {
|
||||
name: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 5
|
||||
})
|
||||
|
||||
const stats = {
|
||||
totalEarnings: totalEarnings._sum.amount || 0,
|
||||
pendingCommissions: pendingCommissions._sum.amount || 0,
|
||||
thisMonthEarnings: thisMonthEarnings._sum.amount || 0,
|
||||
currentBalance: wallet?.balance || 0,
|
||||
totalReferrals,
|
||||
activeReferrals,
|
||||
totalOrders,
|
||||
recentCommissions,
|
||||
recentOrders
|
||||
}
|
||||
|
||||
return NextResponse.json({ stats })
|
||||
} catch (error) {
|
||||
console.error('Error fetching dashboard stats:', error)
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch dashboard stats' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
48
app/api/dashboard/stats/route.ts
Normal file
48
app/api/dashboard/stats/route.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { auth } from '@/auth'
|
||||
import { CommissionService } from '@/lib/commission'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const session = await auth()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const userId = session.user.id
|
||||
|
||||
// Get team stats
|
||||
const teamStats = await CommissionService.getTeamStats(userId)
|
||||
|
||||
// Get wallet info
|
||||
const wallet = await prisma.wallet.findUnique({
|
||||
where: { userId }
|
||||
})
|
||||
|
||||
// Get pending commissions
|
||||
const pendingCommissions = await prisma.commission.aggregate({
|
||||
where: {
|
||||
userId,
|
||||
status: 'PENDING'
|
||||
},
|
||||
_sum: { amount: true }
|
||||
})
|
||||
|
||||
const stats = {
|
||||
...teamStats,
|
||||
totalEarnings: wallet?.totalEarnings || 0,
|
||||
walletBalance: wallet?.balance || 0,
|
||||
pendingCommissions: pendingCommissions._sum.amount || 0
|
||||
}
|
||||
|
||||
return NextResponse.json(stats)
|
||||
} catch (error) {
|
||||
console.error('Error fetching dashboard stats:', error)
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch stats' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
100
app/api/dashboard/team/route.ts
Normal file
100
app/api/dashboard/team/route.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { auth } from '@/auth'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const session = await auth()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const userId = session.user.id
|
||||
|
||||
// Get direct referrals
|
||||
const directReferrals = await prisma.user.findMany({
|
||||
where: { referrerId: userId },
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
role: true,
|
||||
joinedAt: true,
|
||||
referrals: {
|
||||
select: {
|
||||
id: true
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: { joinedAt: 'desc' }
|
||||
})
|
||||
|
||||
// Get team statistics by levels
|
||||
const getAllTeamMembers = async (id: string, level: number = 1, maxLevel: number = 5): Promise<string[]> => {
|
||||
if (level > maxLevel) return []
|
||||
|
||||
const refs = await prisma.user.findMany({
|
||||
where: { referrerId: id },
|
||||
select: { id: true }
|
||||
})
|
||||
|
||||
let allMembers = refs.map(r => r.id)
|
||||
|
||||
if (level < maxLevel) {
|
||||
for (const ref of refs) {
|
||||
const subTeam = await getAllTeamMembers(ref.id, level + 1, maxLevel)
|
||||
allMembers = [...allMembers, ...subTeam]
|
||||
}
|
||||
}
|
||||
|
||||
return allMembers
|
||||
}
|
||||
|
||||
// Calculate team size per level
|
||||
const levels = []
|
||||
for (let level = 1; level <= 5; level++) {
|
||||
if (level === 1) {
|
||||
levels.push({ level, count: directReferrals.length })
|
||||
} else {
|
||||
// Get members at specific level
|
||||
const getLevelMembers = async (parentIds: string[], targetLevel: number, currentLevel: number = 1): Promise<string[]> => {
|
||||
if (currentLevel === targetLevel) return parentIds
|
||||
|
||||
const nextLevel = await prisma.user.findMany({
|
||||
where: { referrerId: { in: parentIds } },
|
||||
select: { id: true }
|
||||
})
|
||||
|
||||
if (nextLevel.length === 0 || currentLevel >= targetLevel) return []
|
||||
|
||||
return getLevelMembers(nextLevel.map(u => u.id), targetLevel, currentLevel + 1)
|
||||
}
|
||||
|
||||
const levelMemberIds = await getLevelMembers([userId], level)
|
||||
levels.push({ level, count: levelMemberIds.length })
|
||||
}
|
||||
}
|
||||
|
||||
const allTeamMemberIds = await getAllTeamMembers(userId)
|
||||
|
||||
const teamData = {
|
||||
directReferrals: directReferrals.map(ref => ({
|
||||
...ref,
|
||||
referrals: ref.referrals || []
|
||||
})),
|
||||
teamStats: {
|
||||
totalTeamSize: allTeamMemberIds.length,
|
||||
levels
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json(teamData)
|
||||
} catch (error) {
|
||||
console.error('Error fetching team data:', error)
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch team data' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
71
app/api/dashboard/wallet/route.ts
Normal file
71
app/api/dashboard/wallet/route.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
import { auth } from '@/auth'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const session = await auth()
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const userId = session.user.id
|
||||
|
||||
// Get wallet info
|
||||
const wallet = await prisma.wallet.findUnique({
|
||||
where: { userId }
|
||||
})
|
||||
|
||||
// Mock transaction history (you can implement proper transaction tracking)
|
||||
const commissions = await prisma.commission.findMany({
|
||||
where: { userId },
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 20,
|
||||
include: {
|
||||
fromUser: {
|
||||
select: { name: true }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const payouts = await prisma.payout.findMany({
|
||||
where: { userId },
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 20
|
||||
})
|
||||
|
||||
// Combine and format transactions
|
||||
const transactions = [
|
||||
...commissions.map(commission => ({
|
||||
id: commission.id,
|
||||
type: 'COMMISSION' as const,
|
||||
amount: commission.amount,
|
||||
description: `Level ${commission.level} commission from ${commission.fromUser.name}`,
|
||||
status: commission.status,
|
||||
createdAt: commission.createdAt
|
||||
})),
|
||||
...payouts.map(payout => ({
|
||||
id: payout.id,
|
||||
type: 'PAYOUT' as const,
|
||||
amount: payout.amount,
|
||||
description: 'Withdrawal request',
|
||||
status: payout.status,
|
||||
createdAt: payout.createdAt
|
||||
}))
|
||||
].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
|
||||
|
||||
return NextResponse.json({
|
||||
balance: wallet?.balance || 0,
|
||||
totalEarnings: wallet?.totalEarnings || 0,
|
||||
totalWithdrawn: wallet?.totalWithdrawn || 0,
|
||||
transactions
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error fetching wallet data:', error)
|
||||
return NextResponse.json(
|
||||
{ error: 'Failed to fetch wallet data' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user