'use server' import { z } from 'zod' import { db } from '@/lib/db' import { scores, roundPlayers, rounds } from '@/lib/db/schema' import { eq, and } from 'drizzle-orm' import { auth } from '@/lib/auth' import { headers } from 'next/headers' const UpsertScoreSchema = z.object({ roundId: z.string().uuid(), holeId: z.string().uuid(), playerId: z.string(), strokes: z.number().int().min(1).max(20), }) export async function upsertScore( roundId: string, holeId: string, playerId: string, strokes: number, ) { const parsed = UpsertScoreSchema.safeParse({ roundId, holeId, playerId, strokes }) 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' } // Caller must be a member of the round const [membership] = await db .select() .from(roundPlayers) .where(and(eq(roundPlayers.roundId, roundId), eq(roundPlayers.userId, session.user.id))) .limit(1) if (!membership) return { error: 'Not a member of this round' } // Round must be active const [round] = await db .select({ status: rounds.status }) .from(rounds) .where(eq(rounds.id, roundId)) .limit(1) if (round?.status !== 'active') return { error: 'Round is not active' } await db .insert(scores) .values({ roundId, holeId, playerId, strokes, updatedBy: session.user.id, updatedAt: new Date(), }) .onConflictDoUpdate({ target: [scores.roundId, scores.holeId, scores.playerId], set: { strokes, updatedBy: session.user.id, updatedAt: new Date() }, }) return { success: true } }