diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 1322519..b8a8fff 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -1,11 +1,21 @@ import { AppShell } from "@/components/app-shell"; import { StatusBadge } from "@/components/status-badge"; import { SYSTEM_PERMISSIONS } from "@/lib/access"; +import { requireCurrentUser, userIsAdmin } from "@/lib/session"; +import { requireInitialSetup } from "@/lib/setup"; import { rooms } from "@/lib/sample-data"; +import { redirect } from "next/navigation"; + +export default async function AdminPage() { + await requireInitialSetup(); + const user = await requireCurrentUser(); + + if (!userIsAdmin(user)) { + redirect("/dashboard"); + } -export default function AdminPage() { return ( - +

Admin

diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index afbd92f..d7e29b8 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -1,14 +1,16 @@ import { AppShell } from "@/components/app-shell"; import { RoomConsole } from "@/components/room-console"; import { StatusBadge } from "@/components/status-badge"; -import { getCurrentUser } from "@/lib/session"; +import { requireCurrentUser, userIsAdmin } from "@/lib/session"; +import { requireInitialSetup } from "@/lib/setup"; import { dashboardStats, friends, rooms } from "@/lib/sample-data"; export default async function DashboardPage() { - const user = await getCurrentUser(); + await requireInitialSetup(); + const user = await requireCurrentUser(); return ( - +

Dashboard

diff --git a/src/app/friends/page.tsx b/src/app/friends/page.tsx index 1ec8544..769123d 100644 --- a/src/app/friends/page.tsx +++ b/src/app/friends/page.tsx @@ -1,10 +1,15 @@ import { AppShell } from "@/components/app-shell"; import { StatusBadge } from "@/components/status-badge"; +import { requireCurrentUser, userIsAdmin } from "@/lib/session"; +import { requireInitialSetup } from "@/lib/setup"; import { friends } from "@/lib/sample-data"; -export default function FriendsPage() { +export default async function FriendsPage() { + await requireInitialSetup(); + const user = await requireCurrentUser(); + return ( - +

Friends

diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index 49f9865..4f4b357 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -1,7 +1,13 @@ import Link from "next/link"; import { loginUser } from "@/lib/user-actions"; +import { hasAdminUser } from "@/lib/setup"; +import { redirect } from "next/navigation"; + +export default async function LoginPage() { + if (!(await hasAdminUser())) { + redirect("/setup"); + } -export default function LoginPage() { return (
diff --git a/src/app/page.tsx b/src/app/page.tsx index 9ef1235..8c82da7 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,5 +1,10 @@ import { redirect } from "next/navigation"; +import { hasAdminUser } from "@/lib/setup"; + +export default async function HomePage() { + if (!(await hasAdminUser())) { + redirect("/setup"); + } -export default function HomePage() { redirect("/dashboard"); } diff --git a/src/app/register/page.tsx b/src/app/register/page.tsx index bd8ede5..37776e4 100644 --- a/src/app/register/page.tsx +++ b/src/app/register/page.tsx @@ -1,7 +1,13 @@ import Link from "next/link"; import { registerUser } from "@/lib/user-actions"; +import { hasAdminUser } from "@/lib/setup"; +import { redirect } from "next/navigation"; + +export default async function RegisterPage() { + if (!(await hasAdminUser())) { + redirect("/setup"); + } -export default function RegisterPage() { return (
diff --git a/src/app/rooms/[slug]/page.tsx b/src/app/rooms/[slug]/page.tsx index 9b9d5f9..b491013 100644 --- a/src/app/rooms/[slug]/page.tsx +++ b/src/app/rooms/[slug]/page.tsx @@ -1,13 +1,17 @@ import { AppShell } from "@/components/app-shell"; import { RoomConsole } from "@/components/room-console"; import { StatusBadge } from "@/components/status-badge"; +import { requireCurrentUser, userIsAdmin } from "@/lib/session"; +import { requireInitialSetup } from "@/lib/setup"; export default async function RoomPage({ params }: { params: Promise<{ slug: string }> }) { + await requireInitialSetup(); + const user = await requireCurrentUser(); const { slug } = await params; const roomSlug = decodeURIComponent(slug); return ( - +

{roomSlug}

diff --git a/src/app/setup/page.tsx b/src/app/setup/page.tsx index 1f3dcdd..3c2432e 100644 --- a/src/app/setup/page.tsx +++ b/src/app/setup/page.tsx @@ -3,21 +3,10 @@ import { hash } from "bcryptjs"; import { prisma } from "@/lib/prisma"; import { SYSTEM_PERMISSIONS } from "@/lib/access"; import { setSession } from "@/lib/session"; +import { hasAdminUser } from "@/lib/setup"; export const dynamic = "force-dynamic"; -async function hasAdmin() { - try { - const admin = await prisma.userRole.findFirst({ - where: { role: { name: "admin" } }, - select: { userId: true } - }); - return Boolean(admin); - } catch { - return false; - } -} - async function createFirstAdmin(formData: FormData) { "use server"; @@ -95,7 +84,7 @@ async function createFirstAdmin(formData: FormData) { } export default async function SetupPage() { - if (await hasAdmin()) { + if (await hasAdminUser()) { redirect("/login"); } diff --git a/src/components/app-shell.tsx b/src/components/app-shell.tsx index fba6213..4dda999 100644 --- a/src/components/app-shell.tsx +++ b/src/components/app-shell.tsx @@ -1,15 +1,23 @@ import Link from "next/link"; -import { Gauge, MonitorPlay, Shield, UserRoundPlus, UsersRound } from "lucide-react"; +import { Gauge, MonitorPlay, Shield, UsersRound } from "lucide-react"; const nav = [ { href: "/dashboard", label: "Dashboard", icon: Gauge }, { href: "/rooms/@admin", label: "Rooms", icon: MonitorPlay }, - { href: "/friends", label: "Friends", icon: UsersRound }, - { href: "/admin", label: "Admin", icon: Shield }, - { href: "/setup", label: "Setup", icon: UserRoundPlus } + { href: "/friends", label: "Friends", icon: UsersRound } ]; -export function AppShell({ children, active = "Dashboard" }: { children: React.ReactNode; active?: string }) { +export function AppShell({ + children, + active = "Dashboard", + isAdmin = false +}: { + children: React.ReactNode; + active?: string; + isAdmin?: boolean; +}) { + const visibleNav = isAdmin ? [...nav, { href: "/admin", label: "Admin", icon: Shield }] : nav; + return (