diff --git a/app/(app)/dm/[conversationId]/page.tsx b/app/(app)/dm/[conversationId]/page.tsx index 283f1d3..471ee16 100644 --- a/app/(app)/dm/[conversationId]/page.tsx +++ b/app/(app)/dm/[conversationId]/page.tsx @@ -13,7 +13,6 @@ 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. */ @@ -35,8 +34,8 @@ export default async function DirectMessagePage({ redirect("/login"); } - // 3. Database Queries - const [conversation, rawMessages, friendships] = await Promise.all([ + // 3. Database Queries (Freundschaften werden nun global im Layout geladen) + const [conversation, rawMessages] = await Promise.all([ db.query.conversations.findFirst({ where: and( eq(conversations.id, conversationId), @@ -57,7 +56,6 @@ export default async function DirectMessagePage({ }, orderBy: (dm, { asc }) => [asc(dm.createdAt)], }), - getUserFriendships(session.user.id), ]); if (!conversation) { @@ -90,8 +88,6 @@ export default async function DirectMessagePage({ type="dm" name={partner.username} initialMessages={initialMessages} - currentUserId={session.user.id} - userFriendships={friendships} /> -
- -
{children}
- -
- + + +
+ +
{children}
+ +
+
+
); } diff --git a/app/(app)/servers/[serverId]/channels/[channelId]/page.tsx b/app/(app)/servers/[serverId]/channels/[channelId]/page.tsx index 1979a23..fb4a543 100644 --- a/app/(app)/servers/[serverId]/channels/[channelId]/page.tsx +++ b/app/(app)/servers/[serverId]/channels/[channelId]/page.tsx @@ -12,7 +12,6 @@ import { getChannelById } from "@/lib/services/channel.service"; import { getChannelMessages } from "@/lib/services/message.service"; import { getServerById } from "@/lib/services/server.service"; import { isValidUuid } from "@/lib/utils"; -import { getUserFriendships } from "@/lib/services/friends.service"; import AppFooter from "@/components/layout/AppFooter"; /** Renders the channel chat view by validating parameters, checking user session, fetching channel data, friendships, and displaying headers, messages, and input controls. */ @@ -34,11 +33,10 @@ export default async function ChannelPage({ } // 3. Parallel Loading of Data - const [server, channel, channelMessages, friendships] = await Promise.all([ + const [server, channel, channelMessages] = await Promise.all([ getServerById(serverId), getChannelById(channelId), getChannelMessages(channelId), - getUserFriendships(session.user.id), ]); if (!channel || !server) { @@ -57,8 +55,6 @@ export default async function ChannelPage({ type="chat" name={channel.name} initialMessages={channelMessages} - currentUserId={session.user.id} - userFriendships={friendships} /> & { @@ -30,12 +31,6 @@ export type MessageWithMember = Omit & { interface ChatItemProps { type: "chat" | "dm"; message: MessageWithMember; - userFriendships: Array<{ - senderId: string; - receiverId: string; - status: string; - }>; - currentUserId: string; onDeleteSuccess?: (id: string) => void; onEditSuccess?: (id: string, newContent: string) => void; } @@ -44,13 +39,14 @@ interface ChatItemProps { export function ChatItem({ type, message, - currentUserId, - userFriendships, onDeleteSuccess, onEditSuccess, }: ChatItemProps) { const router = useRouter(); const { setActiveServer } = useActiveServer(); + const { currentUser, friendships } = useUser(); + + const currentUserId = currentUser.id; const [isDeleting, setIsDeleting] = useState(false); const [isEditing, setIsEditing] = useState(false); @@ -113,15 +109,11 @@ export function ChatItem({ /** Determines the friendship status between the current user and the message author. */ const getFriendshipStatus = () => { - if ( - !user?.id || - user.id === currentUserId || - !Array.isArray(userFriendships) - ) { + if (!user?.id || user.id === currentUserId || !Array.isArray(friendships)) { return null; } - const friendship = userFriendships.find( + const friendship = friendships.find( (f) => (f.senderId === user.id && f.receiverId === currentUserId) || (f.receiverId === user.id && f.senderId === currentUserId), diff --git a/components/chat/ChatMessages.tsx b/components/chat/ChatMessages.tsx index 490e5f6..cb93046 100644 --- a/components/chat/ChatMessages.tsx +++ b/components/chat/ChatMessages.tsx @@ -13,12 +13,6 @@ export interface ChatMessagesProps { type: "chat" | "dm"; name: string; initialMessages: MessageWithMember[]; - userFriendships: Array<{ - senderId: string; - receiverId: string; - status: string; - }>; - currentUserId: string; onDeleteMessage?: (id: string) => void; onEditMessage?: (id: string, newContent: string) => void; } @@ -55,8 +49,6 @@ export function ChatMessages({ type, name, initialMessages, - currentUserId, - userFriendships, onDeleteMessage, onEditMessage, }: ChatMessagesProps) { @@ -156,8 +148,6 @@ export function ChatMessages({ diff --git a/components/layout/MemberSidebar.tsx b/components/layout/MemberSidebar.tsx index 990a932..6e43ef1 100644 --- a/components/layout/MemberSidebar.tsx +++ b/components/layout/MemberSidebar.tsx @@ -19,16 +19,6 @@ interface MemberHeaderProps { onClose: () => void; } -/** Properties for the MemberSidebar component. */ -interface MemberSidebarProps { - currentUserId: string; - userFriendships: Array<{ - senderId: string; - receiverId: string; - status: string; - }>; -} - /** Renders the header section of the member sidebar with a title and close button. */ function MemberHeader({ title, onClose }: MemberHeaderProps) { return ( @@ -49,10 +39,7 @@ function MemberHeader({ title, onClose }: MemberHeaderProps) { } /** Displays the list of members for the active server in a responsive sidebar or drawer layout. */ -export function MemberSidebar({ - currentUserId, - userFriendships = [], -}: MemberSidebarProps) { +export function MemberSidebar() { const { isMembersOpen, closeMembers } = useSidebarStore(); const { activeServer } = useActiveServer(); const desktopSidebarRef = useRef(null); @@ -124,13 +111,7 @@ export function MemberSidebar({ ); } - return ( - - ); + return ; }; return ( diff --git a/components/members/MemberItem.tsx b/components/members/MemberItem.tsx index 06d9968..3b826b2 100644 --- a/components/members/MemberItem.tsx +++ b/components/members/MemberItem.tsx @@ -13,29 +13,22 @@ import { UserAvatar } from "../ui/UserAvatar"; import { UserProfilePopover } from "../ui/UserProfilePopover"; import { useActiveServer } from "@/lib/context/ServerContext"; import { useSidebarStore } from "@/lib/stores/useSidebarStore"; +import { useUser } from "@/lib/context/UserContext"; /** Props for the MemberItem component. */ interface MemberItemProps { member: User; - currentUserId: string; - userFriendships: Array<{ - senderId: string; - receiverId: string; - status: string; - }>; isOffline?: boolean; } /** Renders an individual member item with an interactive user profile popover. */ -export function MemberItem({ - member, - currentUserId, - userFriendships = [], - isOffline = false, -}: MemberItemProps) { +export function MemberItem({ member, isOffline = false }: MemberItemProps) { const router = useRouter(); const { setActiveServer } = useActiveServer(); const { closeMembers } = useSidebarStore(); + const { currentUser, friendships } = useUser(); + + const currentUserId = currentUser.id; const [isProfileOpen, setIsProfileOpen] = useState(false); const containerRef = useRef(null); @@ -71,11 +64,11 @@ export function MemberItem({ /** Determines the friendship status between the logged-in user and this member. */ const getFriendshipStatus = () => { - if (!member.id || member.id === currentUserId || !userFriendships) { + if (!member.id || member.id === currentUserId || !friendships) { return null; } - const friendship = userFriendships.find( + const friendship = friendships.find( (f) => (f.senderId === member.id && f.receiverId === currentUserId) || (f.receiverId === member.id && f.senderId === currentUserId), diff --git a/components/members/MemberList.tsx b/components/members/MemberList.tsx index 345de73..dbc42ca 100644 --- a/components/members/MemberList.tsx +++ b/components/members/MemberList.tsx @@ -1,29 +1,18 @@ /** * @file components/members/MemberList.tsx - * @description Renders categorized lists of online and offline members with their friendship statuses. + * @description Renders categorized lists of online and offline members using the UserContext. */ import { useMemo } from "react"; import { MemberItem } from "@/components/members/MemberItem"; import { User } from "@/db/schema"; -/** Props for the MemberList component. */ interface MemberListProps { members: User[]; - currentUserId: string; - userFriendships: Array<{ - senderId: string; - receiverId: string; - status: string; - }>; } /** Renders online and offline community members in distinct sections. */ -export function MemberList({ - members = [], - currentUserId, - userFriendships = [], -}: MemberListProps) { +export function MemberList({ members = [] }: MemberListProps) { const { onlineMembers, offlineMembers } = useMemo(() => { return { onlineMembers: members.filter((m) => m.status !== "OFFLINE"), @@ -40,12 +29,7 @@ export function MemberList({
{onlineMembers.map((member) => ( - + ))} {onlineMembers.length === 0 && (

@@ -62,13 +46,7 @@ export function MemberList({

{offlineMembers.map((member) => ( - + ))}
diff --git a/lib/context/UserContext.tsx b/lib/context/UserContext.tsx new file mode 100644 index 0000000..28e0178 --- /dev/null +++ b/lib/context/UserContext.tsx @@ -0,0 +1,50 @@ +/** + * @file lib/context/UserContext.tsx + * @description Context provider and hook for managing current user data and friendship states. + */ + +"use client"; + +import { createContext, useContext } from "react"; +import type { User } from "@/db/schema"; + +/** Represents a friendship record between two users. */ +interface Friendship { + senderId: string; + receiverId: string; + status: string; +} + +/** Shape of the user context value. */ +interface UserContextType { + currentUser: User; + friendships: Friendship[]; +} + +const UserContext = createContext(null); + +/** Provides user data and friendship states to child components. */ +export function UserProvider({ + children, + currentUser, + friendships, +}: { + children: React.ReactNode; + currentUser: User; + friendships: Friendship[]; +}) { + return ( + + {children} + + ); +} + +/** Custom hook to consume user context data. */ +export function useUser() { + const context = useContext(UserContext); + if (!context) { + throw new Error("useUser must be used within a UserProvider"); + } + return context; +}