From 835b9a23e214bedf5bafaf550751f641a4cede8a Mon Sep 17 00:00:00 2001 From: Bob Burningham Date: Sat, 14 Oct 2023 21:05:11 -0700 Subject: [PATCH] added members modal and route --- app/api/members/[memberId]/route.ts | 128 ++++++++++++++++++ components/modals/members-modal.tsx | 164 ++++++++++++++++++++++++ components/providors/modal-providor.tsx | 2 + 3 files changed, 294 insertions(+) create mode 100644 app/api/members/[memberId]/route.ts create mode 100644 components/modals/members-modal.tsx diff --git a/app/api/members/[memberId]/route.ts b/app/api/members/[memberId]/route.ts new file mode 100644 index 0000000..eb4871e --- /dev/null +++ b/app/api/members/[memberId]/route.ts @@ -0,0 +1,128 @@ +import { currentProfile } from "@/lib/current-profile"; +import { db } from "@/lib/db"; +import { NextResponse } from "next/server"; + +export async function DELETE(req: Request, { params }: { params: { memberId: string }}) +{ + try + { + const profile = await currentProfile(); + const { searchParams } = new URL(req.url); + const serverId = searchParams.get("serverId"); + + if (!profile) + { + return new NextResponse("Unauthorized", { status: 401 }); + } + + if (!serverId) + { + return new NextResponse("Server ID Missing", { status: 400 }); + } + + if (!params.memberId) + { + return new NextResponse("Member ID Missing", { status: 400 }); + } + + const server = await db.server.update({ + where: { + id: serverId, + profileId: profile.id, + }, + data: { + members: { + deleteMany: { + id: params.memberId, + profileId: { + not: profile.id + }, + } + } + }, + include: { + members: { + include: { + profile: true + }, + orderBy: { + role: "asc" + } + } + } + }); + + return NextResponse.json(server); + } + catch (error) + { + console.log("[MEMBER_ID_DELETE]", error); + return new NextResponse("Internal Error", { status: 500}); + } +} + +export async function PATCH(req: Request, { params }: { params: { memberId: string }}) +{ + try + { + const profile = await currentProfile(); + const { searchParams } = new URL(req.url); + const { role } = await req.json(); + + const serverId = searchParams.get("serverId"); + + if (!profile) + { + return new NextResponse("Unauthorized", { status: 401 }); + } + + if (!serverId) + { + return new NextResponse("Server ID Missing", { status: 400 }); + } + + if (!params.memberId) + { + return new NextResponse("Member ID Missing", { status: 400 }); + } + + const server = await db.server.update({ + where: { + id: serverId, + profileId: profile.id, + }, + data: { + members: { + update: { + where: { + id: params.memberId, + profileId: { + not: profile.id + }, + }, + data: { + role + } + } + } + }, + include: { + members: { + include: { + profile: true + }, + orderBy: { + role: "asc" + } + } + } + }); + + return NextResponse.json(server); + } + catch (error) + { + console.log("[MEMBER_ID_PATCH]", error); + return new NextResponse("Internal Error", { status: 500}); + } +} \ No newline at end of file diff --git a/components/modals/members-modal.tsx b/components/modals/members-modal.tsx new file mode 100644 index 0000000..f7f5ce6 --- /dev/null +++ b/components/modals/members-modal.tsx @@ -0,0 +1,164 @@ +"use client"; + +import axios from "axios"; +import qs from "query-string"; +import { Check, Gavel, Loader2, MoreVertical, Shield, ShieldAlert, ShieldCheck, ShieldQuestion } from "lucide-react"; +import { useState } from "react"; +import { MemberRole } from "@prisma/client"; +import { useRouter } from "next/navigation"; + +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { useModal } from "@/hooks/use-modal-store"; +import { ServerWithMembersWithProfiles } from "@/types"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { UserAvatar } from "@/components/user-avatar"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuPortal, + DropdownMenuSeparator, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuTrigger, + DropdownMenuSubTrigger, +} from "@/components/ui/dropdown-menu"; + +const roleIconMap = { + "GUEST": null, + "MODERATOR": , + "ADMIN": +} + +export const MembersModal = () => { + const router = useRouter(); + const { onOpen, isOpen, onClose, type, data } = useModal(); + const [loadingId, setLodaingId] = useState(""); + + const isModalOpen = isOpen && type === "members"; + const { server } = data as { server: ServerWithMembersWithProfiles }; + + const onKick = async (memberId: string) => { + try { + setLodaingId(memberId); + const url = qs.stringifyUrl({ + url: `/api/members/${memberId}`, + query: { + serverId: server?.id, + } + }); + + const repsponse = await axios.delete(url); + + router.refresh(); + onOpen("members", {server: repsponse.data}); + } catch (error) { + console.log(error); + } finally { + setLodaingId(""); + } + } + + const onRoleChange = async (memberId: string, role: MemberRole) => { + try { + setLodaingId(memberId); + const url = qs.stringifyUrl({ + url: `/api/members/${memberId}`, + query: { + serverId: server?.id, + } + }); + + const response = await axios.patch(url, { role }); + + router.refresh(); + onOpen("members", {server: response.data}); + } catch (error) { + console.log(error); + } finally { + setLodaingId(""); + } + } + + return ( + + + + + Manage Members + + + {server?.members?.length} Members + + + + {server?.members?.map((member) => ( +
+ +
+
+ {member.profile.name} + {roleIconMap[member.role]} +
+

+ {member.profile.email} +

+
+ {server.profileId !== member.profileId && loadingId !== member.id && ( +
+ + + + + + + + + + + Role + + + + onRoleChange(member.id, "GUEST")}> + + Guest + {member.role === "GUEST" && ( + + )} + + onRoleChange(member.id, "MODERATOR")}> + + Moderator + {member.role === "MODERATOR" && ( + + )} + + + + + + onKick(member.id)}> + + Kick + + + +
+ )} + {loadingId === member.id && ( + + )} +
+ ))} +
+
+
+ ) +} \ No newline at end of file diff --git a/components/providors/modal-providor.tsx b/components/providors/modal-providor.tsx index 7710ea2..9213262 100644 --- a/components/providors/modal-providor.tsx +++ b/components/providors/modal-providor.tsx @@ -5,6 +5,7 @@ import { useEffect, useState } from "react"; import { EditServerModal } from "@/components/modals/edit-server-modal"; import { CreateServerModal } from "@/components/modals/create-server-modal"; import { InviteModal } from "@/components/modals/invite-modal"; +import { MembersModal } from "@/components/modals/members-modal"; export const ModalProvidor = () => { const [isMounted, setIsMounted] = useState(false); @@ -22,6 +23,7 @@ export const ModalProvidor = () => { + ) } \ No newline at end of file