98 lines
3.3 KiB
TypeScript
98 lines
3.3 KiB
TypeScript
import { redirect } from 'next/navigation'
|
|
import Link from 'next/link'
|
|
import { auth } from '@/lib/auth'
|
|
import { db } from '@/lib/db'
|
|
import { rounds, roundPlayers, courses, tees } from '@/lib/db/schema'
|
|
import { eq, inArray } from 'drizzle-orm'
|
|
import { buttonVariants } from '@/components/ui/button-variants'
|
|
import { cn } from '@/lib/utils'
|
|
import { headers } from 'next/headers'
|
|
|
|
export default async function DashboardPage() {
|
|
const session = await auth.api.getSession({ headers: await headers() })
|
|
if (!session) redirect('/login')
|
|
|
|
const memberships = await db
|
|
.select({ roundId: roundPlayers.roundId })
|
|
.from(roundPlayers)
|
|
.where(eq(roundPlayers.userId, session.user.id))
|
|
|
|
const roundIds = memberships.map((m) => m.roundId)
|
|
|
|
const activeRounds =
|
|
roundIds.length > 0
|
|
? await db
|
|
.select({
|
|
id: rounds.id,
|
|
name: rounds.name,
|
|
date: rounds.date,
|
|
status: rounds.status,
|
|
holesCount: rounds.holesCount,
|
|
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(inArray(rounds.id, roundIds))
|
|
.orderBy(rounds.date)
|
|
: []
|
|
|
|
const visibleRounds = activeRounds.filter((r) => r.status !== 'completed')
|
|
|
|
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>
|
|
|
|
{visibleRounds.length === 0 && (
|
|
<p className="py-8 text-center text-sm text-muted-foreground">
|
|
No active rounds. Start one!
|
|
</p>
|
|
)}
|
|
|
|
<div className="space-y-3">
|
|
{visibleRounds.map((round) => (
|
|
<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 transition-colors hover:bg-muted"
|
|
>
|
|
<div className="flex items-center justify-between">
|
|
<span className="font-semibold">{round.courseName}</span>
|
|
<StatusBadge status={round.status} />
|
|
</div>
|
|
<div className="text-sm text-muted-foreground">
|
|
{round.name && <span>{round.name} · </span>}
|
|
<span
|
|
className="inline-block h-2.5 w-2.5 rounded-full border align-middle mr-1"
|
|
style={{ backgroundColor: round.teeColor }}
|
|
/>
|
|
{round.teeName} · {round.holesCount} holes ·{' '}
|
|
{new Date(round.date).toLocaleDateString()}
|
|
</div>
|
|
</Link>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function StatusBadge({ status }: { status: string }) {
|
|
const styles: Record<string, string> = {
|
|
lobby: 'bg-yellow-100 text-yellow-800',
|
|
active: 'bg-green-100 text-green-800',
|
|
completed: 'bg-gray-100 text-gray-600',
|
|
}
|
|
return (
|
|
<span className={`rounded-full px-2 py-0.5 text-xs font-medium ${styles[status] ?? styles.completed}`}>
|
|
{status}
|
|
</span>
|
|
)
|
|
}
|