99 lines
2.9 KiB
TypeScript
99 lines
2.9 KiB
TypeScript
import { createClient } from '@/lib/supabase/server'
|
|
import { redirect } from 'next/navigation'
|
|
import Link from 'next/link'
|
|
import { buttonVariants } from '@/components/ui/button'
|
|
import { cn } from '@/lib/utils'
|
|
|
|
export default async function DashboardPage() {
|
|
const supabase = await createClient()
|
|
const {
|
|
data: { user },
|
|
} = await supabase.auth.getUser()
|
|
|
|
if (!user) redirect('/login')
|
|
|
|
type RoundRow = {
|
|
round: {
|
|
id: string
|
|
name: string | null
|
|
date: string
|
|
status: string
|
|
holes_count: number
|
|
course: { name: string } | null
|
|
tee: { name: string; color: string } | null
|
|
} | null
|
|
}
|
|
|
|
// Fetch rounds the user is participating in
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const { data: rounds } = (await (supabase as any)
|
|
.from('round_players')
|
|
.select(
|
|
`
|
|
round:rounds (
|
|
id, name, date, status, holes_count,
|
|
course:courses (name),
|
|
tee:tees (name, color)
|
|
)
|
|
`,
|
|
)
|
|
.eq('user_id', user.id)
|
|
.in('round.status', ['lobby', 'active'])
|
|
.order('round(date)', { ascending: false })) as { data: RoundRow[] | null }
|
|
|
|
return (
|
|
<div className="p-4 space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<h1 className="text-2xl font-bold">Rounds</h1>
|
|
<Link href="/rounds/new" className={cn(buttonVariants({ size: 'sm' }))}>
|
|
New round
|
|
</Link>
|
|
</div>
|
|
|
|
{!rounds?.length && (
|
|
<p className="text-muted-foreground text-sm py-8 text-center">
|
|
No active rounds. Start one!
|
|
</p>
|
|
)}
|
|
|
|
<div className="space-y-3">
|
|
{rounds?.map(({ round }) => {
|
|
if (!round) return null
|
|
return (
|
|
<Link
|
|
key={round.id}
|
|
href={round.status === 'active' ? `/rounds/${round.id}/scorecard` : `/rounds/${round.id}`}
|
|
className="block rounded-xl border p-4 space-y-1 hover:bg-muted transition-colors"
|
|
>
|
|
<div className="flex items-center justify-between">
|
|
<span className="font-semibold">{round.course?.name}</span>
|
|
<StatusBadge status={round.status} />
|
|
</div>
|
|
<div className="text-sm text-muted-foreground">
|
|
{round.name && <span>{round.name} · </span>}
|
|
{round.tee?.name} tees · {round.holes_count} holes ·{' '}
|
|
{new Date(round.date).toLocaleDateString()}
|
|
</div>
|
|
</Link>
|
|
)
|
|
})}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function StatusBadge({ status }: { status: string }) {
|
|
const styles = {
|
|
lobby: 'bg-yellow-100 text-yellow-800',
|
|
active: 'bg-green-100 text-green-800',
|
|
completed: 'bg-gray-100 text-gray-600',
|
|
}
|
|
return (
|
|
<span
|
|
className={`text-xs font-medium px-2 py-0.5 rounded-full ${styles[status as keyof typeof styles] ?? styles.completed}`}
|
|
>
|
|
{status}
|
|
</span>
|
|
)
|
|
}
|