letsbe-hub/src/app/api/v1/admin/stats/route.ts

171 lines
5.2 KiB
TypeScript

import { NextResponse } from 'next/server'
import { auth } from '@/lib/auth'
import { prisma } from '@/lib/prisma'
import { OrderStatus, SubscriptionPlan, SubscriptionTier, UserStatus, SubscriptionStatus } from '@prisma/client'
/**
* GET /api/v1/admin/stats
* Get dashboard statistics
*/
export async function GET() {
try {
const session = await auth()
if (!session || session.user.userType !== 'staff') {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
// Get order counts by status
const ordersByStatus = await prisma.order.groupBy({
by: ['status'],
_count: { status: true },
})
const orderStatusCounts: Record<OrderStatus, number> = Object.fromEntries(
Object.values(OrderStatus).map((status) => [status, 0])
) as Record<OrderStatus, number>
ordersByStatus.forEach((item) => {
orderStatusCounts[item.status] = item._count.status
})
// Calculate order statistics
const pendingStatuses = [
OrderStatus.PAYMENT_CONFIRMED,
OrderStatus.AWAITING_SERVER,
OrderStatus.SERVER_READY,
OrderStatus.DNS_PENDING,
OrderStatus.DNS_READY,
]
const inProgressStatuses = [OrderStatus.PROVISIONING]
const completedStatuses = [OrderStatus.FULFILLED, OrderStatus.EMAIL_CONFIGURED]
const failedStatuses = [OrderStatus.FAILED]
const ordersPending = pendingStatuses.reduce(
(sum, status) => sum + orderStatusCounts[status],
0
)
const ordersInProgress = inProgressStatuses.reduce(
(sum, status) => sum + orderStatusCounts[status],
0
)
const ordersCompleted = completedStatuses.reduce(
(sum, status) => sum + orderStatusCounts[status],
0
)
const ordersFailed = failedStatuses.reduce(
(sum, status) => sum + orderStatusCounts[status],
0
)
// Get customer counts by status
const customersByStatus = await prisma.user.groupBy({
by: ['status'],
_count: { status: true },
})
const customerStatusCounts: Record<UserStatus, number> = Object.fromEntries(
Object.values(UserStatus).map((status) => [status, 0])
) as Record<UserStatus, number>
customersByStatus.forEach((item) => {
customerStatusCounts[item.status] = item._count.status
})
// Get subscription counts
const subscriptionsByPlan = await prisma.subscription.groupBy({
by: ['plan'],
_count: { plan: true },
})
const subscriptionsByTier = await prisma.subscription.groupBy({
by: ['tier'],
_count: { tier: true },
})
const subscriptionsByStatusRaw = await prisma.subscription.groupBy({
by: ['status'],
_count: { status: true },
})
const planCounts: Record<SubscriptionPlan, number> = Object.fromEntries(
Object.values(SubscriptionPlan).map((plan) => [plan, 0])
) as Record<SubscriptionPlan, number>
subscriptionsByPlan.forEach((item) => {
planCounts[item.plan] = item._count.plan
})
const tierCounts: Record<SubscriptionTier, number> = Object.fromEntries(
Object.values(SubscriptionTier).map((tier) => [tier, 0])
) as Record<SubscriptionTier, number>
subscriptionsByTier.forEach((item) => {
tierCounts[item.tier] = item._count.tier
})
const subscriptionStatusCounts: Record<SubscriptionStatus, number> = Object.fromEntries(
Object.values(SubscriptionStatus).map((status) => [status, 0])
) as Record<SubscriptionStatus, number>
subscriptionsByStatusRaw.forEach((item) => {
subscriptionStatusCounts[item.status] = item._count.status
})
// Get recent orders
const recentOrders = await prisma.order.findMany({
take: 5,
orderBy: { createdAt: 'desc' },
include: {
user: {
select: {
id: true,
name: true,
email: true,
company: true,
},
},
_count: {
select: { provisioningLogs: true },
},
},
})
// Calculate totals
const ordersTotal = Object.values(orderStatusCounts).reduce((a, b) => a + b, 0)
const customersTotal = Object.values(customerStatusCounts).reduce((a, b) => a + b, 0)
const subscriptionsTotal = Object.values(planCounts).reduce((a, b) => a + b, 0)
return NextResponse.json({
orders: {
total: ordersTotal,
pending: ordersPending,
inProgress: ordersInProgress,
completed: ordersCompleted,
failed: ordersFailed,
byStatus: orderStatusCounts,
},
customers: {
total: customersTotal,
active: customerStatusCounts[UserStatus.ACTIVE],
suspended: customerStatusCounts[UserStatus.SUSPENDED],
pending: customerStatusCounts[UserStatus.PENDING_VERIFICATION],
},
subscriptions: {
total: subscriptionsTotal,
trial: subscriptionStatusCounts[SubscriptionStatus.TRIAL],
active: subscriptionStatusCounts[SubscriptionStatus.ACTIVE],
byPlan: planCounts,
byTier: tierCounts,
},
recentOrders,
})
} catch (error) {
console.error('Error getting dashboard stats:', error)
return NextResponse.json(
{ error: 'Failed to get dashboard stats' },
{ status: 500 }
)
}
}