72 lines
2.2 KiB
TypeScript
72 lines
2.2 KiB
TypeScript
'use server'
|
|
|
|
import { z } from 'zod'
|
|
import { db } from '@/lib/db'
|
|
import { courses, tees, holes } from '@/lib/db/schema'
|
|
import { auth } from '@/lib/auth'
|
|
import { headers } from 'next/headers'
|
|
import { revalidatePath } from 'next/cache'
|
|
|
|
const TeeInput = z.object({
|
|
name: z.string().min(1, 'Tee name required'),
|
|
color: z.string().regex(/^#[0-9a-fA-F]{6}$/),
|
|
courseRating: z.coerce.number().min(50).max(80),
|
|
slopeRating: z.coerce.number().int().min(55).max(155),
|
|
})
|
|
|
|
const HoleInput = z.object({
|
|
holeNumber: z.number().int().min(1).max(18),
|
|
par: z.number().int().min(3).max(5),
|
|
strokeIndex: z.number().int().min(1).max(18),
|
|
})
|
|
|
|
export const CreateCourseSchema = z.object({
|
|
name: z.string().min(1, 'Course name required').max(100),
|
|
par: z.number().int().min(27).max(90),
|
|
tees: z.array(TeeInput).min(1, 'At least one tee required'),
|
|
holes: z.array(HoleInput).min(9),
|
|
})
|
|
|
|
export type CreateCourseInput = z.infer<typeof CreateCourseSchema>
|
|
|
|
export async function createCourse(data: CreateCourseInput) {
|
|
const parsed = CreateCourseSchema.safeParse(data)
|
|
if (!parsed.success) return { error: parsed.error.issues[0]?.message ?? 'Invalid data' }
|
|
|
|
const session = await auth.api.getSession({ headers: await headers() })
|
|
if (!session) return { error: 'Not authenticated' }
|
|
|
|
// Validate par sum equals declared course par
|
|
const parSum = parsed.data.holes.reduce((s, h) => s + h.par, 0)
|
|
if (parSum !== parsed.data.par) {
|
|
return { error: `Sum of hole pars (${parSum}) does not equal course par (${parsed.data.par})` }
|
|
}
|
|
|
|
const [course] = await db
|
|
.insert(courses)
|
|
.values({ name: parsed.data.name, par: parsed.data.par, createdBy: session.user.id })
|
|
.returning({ id: courses.id })
|
|
|
|
await db.insert(tees).values(
|
|
parsed.data.tees.map((t) => ({
|
|
courseId: course.id,
|
|
name: t.name,
|
|
color: t.color,
|
|
courseRating: String(t.courseRating),
|
|
slopeRating: t.slopeRating,
|
|
})),
|
|
)
|
|
|
|
await db.insert(holes).values(
|
|
parsed.data.holes.map((h) => ({
|
|
courseId: course.id,
|
|
holeNumber: h.holeNumber,
|
|
par: h.par,
|
|
strokeIndex: h.strokeIndex,
|
|
})),
|
|
)
|
|
|
|
revalidatePath('/rounds/new')
|
|
return { courseId: course.id }
|
|
}
|