diff --git a/app/(invite)/(routes)/invite/[inviteCode]/page.tsx b/app/(invite)/(routes)/invite/[inviteCode]/page.tsx
new file mode 100644
index 0000000..0a8c1c7
--- /dev/null
+++ b/app/(invite)/(routes)/invite/[inviteCode]/page.tsx
@@ -0,0 +1,62 @@
+import { currentProfile } from "@/lib/current-profile";
+import { redirectToSignIn } from "@clerk/nextjs";
+import { redirect } from "next/navigation";
+import { db } from "@/lib/db";
+
+interface InviteCodePageProps {
+ params: {
+ inviteCode: string;
+ };
+};
+
+const InviteCodePage = async ({
+ params
+}: InviteCodePageProps) => {
+ const profile = await currentProfile();
+
+ if (!profile) {
+ return redirectToSignIn();
+ }
+
+ if (!params?.inviteCode) {
+ return redirect("/");
+ }
+
+ const existingServer = await db.server.findFirst({
+ where: {
+ inviteCode: params.inviteCode,
+ members: {
+ some: {
+ profileId: profile.id,
+ },
+ },
+ },
+ });
+
+ if (existingServer) {
+ return redirect(`/servers/${existingServer.id}`);
+ }
+
+ const server= await db.server.update({
+ where: {
+ inviteCode: params.inviteCode,
+ },
+ data: {
+ members: {
+ create: [
+ {
+ profileId: profile.id,
+ },
+ ],
+ },
+ },
+ });
+
+ if(server) {
+ return redirect(`/servers/${server.id}`);
+ }
+
+ return null
+}
+
+export default InviteCodePage;
\ No newline at end of file
diff --git a/app/api/servers/[serverId]/invite-code/route.ts b/app/api/servers/[serverId]/invite-code/route.ts
new file mode 100644
index 0000000..beba2a4
--- /dev/null
+++ b/app/api/servers/[serverId]/invite-code/route.ts
@@ -0,0 +1,38 @@
+import { v4 as uuidv4 } from "uuid";
+import { NextResponse } from "next/server";
+
+import { currentProfile } from "@/lib/current-profile";
+import { db } from "@/lib/db";
+
+
+export async function PATCH(
+ req: Request,
+ { params }: { params: { serverId: string } }
+) {
+ try {
+ const profile = await currentProfile();
+
+ if (!profile) {
+ return new NextResponse("Unauthorized", { status: 401 });
+ }
+
+ if (!params.serverId) {
+ return new NextResponse("Server ID Missing", { status: 400 });
+ }
+
+ const server = await db.server.update({
+ where: {
+ id: params.serverId,
+ profileId: profile.id,
+ },
+ data: {
+ inviteCode: uuidv4(),
+ }
+ });
+
+ return NextResponse.json(server)
+ } catch (error) {
+ console.log("[SERVER_ID]", error);
+ return new NextResponse("Internal Error", { status: 500});
+ }
+}
\ No newline at end of file
diff --git a/components/modals/invite-modal.tsx b/components/modals/invite-modal.tsx
new file mode 100644
index 0000000..840c5f9
--- /dev/null
+++ b/components/modals/invite-modal.tsx
@@ -0,0 +1,90 @@
+"use client";
+
+import axios from "axios";
+import { useState } from "react";
+import { Check, Copy, RefreshCw } from "lucide-react";
+
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog";
+import { useModal } from "@/hooks/use-modal-store";
+import { Label } from "@/components/ui/label";
+import { Input } from "@/components/ui/input";
+import { Button } from "@/components/ui/button";
+import { useOrigin } from "@/hooks/user-origin";
+
+
+export const InviteModal = () => {
+ const { onOpen, isOpen, onClose, type, data } = useModal();
+ const origin = useOrigin();
+
+ const isModalOpen = isOpen && type === "invite";
+ const { server } = data;
+
+ const [copied, setCopied] = useState(false);
+ const [isLoading, setIsLoading] = useState(false);
+
+ const inviteUrl = `${origin}/invite/${server?.inviteCode}`;
+
+ const onCopy = () => {
+ navigator.clipboard.writeText(inviteUrl);
+ setCopied(true);
+
+ setTimeout(() => {
+ setCopied(false);
+ }, 1000);
+ }
+
+ const onNew = async () => {
+ try {
+ setIsLoading(true);
+ const response = await axios.patch(`/api/servers/${server?.id}/invite-code`);
+
+ onOpen("invite", {server: response.data});
+ } catch (error) {
+ console.log(error);
+ } finally{
+ setIsLoading(false);
+ }
+ }
+
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/components/providors/modal-providor.tsx b/components/providors/modal-providor.tsx
index c73bdb7..76ad0ca 100644
--- a/components/providors/modal-providor.tsx
+++ b/components/providors/modal-providor.tsx
@@ -3,6 +3,7 @@
import { useEffect, useState } from "react";
import { CreateServerModal } from "@/components/modals/create-server-modal";
+import { InviteModal } from "@/components/modals/invite-modal";
export const ModalProvidor = () => {
const [isMounted, setIsMounted] = useState(false);
@@ -18,6 +19,7 @@ export const ModalProvidor = () => {
return (
<>
+
>
)
}
\ No newline at end of file
diff --git a/components/server/server-header.tsx b/components/server/server-header.tsx
index 1e920c5..0a1dda4 100644
--- a/components/server/server-header.tsx
+++ b/components/server/server-header.tsx
@@ -3,7 +3,8 @@
import { ServerWithMembersWithProfiles } from "@/types";
import { MemberRole } from "@prisma/client";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
-import { ChevronDown, LogOut, LogOutIcon, Plus, PlusCircle, Settings, Trash, Users } from "lucide-react";
+import { ChevronDown, LogOut, Plus, PlusCircle, Settings, Trash, Users } from "lucide-react";
+import { useModal } from "@/hooks/use-modal-store";
interface ServerHeaderProps {
server: ServerWithMembersWithProfiles;
@@ -11,6 +12,7 @@ interface ServerHeaderProps {
}
export const SeverHeader = ({server, role}: ServerHeaderProps) => {
+ const { onOpen } = useModal();
const isAdmin = role === MemberRole.ADMIN;
const isModerator = isAdmin || role === MemberRole.MODERATOR;
@@ -30,6 +32,7 @@ export const SeverHeader = ({server, role}: ServerHeaderProps) => {
>
{isModerator && (
onOpen("invite", {server})}
className="text-indigo-600 dark:text-indigo-400 px-3 py-2 text-sm cursor-pointer"
>
Invite People
diff --git a/hooks/use-modal-store.ts b/hooks/use-modal-store.ts
index 77ff451..9eb292f 100644
--- a/hooks/use-modal-store.ts
+++ b/hooks/use-modal-store.ts
@@ -1,17 +1,25 @@
+
+import { Server } from "@prisma/client";
import { create } from "zustand";
-export type ModalType = "createServer";
+export type ModalType = "createServer" | "invite";
+
+interface ModalData {
+ server?: Server
+}
interface ModalStore {
type: ModalType | null;
+ data: ModalData;
isOpen: boolean;
- onOpen: (type: ModalType) => void;
+ onOpen: (type: ModalType, data?:ModalData) => void;
onClose: () => void;
}
export const useModal = create((set) => ({
type: null,
+ data: {},
isOpen: false,
- onOpen: (type) => set({ isOpen: true, type }),
+ onOpen: (type, data= {}) => set({ isOpen: true, type, data }),
onClose: () => set({ type: null, isOpen: false }),
}));
\ No newline at end of file
diff --git a/hooks/user-origin.ts b/hooks/user-origin.ts
new file mode 100644
index 0000000..f4d1a63
--- /dev/null
+++ b/hooks/user-origin.ts
@@ -0,0 +1,18 @@
+import { useEffect, useState } from "react";
+
+export const useOrigin = () => {
+ const [mounted, setMounted] = useState(false);
+
+ useEffect(() => {
+ setMounted(true);
+
+ }, []);
+
+ const origin = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
+
+ if (!mounted) {
+ return "";
+ }
+
+ return origin;
+}
\ No newline at end of file