Refactor to vertical slice

This commit is contained in:
Jose Selesan
2026-06-26 14:05:37 -03:00
parent 3949c9add1
commit c8477de5d2
149 changed files with 5011 additions and 5127 deletions

View File

@@ -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;
});
}