81 lines
2.1 KiB
TypeScript
81 lines
2.1 KiB
TypeScript
import { db } from '@/lib/prisma';
|
|
|
|
type ComplexStats = {
|
|
id: string;
|
|
complexName: string;
|
|
complexSlug: string;
|
|
city: string | null;
|
|
planCode: string | null;
|
|
planName: string | null;
|
|
userCount: number;
|
|
courtCount: number;
|
|
totalBookings: number;
|
|
avgBookingsPerDay: number;
|
|
bookingsByStatus: {
|
|
confirmed: number;
|
|
cancelled: number;
|
|
completed: number;
|
|
noshow: number;
|
|
};
|
|
paymentStatus: 'active' | 'no_plan' | 'expired';
|
|
};
|
|
|
|
export async function getComplexStatsList(): Promise<ComplexStats[]> {
|
|
const complexes = await db.complex.findMany({
|
|
include: {
|
|
plan: true,
|
|
users: true,
|
|
courts: {
|
|
include: {
|
|
bookings: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
return complexes.map((complex) => {
|
|
const courtCount = complex.courts.length;
|
|
const allBookings = complex.courts.flatMap((c) => c.bookings);
|
|
|
|
const bookingsByStatus = {
|
|
confirmed: allBookings.filter((b) => b.status === 'CONFIRMED').length,
|
|
cancelled: allBookings.filter((b) => b.status === 'CANCELLED').length,
|
|
completed: allBookings.filter((b) => b.status === 'COMPLETED').length,
|
|
noshow: allBookings.filter((b) => b.status === 'NOSHOW').length,
|
|
};
|
|
|
|
const totalBookings = allBookings.length;
|
|
|
|
let avgBookingsPerDay = 0;
|
|
if (allBookings.length > 0) {
|
|
const dates = allBookings.map((b) => b.bookingDate);
|
|
const minDate = new Date(Math.min(...dates.map((d) => d.getTime())));
|
|
const daysDiff = Math.max(
|
|
1,
|
|
Math.ceil((Date.now() - minDate.getTime()) / (1000 * 60 * 60 * 24))
|
|
);
|
|
avgBookingsPerDay = Math.round((totalBookings / daysDiff) * 100) / 100;
|
|
}
|
|
|
|
let paymentStatus: 'active' | 'no_plan' | 'expired' = 'no_plan';
|
|
if (complex.plan) {
|
|
paymentStatus = 'active';
|
|
}
|
|
|
|
return {
|
|
id: complex.id,
|
|
complexName: complex.complexName,
|
|
complexSlug: complex.complexSlug,
|
|
city: complex.city,
|
|
planCode: complex.planCode,
|
|
planName: complex.plan?.name ?? null,
|
|
userCount: complex.users.length,
|
|
courtCount,
|
|
totalBookings,
|
|
avgBookingsPerDay,
|
|
bookingsByStatus,
|
|
paymentStatus,
|
|
};
|
|
});
|
|
}
|