waveform/app/(app)/dm/[conversationId]/page.tsx

106 lines
2.9 KiB
TypeScript

/**
* @file app/(app)/dm/[conversationId]/page.tsx
* @description Server component for direct message conversation pages, handling authentication, route validation, database fetching, and layout rendering.
*/
import { auth } from "@/auth";
import { db } from "@/db";
import { conversations, directMessages } from "@/db/schema";
import { and, eq, or } from "drizzle-orm";
import { redirect } from "next/navigation";
import { AppHeader } from "@/components/layout/AppHeader";
import { ChatInput } from "@/components/chat/ChatInput";
import { ChatMessages } from "@/components/chat/ChatMessages";
import type { MessageWithMember } from "@/components/chat/ChatItem";
import { isValidUuid } from "@/lib/utils";
import { getUserFriendships } from "@/lib/services/friends.service";
import AppFooter from "@/components/layout/AppFooter";
/** Renders the direct message conversation page with header, message history, and input field. */
export default async function DirectMessagePage({
params,
}: {
params: Promise<{ conversationId: string }>;
}) {
const { conversationId } = await params;
// 1. Validation
if (!isValidUuid(conversationId)) {
redirect("/");
}
// 2. Auth Guard
const session = await auth();
if (!session?.user?.id) {
redirect("/login");
}
// 3. Database Queries
const [conversation, rawMessages, friendships] = await Promise.all([
db.query.conversations.findFirst({
where: and(
eq(conversations.id, conversationId),
or(
eq(conversations.userOneId, session.user.id),
eq(conversations.userTwoId, session.user.id),
),
),
with: {
userOne: true,
userTwo: true,
},
}),
db.query.directMessages.findMany({
where: eq(directMessages.conversationId, conversationId),
with: {
sender: true,
},
orderBy: (dm, { asc }) => [asc(dm.createdAt)],
}),
getUserFriendships(session.user.id),
]);
if (!conversation) {
redirect("/");
}
// 4. Identify the person to contact
const partner =
conversation.userOne.id === session.user.id
? conversation.userTwo
: conversation.userOne;
// 5. Format Messages for UI
const initialMessages: MessageWithMember[] = rawMessages.map((msg) => ({
...msg,
type: "dm",
memberId: msg.senderId,
member: {
id: msg.sender.id,
role: "MEMBER",
user: msg.sender,
},
}));
return (
<div className="flex p-4 flex-col h-full w-full bg-background min-h-0 overflow-hidden">
<AppHeader title={partner.username} />
<ChatMessages
type="dm"
name={partner.username}
initialMessages={initialMessages}
currentUserId={session.user.id}
userFriendships={friendships}
/>
<ChatInput
type="dm"
conversationId={conversationId}
placeholderName={partner.username}
/>
<AppFooter />
</div>
);
}