133 lines
3.4 KiB
TypeScript
133 lines
3.4 KiB
TypeScript
import { auth } from '@/lib/auth'
|
|
import { db } from '@/lib/db'
|
|
import { rounds, roundPlayers, holes, scores, courses, tees, user } from '@/lib/db/schema'
|
|
import { eq, asc } from 'drizzle-orm'
|
|
import { redirect, notFound } from 'next/navigation'
|
|
import { headers } from 'next/headers'
|
|
import { ScorecardView } from '@/components/scorecard/scorecard-view'
|
|
|
|
export type Hole = {
|
|
id: string
|
|
holeNumber: number
|
|
par: number
|
|
strokeIndex: number
|
|
}
|
|
|
|
export type Player = {
|
|
userId: string
|
|
courseHandicap: number | null
|
|
handicapIndex: string | null
|
|
profile: { id: string; displayName: string; avatarUrl: string | null } | null
|
|
}
|
|
|
|
export type ScoreRow = {
|
|
holeId: string
|
|
playerId: string
|
|
strokes: number
|
|
}
|
|
|
|
export type RoundInfo = {
|
|
id: string
|
|
name: string | null
|
|
date: string
|
|
status: string
|
|
holesCount: number
|
|
createdBy: string
|
|
course: { name: string } | null
|
|
tee: { name: string; color: string } | null
|
|
}
|
|
|
|
export default async function ScorecardPage({
|
|
params,
|
|
}: {
|
|
params: Promise<{ id: string }>
|
|
}) {
|
|
const { id } = await params
|
|
const session = await auth.api.getSession({ headers: await headers() })
|
|
if (!session) redirect('/login')
|
|
|
|
const [round] = await db
|
|
.select({
|
|
id: rounds.id,
|
|
name: rounds.name,
|
|
date: rounds.date,
|
|
status: rounds.status,
|
|
holesCount: rounds.holesCount,
|
|
createdBy: rounds.createdBy,
|
|
courseId: rounds.courseId,
|
|
courseName: courses.name,
|
|
teeName: tees.name,
|
|
teeColor: tees.color,
|
|
})
|
|
.from(rounds)
|
|
.innerJoin(courses, eq(rounds.courseId, courses.id))
|
|
.innerJoin(tees, eq(rounds.teeId, tees.id))
|
|
.where(eq(rounds.id, id))
|
|
.limit(1)
|
|
|
|
if (!round) notFound()
|
|
if (round.status === 'lobby') redirect(`/rounds/${id}`)
|
|
|
|
const holeRows = await db
|
|
.select({
|
|
id: holes.id,
|
|
holeNumber: holes.holeNumber,
|
|
par: holes.par,
|
|
strokeIndex: holes.strokeIndex,
|
|
})
|
|
.from(holes)
|
|
.where(eq(holes.courseId, round.courseId))
|
|
.orderBy(asc(holes.holeNumber))
|
|
.limit(round.holesCount)
|
|
|
|
const playerRows = await db
|
|
.select({
|
|
userId: roundPlayers.userId,
|
|
courseHandicap: roundPlayers.courseHandicap,
|
|
handicapIndex: roundPlayers.handicapIndex,
|
|
displayName: user.name,
|
|
avatarUrl: user.image,
|
|
})
|
|
.from(roundPlayers)
|
|
.innerJoin(user, eq(roundPlayers.userId, user.id))
|
|
.where(eq(roundPlayers.roundId, id))
|
|
.orderBy(roundPlayers.joinedAt)
|
|
|
|
const scoreRows = await db
|
|
.select({ holeId: scores.holeId, playerId: scores.playerId, strokes: scores.strokes })
|
|
.from(scores)
|
|
.where(eq(scores.roundId, id))
|
|
|
|
const roundInfo: RoundInfo = {
|
|
id: round.id,
|
|
name: round.name,
|
|
date: round.date,
|
|
status: round.status,
|
|
holesCount: round.holesCount,
|
|
createdBy: round.createdBy,
|
|
course: { name: round.courseName },
|
|
tee: { name: round.teeName, color: round.teeColor },
|
|
}
|
|
|
|
const players: Player[] = playerRows.map((p) => ({
|
|
userId: p.userId,
|
|
courseHandicap: p.courseHandicap,
|
|
handicapIndex: p.handicapIndex,
|
|
profile: {
|
|
id: p.userId,
|
|
displayName: p.displayName,
|
|
avatarUrl: p.avatarUrl,
|
|
},
|
|
}))
|
|
|
|
return (
|
|
<ScorecardView
|
|
round={roundInfo}
|
|
holes={holeRows}
|
|
players={players}
|
|
initialScores={scoreRows}
|
|
currentUserId={session.user.id}
|
|
/>
|
|
)
|
|
}
|