Initial commit

This commit is contained in:
Jose Selesan
2026-04-08 22:53:11 -03:00
commit 9ae270609d
179 changed files with 28096 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
import type { CreateSportInput } from '@repo/api-contract'
import { Prisma } from '@/generated/prisma/client'
import type { AppContext } from '@/types/hono'
import { createSport } from '@/modules/sport/services/sport.service'
export async function createSportHandler(c: AppContext) {
const payload = c.req.valid('json' as never) as CreateSportInput
try {
const sport = await createSport(payload)
return c.json(sport, 201)
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
return c.json({ message: 'No se pudo crear el deporte.' }, 409)
}
throw error
}
}

View File

@@ -0,0 +1,7 @@
import type { AppContext } from '@/types/hono'
import { listSports } from '@/modules/sport/services/sport.service'
export async function listSportsHandler(c: AppContext) {
const sports = await listSports()
return c.json(sports)
}

View File

@@ -0,0 +1,27 @@
import type { UpdateSportInput } from '@repo/api-contract'
import { Prisma } from '@/generated/prisma/client'
import type { AppContext } from '@/types/hono'
import { getSportById, updateSport } from '@/modules/sport/services/sport.service'
type SportIdParams = { id: string }
export async function updateSportHandler(c: AppContext) {
const { id } = c.req.valid('param' as never) as SportIdParams
const payload = c.req.valid('json' as never) as UpdateSportInput
const existing = await getSportById(id)
if (!existing) {
return c.json({ message: 'Deporte no encontrado.' }, 404)
}
try {
const sport = await updateSport(id, payload)
return c.json(sport)
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
return c.json({ message: 'No se pudo actualizar el deporte.' }, 409)
}
throw error
}
}

View File

@@ -0,0 +1,96 @@
import { v7 as uuidv7 } from 'uuid'
import { Prisma } from '@/generated/prisma/client'
import { db } from '@/lib/prisma'
export type CreateSportInput = {
name: string
}
export type UpdateSportInput = {
name?: string
isActive?: boolean
}
function slugify(value: string): string {
return value
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.toLowerCase()
.trim()
.replace(/[^a-z0-9\s-]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-')
}
async function buildUniqueSlug(
source: string,
excludeSportId?: string,
): Promise<string> {
const base = slugify(source)
const fallback = base.length > 0 ? base : `sport-${uuidv7().slice(0, 8)}`
let candidate = fallback
let index = 1
while (true) {
const existing = await db.sport.findFirst({
where: {
slug: candidate,
...(excludeSportId
? {
id: {
not: excludeSportId,
},
}
: {}),
},
select: { id: true },
})
if (!existing) return candidate
index += 1
candidate = `${fallback}-${index}`
}
}
export async function listSports() {
return db.sport.findMany({
orderBy: { name: 'asc' },
})
}
export async function createSport(input: CreateSportInput) {
const slug = await buildUniqueSlug(input.name)
return db.sport.create({
data: {
id: uuidv7(),
name: input.name.trim(),
slug,
isActive: true,
},
})
}
export async function getSportById(id: string) {
return db.sport.findUnique({ where: { id } })
}
export async function updateSport(id: string, input: UpdateSportInput) {
const data: Prisma.SportUncheckedUpdateInput = {}
if (input.name) {
data.name = input.name
data.slug = await buildUniqueSlug(input.name, id)
}
if (input.isActive !== undefined) {
data.isActive = input.isActive
}
return db.sport.update({
where: { id },
data,
})
}

View File

@@ -0,0 +1,30 @@
import { zValidator } from '@hono/zod-validator'
import { createSportSchema, updateSportSchema } from '@repo/api-contract'
import { Hono } from 'hono'
import { z } from 'zod'
import { requireAuth } from '@/middlewares/require-auth.middleware'
import { requireSuperAdmin } from '@/middlewares/require-super-admin.middleware'
import { createSportHandler } from '@/modules/sport/handlers/create-sport.handler'
import { listSportsHandler } from '@/modules/sport/handlers/list-sports.handler'
import { updateSportHandler } from '@/modules/sport/handlers/update-sport.handler'
import type { AppEnv } from '@/types/hono'
export const sportRoutes = new Hono<AppEnv>()
const sportIdParamsSchema = z.object({ id: z.uuid() })
sportRoutes.use('*', requireAuth)
sportRoutes.get('/', listSportsHandler)
sportRoutes.post(
'/',
requireSuperAdmin,
zValidator('json', createSportSchema),
createSportHandler,
)
sportRoutes.patch(
'/:id',
requireSuperAdmin,
zValidator('param', sportIdParamsSchema),
zValidator('json', updateSportSchema),
updateSportHandler,
)