Refactor to vertical slice
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
import { db } from '@/lib/prisma';
|
||||
import { buildUniqueSlug, slugify } from '@/lib/slug';
|
||||
import { ensureActiveSport } from '@/modules/court/shared/guards';
|
||||
import type { CreateComplexInput } from '@repo/api-contract';
|
||||
import { v7 as uuidv7 } from 'uuid';
|
||||
|
||||
type DayOfWeek = 'MONDAY' | 'TUESDAY' | 'WEDNESDAY' | 'THURSDAY' | 'FRIDAY' | 'SATURDAY' | 'SUNDAY';
|
||||
|
||||
type CreateComplexInternalInput = CreateComplexInput & {
|
||||
adminEmail: string;
|
||||
userId?: string;
|
||||
};
|
||||
|
||||
function toMinutes(value: string): number {
|
||||
const [hours, minutes] = value.split(':').map((part) => Number(part));
|
||||
return hours * 60 + minutes;
|
||||
}
|
||||
|
||||
function assertAvailabilityRanges(
|
||||
availability: Array<{
|
||||
dayOfWeek: DayOfWeek;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
}>
|
||||
) {
|
||||
for (const range of availability) {
|
||||
const start = toMinutes(range.startTime);
|
||||
const end = toMinutes(range.endTime);
|
||||
if (start >= end) {
|
||||
throw new Error(`El rango ${range.startTime}-${range.endTime} es inválido.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function createComplex(input: CreateComplexInternalInput) {
|
||||
return db.$transaction(async (tx) => {
|
||||
const base = slugify(input.complexName);
|
||||
const fallback = base.length > 0 ? base : `complex-${uuidv7().slice(0, 8)}`;
|
||||
const complexSlug = await buildUniqueSlug(fallback, (slug) =>
|
||||
tx.complex.findFirst({ where: { complexSlug: slug }, select: { id: true } })
|
||||
);
|
||||
|
||||
const complex = await tx.complex.create({
|
||||
data: {
|
||||
id: uuidv7(),
|
||||
complexName: input.complexName,
|
||||
physicalAddress: input.physicalAddress.trim(),
|
||||
city: input.city?.trim() || null,
|
||||
state: input.state?.trim() || null,
|
||||
country: input.country?.trim() || null,
|
||||
complexSlug,
|
||||
adminEmail: input.adminEmail,
|
||||
planCode: input.planCode,
|
||||
},
|
||||
});
|
||||
|
||||
if (input.userId) {
|
||||
await tx.complexUser.create({
|
||||
data: {
|
||||
complexId: complex.id,
|
||||
userId: input.userId,
|
||||
role: 'ADMIN',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (input.setupCourts && input.courtSportId) {
|
||||
const sport = await ensureActiveSport(input.courtSportId);
|
||||
const availability = (input.courtDaysOfWeek ?? []).map((day) => ({
|
||||
dayOfWeek: day as DayOfWeek,
|
||||
startTime: input.courtStartTime ?? '08:00',
|
||||
endTime: input.courtEndTime ?? '22:00',
|
||||
}));
|
||||
|
||||
assertAvailabilityRanges(availability);
|
||||
|
||||
const court = await tx.court.create({
|
||||
data: {
|
||||
id: uuidv7(),
|
||||
complexId: complex.id,
|
||||
sportId: input.courtSportId,
|
||||
name: `${sport.name} 1`,
|
||||
slotDurationMinutes: 60,
|
||||
basePrice: 0,
|
||||
},
|
||||
});
|
||||
|
||||
await tx.courtAvailability.createMany({
|
||||
data: availability.map((avail) => ({
|
||||
id: uuidv7(),
|
||||
courtId: court.id,
|
||||
dayOfWeek: avail.dayOfWeek,
|
||||
startTime: avail.startTime,
|
||||
endTime: avail.endTime,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
return complex;
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user