171 lines
5.2 KiB
TypeScript
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 }
|
|
)
|
|
}
|
|
}
|