created server sidebar header and dropdown menu

This commit is contained in:
Bob Burningham 2023-10-11 00:12:02 -07:00
parent 65d90df42a
commit 868021049c
4 changed files with 203 additions and 0 deletions

View File

@ -0,0 +1,51 @@
import { redirectToSignIn } from "@clerk/nextjs";
import { redirect } from "next/navigation";
import { currentProfile } from "@/lib/current-profile";
import { db } from "@/lib/db";
import { ServerSidebar } from "@/components/server/server-sidebar";
const ServerIdLayout = async ({
children,
params,
}: {
children: React.ReactNode;
params: { serverId: string};
}) => {
const profile = await currentProfile();
if (!profile) {
return redirectToSignIn();
}
const server = await db.server.findUnique({
where: {
id: params.serverId,
members: {
some: {
profileId: profile.id,
}
}
},
})
if (!server) {
return redirect("/");
}
return (
<div className="h-full">
<div
className="hidden md:flex h-full w-60 z-20 flex-col fixed inset-y-0">
<ServerSidebar serverId={params.serverId} />
</div>
<main className="h-full md:pl-60">
{children}
</main>
</div>
);
}
export default ServerIdLayout;

View File

@ -0,0 +1,85 @@
"use client";
import { ServerWithMembersWithProfiles } from "@/types";
import { MemberRole } from "@prisma/client";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { ChevronDown, LogOutIcon, Plus, PlusCircle, Settings, Trash, Users } from "lucide-react";
interface ServerHeaderProps {
server: ServerWithMembersWithProfiles;
role?: MemberRole;
}
export const SeverHeader = ({server, role}: ServerHeaderProps) => {
const isAdmin = role === MemberRole.ADMIN;
const isModerator = isAdmin || role === MemberRole.MODERATOR;
return (
<DropdownMenu>
<DropdownMenuTrigger
className="focus:outline-none"
asChild
>
<button className="w-full text-md font-semibold px-3 flex items-center h-12 border-neutral-2 dark:border-neutral-800 border-b-2 hover:bg-zinc-700/10 dark:hover:bg-zinc-700/50 transition"
>
{server.name}
<ChevronDown className="w-5 h-5 ml-auto"/>
</button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56 text-xs font-medium text-black dark:text-neutral-400 space-y-[2px]"
>
{isModerator && (
<DropdownMenuItem
className="text-indigo-600 dark:text-indigo-400 px-3 py-2 text-sm cursor-pointer"
>
Invite People
<Plus className="w-4 h-4 ml-auto"/>
</DropdownMenuItem>
)}
{isAdmin && (
<DropdownMenuItem
className=" px-3 py-2 text-sm cursor-pointer"
>
Server Settings
<Settings className="w-4 h-4 ml-auto"/>
</DropdownMenuItem>
)}
{isModerator && (
<DropdownMenuItem
className=" px-3 py-2 text-sm cursor-pointer"
>
Manager Members
<Users className="w-4 h-4 ml-auto"/>
</DropdownMenuItem>
)}
{isModerator && (
<DropdownMenuItem
className=" px-3 py-2 text-sm cursor-pointer"
>
Create Channel
<PlusCircle className="w-4 h-4 ml-auto"/>
</DropdownMenuItem>
)}
{isModerator && (
<DropdownMenuSeparator/>
)}
{isAdmin && (
<DropdownMenuItem
className="text-rose-500 px-3 py-2 text-sm cursor-pointer"
>
Delete Server
<Trash className="w-4 h-4 ml-auto"/>
</DropdownMenuItem>
)}
{!isAdmin && (
<DropdownMenuItem
className="text-rose-500 px-3 py-2 text-sm cursor-pointer"
>
Delete Server
<LogOutIcon className="w-4 h-4 ml-auto"/>
</DropdownMenuItem>
)}
</DropdownMenuContent>
</DropdownMenu>
)
}

View File

@ -0,0 +1,62 @@
import { ChannelType } from "@prisma/client";
import { redirect } from "next/navigation";
import { currentProfile } from "@/lib/current-profile";
import { db } from "@/lib/db";
import { SeverHeader } from "./server-header";
interface ServerSidebarProps {
serverId: string;
}
export const ServerSidebar = async ({
serverId
}: ServerSidebarProps) => {
const profile = await currentProfile();
if (!profile) {
return redirect("/");
}
const server = await db.server.findUnique({
where: {
id: serverId,
},
include: {
channels: {
orderBy: {
createdAt: "asc",
},
},
members: {
include: {
profile: true,
},
orderBy: {
role: "asc",
}
},
}
});
const textChannels = server?.channels.filter((channel) => channel.type === ChannelType.TEXT)
const audioChannels = server?.channels.filter((channel) => channel.type === ChannelType.AUDIO)
const videoChannels = server?.channels.filter((channel) => channel.type === ChannelType.VIDEO)
const members = server?.members.filter((member) => member.profileId !== profile.id)
if (!server) {
return redirect("/");
}
const role = server.members.find((member) => member.profileId === profile.id)?.role;
return (
<div className="flex flex-col h-full text-primary w-full dark:bg-[#2B2D31] bg-[#F2F3F5]">
<SeverHeader
server={server}
role={role}
/>
</div>
)
}

5
types.ts Normal file
View File

@ -0,0 +1,5 @@
import { Server, Member, Profile } from '@prisma/client';
export type ServerWithMembersWithProfiles = Server & {
members: (Member & { profile: Profile })[];
}