diff --git a/actions/contributors.tsx b/actions/contributors.tsx new file mode 100644 index 0000000..f45d9cd --- /dev/null +++ b/actions/contributors.tsx @@ -0,0 +1,90 @@ +"use server"; + +import { db } from "@/lib/prisma"; + +export async function deleteContributor(contributorId: string, authorId: string, projectId: string) { + try { + if (!contributorId || !authorId || !projectId) { + throw new Error("Missing required parameters"); + } + + const project = await db.project.findUnique({ + where: { id: projectId }, + include: { contributors: true } + }); + + if (!project) { + throw new Error("Project not found"); + } + + if (project.authorId !== authorId) { + throw new Error("Unauthorized: Only the project author can remove contributors"); + } + + const contributer = project.contributors.find(c => c.id === contributorId); + + if (!contributer) { + throw new Error("Contributor not found in this project"); + } + + await db.contributor.delete({ + where: { id: contributorId } + }); + + await db.application.delete({ + where: { + profileId_projectId: { + profileId: contributer.profileId, + projectId: projectId, + } + } + }); + + return { success: true, message: "Contributor removed successfully" }; + } catch (error) { + console.error('Error removing contributor:', error); + return { + success: false, + message: 'Failed to remove contributor', + }; + } +} + +export async function leaveProject(contributorId: string, userId: string, projectId: string) { + try { + if (!contributorId || !userId || !projectId) { + throw new Error("Missing required parameters"); + } + + const project = await db.project.findUnique({ + where: { id: projectId }, + include: { contributors: true } + }); + + if (!project) throw new Error("Project not found"); + const contributor = project.contributors.find(c => c.id === contributorId); + if (!contributor) throw new Error("Contributor not found in this project"); + if (contributor?.profileId !== userId) throw new Error("Unauthorized: You can only leave projects you are a contributor of"); + + await db.contributor.delete({ + where: { id: contributorId } + }); + + await db.application.delete({ + where: { + profileId_projectId: { + profileId: contributor.profileId, + projectId: projectId, + } + } + }); + + return { success: true, message: "Successfully left the project" }; + } catch (error) { + console.error('Error leaving project:', error); + return { + success: false, + message: 'Failed to leave project', + }; + } +} \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 7cd6faa..def88aa 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -61,7 +61,7 @@ model Profile { image String? section String branch String - college String @default("Not Set") + college String? year String skills String[] bio String? diff --git a/src/app/(user)/projects/[id]/_components/ContributorActions.tsx b/src/app/(user)/projects/[id]/_components/ContributorActions.tsx new file mode 100644 index 0000000..8407fe1 --- /dev/null +++ b/src/app/(user)/projects/[id]/_components/ContributorActions.tsx @@ -0,0 +1,132 @@ +"use client"; + +import { useState } from "react"; +import { useRouter } from "next/navigation"; +import { UserMinus, LogOut, Loader2 } from "lucide-react"; +import { toast } from "sonner"; +import { deleteContributor, leaveProject } from "../../../../../../actions/contributors"; + +interface ContributorActionsProps { + contributorId: string; + contributorProfileId: string; + contributorName: string; + projectId: string; + currentUserProfileId?: string; + authorProfileId: string; +} + +export function ContributorActions({ + contributorId, + contributorProfileId, + contributorName, + projectId, + currentUserProfileId, + authorProfileId, +}: ContributorActionsProps) { + const [loading, setLoading] = useState(false); + const [showConfirm, setShowConfirm] = useState(false); + const router = useRouter(); + + const isAuthor = currentUserProfileId === authorProfileId; + const isCurrentUserContributor = currentUserProfileId === contributorProfileId; + + if (!isAuthor && !isCurrentUserContributor) { + return null; + } + + const handleRemoveContributor = async () => { + if (!currentUserProfileId) return; + + setLoading(true); + try { + const result = await deleteContributor(contributorId, currentUserProfileId, projectId); + + if (result.success) { + toast.success("Contributor removed successfully"); + router.refresh(); + } else { + toast.error(result.message || "Failed to remove contributor"); + } + } catch { + toast.error("An error occurred while removing the contributor"); + } finally { + setLoading(false); + setShowConfirm(false); + } + }; + + const handleLeaveProject = async () => { + if (!currentUserProfileId) return; + + setLoading(true); + try { + const result = await leaveProject(contributorId, currentUserProfileId, projectId); + + if (result.success) { + toast.success("Successfully left the project"); + router.refresh(); + } else { + toast.error(result.message || "Failed to leave project"); + } + } catch { + toast.error("An error occurred while leaving the project"); + } finally { + setLoading(false); + setShowConfirm(false); + } + }; + + if (showConfirm) { + return ( +
+ {contributor.name} +
+Contributor
+- {contributor.name} -
-- Contributor -
-