import { zodResolver } from "@hookform/resolvers/zod"; import { MembershipSchemas, type UtilitySchemas } from "@plunk/shared"; import type { Project, Role } from "@prisma/client"; import { motion } from "framer-motion"; import { useRouter } from "next/router"; import React, { useState } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { Card, FullscreenLoader, Input, Modal, SettingTabs, Table, } from "../../components"; import { Dashboard } from "../../layouts"; import { useActiveProject, useActiveProjectMemberships, useProjects, } from "../../lib/hooks/projects"; import { useUser } from "../../lib/hooks/users"; import { network } from "../../lib/network"; interface EmailValues { email: string; } /** * */ export default function Index() { const [showInviteModal, setShowInviteModal] = useState(false); const [showLeaveModal, setShowLeaveModal] = useState(false); const [project, setProject] = useState(); const router = useRouter(); const activeProject = useActiveProject(); const { data: user } = useUser(); const { data: projects, mutate: projectMutate } = useProjects(); const { data: memberships, mutate: membershipMutate } = useActiveProjectMemberships(); const { register, handleSubmit, formState: { errors }, } = useForm({ resolver: zodResolver( MembershipSchemas.invite.omit({ id: true, role: true }), ), }); if (activeProject && !project) { setProject(activeProject); } if (!project || !projects || !memberships || !user) { return ; } if (!activeProject) { return ; } const inviteAccount = (data: EmailValues) => { toast.promise( network.mock< { success: true; members: { userId: string; email: string; role: Role; }[]; }, typeof MembershipSchemas.invite >(project.secret, "POST", "/memberships/invite", { id: project.id, email: data.email, role: "ADMIN", }), { loading: "Adding new member", success: async (result) => { await membershipMutate(result.members); setShowInviteModal(false); return "Added new member"; }, error: "Could not add new member!", }, ); }; const kickAccount = (email: string) => { void network .fetch< { success: true; members: { userId: string; email: string; role: Role; }[]; }, typeof MembershipSchemas.kick >("POST", "/memberships/kick", { id: project.id, email, }) .then(async (res) => { await membershipMutate(res.members); }); }; const leaveProject = () => { void network .fetch< { success: true; memberships: Project[]; }, typeof UtilitySchemas.id >("POST", "/memberships/leave", { id: project.id, }) .then(async (res) => { await projectMutate(res.memberships); localStorage.removeItem("project"); await router.push("/"); window.location.reload(); }); }; return ( <> setShowLeaveModal(!showLeaveModal)} onAction={leaveProject} type={"danger"} title={"Are you sure?"} description={ memberships.length === 1 ? "You are the last person in this project, if you leave it we will automatically delete it!" : "Leaving a project is permanent, you will lose access to the data and will need to be reinvited again." } /> setShowInviteModal(!showInviteModal)} onAction={handleSubmit(inviteAccount)} type={"info"} title={"Invite a new member"} description={ "Enter the email of the account you want to invite to this project. The person you want to invite needs to have an account on Plunk." } > { return { Account: membership.email, Role: membership.role.charAt(0).toUpperCase() + membership.role.slice(1).toLowerCase(), Manage: membership.userId === user.id ? ( ) : memberships.find( (membership) => membership.userId === user.id, )?.role === "OWNER" ? ( ) : ( "" ), }; })} />

Invite team

By adding someone to your project you give them access to all data present in your project including emails and your API key.

setShowInviteModal(true)} whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.9 }} className={ "ml-auto mt-4 self-end rounded bg-neutral-800 px-8 py-2.5 text-sm font-medium text-white" } > Invite user
); }