/**
* @file components/layout/MemberSidebar.tsx
* @description Member sidebar component displaying server members with desktop sliding panel and mobile drawer functionality.
*/
"use client";
import { useEffect, useRef, useState } from "react";
import { useSidebarStore } from "@/lib/stores/useSidebarStore";
import { useActiveServer } from "@/lib/context/ServerContext";
import { MemberList } from "@/components/members/MemberList";
import { X, Loader2 } from "lucide-react";
import { clsx } from "clsx";
import { User } from "@/db/schema";
/** Properties for the MemberHeader component. */
interface MemberHeaderProps {
title: string;
onClose: () => void;
}
/** Renders the header section of the member sidebar with a title and close button. */
function MemberHeader({ title, onClose }: MemberHeaderProps) {
return (
Members
);
}
/** Displays the list of members for the active server in a responsive sidebar or drawer layout. */
export function MemberSidebar() {
const { isMembersOpen, closeMembers } = useSidebarStore();
const { activeServer } = useActiveServer();
const desktopSidebarRef = useRef(null);
const [members, setMembers] = useState([]);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
if (!activeServer?.id) {
setMembers([]);
return;
}
const controller = new AbortController();
async function fetchMembers() {
try {
setIsLoading(true);
const res = await fetch(`/api/servers/${activeServer?.id}/members`, {
signal: controller.signal,
});
if (res.ok) {
const data: User[] = await res.json();
setMembers(data);
}
} catch (err: unknown) {
if (err instanceof Error && err.name !== "AbortError") {
console.error("Error loading members:", err);
}
} finally {
setIsLoading(false);
}
}
fetchMembers();
return () => {
controller.abort();
};
}, [activeServer?.id]);
useEffect(() => {
function handleClickOutside(event: MouseEvent) {
const target = event.target as HTMLElement;
if (target.closest('button[title*="Mitgliederliste"]')) return;
if (
isMembersOpen &&
desktopSidebarRef.current &&
!desktopSidebarRef.current.contains(target)
) {
closeMembers();
}
}
if (isMembersOpen) {
document.addEventListener("mousedown", handleClickOutside);
}
return () => document.removeEventListener("mousedown", handleClickOutside);
}, [isMembersOpen, closeMembers]);
/** Renders either a loading spinner or the populated member list depending on state. */
const renderContent = () => {
if (isLoading && members.length === 0) {
return (