Files
WatchLink/src/app/rooms/[slug]/page.tsx
MrSphay 2f0b54b94e
All checks were successful
Release Dry Run / release-dry-run (push) Successful in 1m30s
Template Compliance / compliance (push) Successful in 5s
Build / build (push) Successful in 11m24s
Fix first setup server error handling
2026-05-15 18:20:01 +02:00

119 lines
3.7 KiB
TypeScript

import { AppShell } from "@/components/app-shell";
import { RoomConsole } from "@/components/room-console";
import { StatusBadge } from "@/components/status-badge";
import { canEnterRoom } from "@/lib/access";
import { prisma } from "@/lib/prisma";
import { requireCurrentUser, userIsAdmin } from "@/lib/session";
import { requireInitialSetup } from "@/lib/setup";
import { redirect } from "next/navigation";
export const dynamic = "force-dynamic";
export default async function RoomPage({ params }: { params: Promise<{ slug: string }> }) {
await requireInitialSetup();
const user = await requireCurrentUser();
const isAdmin = userIsAdmin(user);
const { slug } = await params;
const roomSlug = decodeURIComponent(slug);
const room = await prisma.room.findUnique({
where: { slug: roomSlug },
include: {
owner: true,
members: { include: { user: true } },
mediaSources: { include: { submitter: true }, orderBy: { createdAt: "desc" }, take: 20 }
}
});
if (!room) {
redirect("/dashboard");
}
const isOwner = room.ownerId === user.id;
const explicitMember = room.members.some((member) => member.userId === user.id);
const isFriend = room.ownerId
? Boolean(
await prisma.friendship.findFirst({
where: {
status: "ACCEPTED",
OR: [
{ requesterId: user.id, receiverId: room.ownerId },
{ requesterId: room.ownerId, receiverId: user.id }
]
},
select: { id: true }
})
)
: false;
if (
!canEnterRoom({
visibility: room.visibility,
isOwner,
isAdmin,
isFriend,
explicitMember,
hasRoomRole: explicitMember
})
) {
redirect("/dashboard");
}
const personalRoom = await prisma.room.findFirst({ where: { ownerId: user.id }, select: { slug: true } });
return (
<AppShell
active="Rooms"
isAdmin={isAdmin}
roomHref={personalRoom ? `/rooms/${encodeURIComponent(personalRoom.slug)}` : "/dashboard"}
userName={user.displayName || user.username}
>
<header className="topbar">
<div className="title-block">
<h1>{room.name}</h1>
<p>{room.owner ? `Owned by ${room.owner.displayName || room.owner.username}` : "Shared watch room"}</p>
</div>
<div className="status-row">
<StatusBadge tone="good">Online</StatusBadge>
<StatusBadge>{room.visibility}</StatusBadge>
</div>
</header>
<RoomConsole
roomId={room.id}
roomSlug={room.slug}
currentUser={user.displayName || user.username}
queue={room.mediaSources.map((item) => ({
id: item.id,
title: item.title || item.originalUrl,
provider: item.provider,
originalUrl: item.originalUrl,
playbackUrl: item.playbackUrl,
by: item.submitter?.displayName || item.submitter?.username || "Unknown",
createdAt: formatDate(item.createdAt)
}))}
participants={[
...(room.owner
? [
{
id: room.owner.id,
name: room.owner.displayName || room.owner.username,
role: "Owner",
status: room.owner.id === user.id ? "Online" : "Available"
}
]
: []),
...room.members.map((member) => ({
id: member.userId,
name: member.user.displayName || member.user.username,
role: member.canManage ? "Manager" : "Member",
status: member.userId === user.id ? "Online" : "Allowed"
}))
]}
/>
</AppShell>
);
}
function formatDate(date: Date) {
return new Intl.DateTimeFormat("en", { month: "short", day: "numeric" }).format(date);
}