- Introduced recurring booking groups with the ability to create and cancel them. - Added database migrations for recurring bookings, including new tables and relationships. - Implemented handlers for creating and canceling recurring bookings in the admin booking module. - Enhanced existing booking services to support recurring bookings logic. - Updated API contract to include new schemas for recurring bookings. - Refactored existing code for improved readability and maintainability.
117 lines
3.8 KiB
TypeScript
117 lines
3.8 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
export const adminPaymentStatusSchema = z.enum(['active', 'no_plan', 'expired']);
|
|
|
|
export const adminComplexListItemSchema = z.object({
|
|
id: z.string(),
|
|
complexName: z.string(),
|
|
complexSlug: z.string(),
|
|
city: z.string().nullable(),
|
|
planCode: z.string().nullable(),
|
|
planName: z.string().nullable(),
|
|
userCount: z.number().int().nonnegative(),
|
|
courtCount: z.number().int().nonnegative(),
|
|
avgBookingsPerDay: z.number().nonnegative(),
|
|
paymentStatus: adminPaymentStatusSchema,
|
|
});
|
|
|
|
export const adminComplexStatsSchema = z.object({
|
|
id: z.string(),
|
|
complexName: z.string(),
|
|
complexSlug: z.string(),
|
|
city: z.string().nullable(),
|
|
adminEmail: z.string(),
|
|
planCode: z.string().nullable(),
|
|
planName: z.string().nullable(),
|
|
userCount: z.number().int().nonnegative(),
|
|
courtCount: z.number().int().nonnegative(),
|
|
totalBookings: z.number().int().nonnegative(),
|
|
avgBookingsPerDay: z.number().nonnegative(),
|
|
bookingsByStatus: z.object({
|
|
confirmed: z.number().int().nonnegative(),
|
|
cancelled: z.number().int().nonnegative(),
|
|
completed: z.number().int().nonnegative(),
|
|
noshow: z.number().int().nonnegative(),
|
|
}),
|
|
paymentStatus: adminPaymentStatusSchema,
|
|
});
|
|
|
|
export const adminCreatePlanSchema = z.object({
|
|
code: z.string().trim().min(1).max(10),
|
|
name: z.string().trim().min(1).max(30),
|
|
price: z.number().nonnegative(),
|
|
rules: z.any(),
|
|
});
|
|
|
|
export const adminUpdatePlanSchema = z.object({
|
|
name: z.string().trim().min(1).max(30).optional(),
|
|
price: z.number().nonnegative().optional(),
|
|
rules: z.any().optional(),
|
|
});
|
|
|
|
export const adminUserSchema = z.object({
|
|
id: z.string(),
|
|
name: z.string(),
|
|
email: z.string(),
|
|
role: z.string(),
|
|
banned: z.boolean(),
|
|
bannedAt: z.string().datetime().nullable(),
|
|
banReason: z.string().nullable(),
|
|
createdAt: z.string().datetime(),
|
|
complexCount: z.number().int().nonnegative(),
|
|
activeSessions: z.number().int().nonnegative(),
|
|
});
|
|
|
|
export const adminBlockUserSchema = z.object({
|
|
banReason: z.string().max(500).optional(),
|
|
});
|
|
|
|
export const adminGlobalStatsSchema = z.object({
|
|
totalComplexes: z.number().int().nonnegative(),
|
|
totalUsers: z.number().int().nonnegative(),
|
|
totalCourts: z.number().int().nonnegative(),
|
|
totalBookings: z.number().int().nonnegative(),
|
|
});
|
|
|
|
export const adminUserSessionSchema = z.object({
|
|
id: z.string(),
|
|
createdAt: z.string().datetime(),
|
|
expiresAt: z.string().datetime(),
|
|
ipAddress: z.string().nullable(),
|
|
userAgent: z.string().nullable(),
|
|
city: z.string().nullable(),
|
|
country: z.string().nullable(),
|
|
countryCode: z.string().nullable(),
|
|
});
|
|
|
|
export type AdminComplexListItem = z.infer<typeof adminComplexListItemSchema>;
|
|
export type AdminComplexStats = z.infer<typeof adminComplexStatsSchema>;
|
|
export type AdminCreatePlanInput = z.infer<typeof adminCreatePlanSchema>;
|
|
export type AdminUpdatePlanInput = z.infer<typeof adminUpdatePlanSchema>;
|
|
export type AdminUser = z.infer<typeof adminUserSchema>;
|
|
export type AdminBlockUserInput = z.infer<typeof adminBlockUserSchema>;
|
|
export type AdminGlobalStats = z.infer<typeof adminGlobalStatsSchema>;
|
|
export type AdminPaymentStatus = z.infer<typeof adminPaymentStatusSchema>;
|
|
export type AdminUserSession = z.infer<typeof adminUserSessionSchema>;
|
|
|
|
export const adminGeoCitySchema = z.object({
|
|
city: z.string(),
|
|
userCount: z.number().int().nonnegative(),
|
|
});
|
|
|
|
export const adminGeoCountrySchema = z.object({
|
|
country: z.string(),
|
|
countryCode: z.string(),
|
|
totalUsers: z.number().int().nonnegative(),
|
|
cities: z.array(adminGeoCitySchema),
|
|
});
|
|
|
|
export const adminGeoStatsSchema = z.object({
|
|
countries: z.array(adminGeoCountrySchema),
|
|
totalUniqueCountries: z.number().int().nonnegative(),
|
|
});
|
|
|
|
export type AdminGeoCity = z.infer<typeof adminGeoCitySchema>;
|
|
export type AdminGeoCountry = z.infer<typeof adminGeoCountrySchema>;
|
|
export type AdminGeoStats = z.infer<typeof adminGeoStatsSchema>;
|