Initial commit v1
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
import { createClient } from '@/lib/supabase/server'
|
||||
import { redirect, notFound } from 'next/navigation'
|
||||
import { JoinRound } from '@/components/round/join-round'
|
||||
|
||||
export default async function JoinRoundPage({ params }: { params: Promise<{ id: string }> }) {
|
||||
const { id } = await params
|
||||
const supabase = await createClient()
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const db = supabase as any
|
||||
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser()
|
||||
if (!user) redirect(`/login`)
|
||||
|
||||
const { data: round } = await db
|
||||
.from('rounds')
|
||||
.select(
|
||||
`
|
||||
id, name, date, holes_count, status, created_by,
|
||||
course:courses (name),
|
||||
tee:tees (name, color),
|
||||
round_players (user_id)
|
||||
`,
|
||||
)
|
||||
.eq('id', id)
|
||||
.single()
|
||||
|
||||
if (!round) notFound()
|
||||
|
||||
// Already a member — go straight to the round
|
||||
const alreadyJoined = round.round_players?.some(
|
||||
(p: { user_id: string }) => p.user_id === user.id,
|
||||
)
|
||||
if (alreadyJoined) redirect(`/rounds/${id}`)
|
||||
|
||||
// Round must be in lobby to join
|
||||
if (round.status !== 'lobby') {
|
||||
redirect(`/dashboard`)
|
||||
}
|
||||
|
||||
return <JoinRound round={round} userId={user.id} />
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { createClient } from '@/lib/supabase/server'
|
||||
import { redirect, notFound } from 'next/navigation'
|
||||
import { RoundLobby } from '@/components/round/round-lobby'
|
||||
|
||||
export default async function RoundPage({ params }: { params: Promise<{ id: string }> }) {
|
||||
const { id } = await params
|
||||
const supabase = await createClient()
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const db = supabase as any
|
||||
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser()
|
||||
if (!user) redirect('/login')
|
||||
|
||||
const { data: round } = await db
|
||||
.from('rounds')
|
||||
.select(
|
||||
`
|
||||
id, name, date, status, holes_count, created_by,
|
||||
course:courses (id, name, par),
|
||||
tee:tees (id, name, color, course_rating, slope_rating)
|
||||
`,
|
||||
)
|
||||
.eq('id', id)
|
||||
.single()
|
||||
|
||||
if (!round) notFound()
|
||||
|
||||
const { data: players } = await db
|
||||
.from('round_players')
|
||||
.select(
|
||||
`
|
||||
id, role, handicap_index, course_handicap, joined_at,
|
||||
profile:profiles (id, display_name, avatar_url)
|
||||
`,
|
||||
)
|
||||
.eq('round_id', id)
|
||||
.order('joined_at')
|
||||
|
||||
const { data: invites } = await db
|
||||
.from('round_invites')
|
||||
.select('id, email, accepted_at, created_at')
|
||||
.eq('round_id', id)
|
||||
.is('accepted_at', null)
|
||||
.order('created_at')
|
||||
|
||||
const isCreator = round.created_by === user.id
|
||||
|
||||
if (round.status === 'active' || round.status === 'completed') {
|
||||
redirect(`/rounds/${id}/scorecard`)
|
||||
}
|
||||
|
||||
return (
|
||||
<RoundLobby
|
||||
round={round}
|
||||
players={players ?? []}
|
||||
pendingInvites={invites ?? []}
|
||||
currentUserId={user.id}
|
||||
isCreator={isCreator}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import { createClient } from '@/lib/supabase/server'
|
||||
import { redirect, notFound } from 'next/navigation'
|
||||
import { ScorecardView } from '@/components/scorecard/scorecard-view'
|
||||
|
||||
export type Hole = {
|
||||
id: string
|
||||
hole_number: number
|
||||
par: number
|
||||
stroke_index: number
|
||||
}
|
||||
|
||||
export type Player = {
|
||||
user_id: string
|
||||
course_handicap: number | null
|
||||
handicap_index: number | null
|
||||
profile: { id: string; display_name: string; avatar_url: string | null } | null
|
||||
}
|
||||
|
||||
export type ScoreRow = {
|
||||
hole_id: string
|
||||
player_id: string
|
||||
strokes: number
|
||||
}
|
||||
|
||||
export type RoundInfo = {
|
||||
id: string
|
||||
name: string | null
|
||||
date: string
|
||||
status: string
|
||||
holes_count: number
|
||||
created_by: 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 supabase = await createClient()
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const db = supabase as any
|
||||
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser()
|
||||
if (!user) redirect('/login')
|
||||
|
||||
const { data: round } = await db
|
||||
.from('rounds')
|
||||
.select(
|
||||
`id, name, date, status, holes_count, created_by,
|
||||
course:courses (name),
|
||||
tee:tees (name, color)`,
|
||||
)
|
||||
.eq('id', id)
|
||||
.single()
|
||||
|
||||
if (!round) notFound()
|
||||
if (round.status === 'lobby') redirect(`/rounds/${id}`)
|
||||
|
||||
// Holes ordered by hole_number, limited to holes_count
|
||||
const { data: holes } = await db
|
||||
.from('holes')
|
||||
.select('id, hole_number, par, stroke_index')
|
||||
.eq('course_id', await getCourseId(db, id))
|
||||
.order('hole_number')
|
||||
.limit(round.holes_count)
|
||||
|
||||
const { data: players } = await db
|
||||
.from('round_players')
|
||||
.select(
|
||||
`user_id, course_handicap, handicap_index,
|
||||
profile:profiles (id, display_name, avatar_url)`,
|
||||
)
|
||||
.eq('round_id', id)
|
||||
.order('joined_at')
|
||||
|
||||
const { data: scores } = await db
|
||||
.from('scores')
|
||||
.select('hole_id, player_id, strokes')
|
||||
.eq('round_id', id)
|
||||
|
||||
return (
|
||||
<ScorecardView
|
||||
round={round as RoundInfo}
|
||||
holes={(holes as Hole[]) ?? []}
|
||||
players={(players as Player[]) ?? []}
|
||||
initialScores={(scores as ScoreRow[]) ?? []}
|
||||
currentUserId={user.id}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
async function getCourseId(db: any, roundId: string): Promise<string> {
|
||||
const { data } = await db
|
||||
.from('rounds')
|
||||
.select('course_id')
|
||||
.eq('id', roundId)
|
||||
.single()
|
||||
return data?.course_id ?? ''
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { createClient } from '@/lib/supabase/server'
|
||||
import { NewRoundWizard } from '@/components/round/new-round-wizard'
|
||||
|
||||
type Tee = {
|
||||
id: string
|
||||
name: string
|
||||
color: string
|
||||
course_rating: number
|
||||
slope_rating: number
|
||||
}
|
||||
|
||||
type Course = {
|
||||
id: string
|
||||
name: string
|
||||
par: number
|
||||
tees: Tee[]
|
||||
}
|
||||
|
||||
export default async function NewRoundPage() {
|
||||
const supabase = await createClient()
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const { data: courses } = await (supabase as any)
|
||||
.from('courses')
|
||||
.select('id, name, par, tees(id, name, color, course_rating, slope_rating)')
|
||||
.order('name')
|
||||
|
||||
return <NewRoundWizard courses={(courses as Course[]) ?? []} />
|
||||
}
|
||||
Reference in New Issue
Block a user