From ab5eab2d4c9b2e5d4276591d7f24434dc8cf08f2 Mon Sep 17 00:00:00 2001 From: anmolsinghbhatia Date: Fri, 14 Jul 2023 18:35:37 +0530 Subject: [PATCH 1/2] feat: workspace member bulk invite --- .../project/send-project-invitation-modal.tsx | 3 +- .../send-workspace-invitation-modal.tsx | 247 +++++++++++------- .../[workspaceSlug]/settings/members.tsx | 1 - 3 files changed, 156 insertions(+), 95 deletions(-) diff --git a/apps/app/components/project/send-project-invitation-modal.tsx b/apps/app/components/project/send-project-invitation-modal.tsx index 13d1c7bc5af..ffdecc321b2 100644 --- a/apps/app/components/project/send-project-invitation-modal.tsx +++ b/apps/app/components/project/send-project-invitation-modal.tsx @@ -71,7 +71,6 @@ const SendProjectInvitationModal: React.FC = ({ isOpen, setIsOpen, member const { formState: { errors, isSubmitting }, - reset, handleSubmit, control, @@ -172,7 +171,7 @@ const SendProjectInvitationModal: React.FC = ({ isOpen, setIsOpen, member leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > - +
>; workspace_slug: string; - members: any[]; user: ICurrentUserResponse | undefined; }; -const defaultValues: Partial = { - email: "", - role: 5, +type EmailRole = { + email: string; + role: 5 | 10 | 15 | 20; +}; + +type FormValues = { + emails: EmailRole[]; +}; + +const defaultValues: FormValues = { + emails: [ + { + email: "", + role: 15, + }, + ], }; const SendWorkspaceInvitationModal: React.FC = ({ isOpen, setIsOpen, workspace_slug, - members, user, }) => { - const { setToastAlert } = useToast(); - const { memberDetails } = useWorkspaceMyMembership(); - const { control, - register, - formState: { errors, isSubmitting }, - handleSubmit, reset, - } = useForm({ - defaultValues, - reValidateMode: "onChange", + handleSubmit, + formState: { isSubmitting, errors }, + } = useForm(); + + const { fields, append, remove } = useFieldArray({ + control, + name: "emails", }); + const { setToastAlert } = useToast(); + const handleClose = () => { setIsOpen(false); - reset(defaultValues); + const timeout = setTimeout(() => { + reset(defaultValues); + clearTimeout(timeout); + }, 500); }; - const onSubmit = async (formData: IWorkspaceMemberInvitation) => { + const onSubmit = async (formData: FormValues) => { + if (!workspace_slug) return; + + const payload = { ...formData }; + await workspaceService - .inviteWorkspace(workspace_slug, { emails: [formData] }, user) - .then((res) => { + .inviteWorkspace(workspace_slug, payload, user) + .then(async (res) => { setIsOpen(false); handleClose(); - mutate(WORKSPACE_INVITATIONS, (prevData: any) => [ - { ...res, ...formData }, - ...(prevData ?? []), - ]); setToastAlert({ type: "success", title: "Success!", - message: "Member invited successfully.", + message: "Invitations sent successfully.", + }); + }) + .catch((err) => { + setToastAlert({ + type: "error", + title: "Error!", + message: `${err.error}`, }); + console.log(err); }) - .catch((err) => console.log(err)); + .finally(() => reset(defaultValues)); }; + const appendField = () => { + append({ email: "", role: 15 }); + }; + + useEffect(() => { + if (fields.length === 0) { + append([{ email: "", role: 15 }]); + } + }, [fields, append]); + return ( @@ -91,11 +119,11 @@ const SendWorkspaceInvitationModal: React.FC = ({ leaveFrom="opacity-100" leaveTo="opacity-0" > -
+
-
+
= ({ leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > - - + + { + if (e.code === "Enter") e.preventDefault(); + }} + >
-
- - Members - + + Invite people to collaborate + +

Invite members to work on your workspace.

-
-
- { - if (members.find((member) => member.email === value)) - return "Email already exist"; - }, - }} - /> -
-
- ( - + {fields.map((field, index) => ( +
+
+ ( + <> + + {errors.emails?.[index]?.email && ( + + {errors.emails?.[index]?.email?.message} + + )} + + )} + /> +
+
+ ( + {ROLE[value]}} + onChange={onChange} + width="w-full" + input + > + {Object.entries(ROLE).map(([key, value]) => ( + + {value} + + ))} + + )} + /> +
+ {fields.length > 1 && ( + )} - /> -
+
+ ))}
-
- Cancel - - {isSubmitting ? "Sending Invitation..." : "Send Invitation"} - + +
+ +
+ Cancel + + {isSubmitting ? "Sending Invitation..." : "Send Invitation"} + +
diff --git a/apps/app/pages/[workspaceSlug]/settings/members.tsx b/apps/app/pages/[workspaceSlug]/settings/members.tsx index 0955f6c0740..f4630baafd9 100644 --- a/apps/app/pages/[workspaceSlug]/settings/members.tsx +++ b/apps/app/pages/[workspaceSlug]/settings/members.tsx @@ -144,7 +144,6 @@ const MembersSettings: NextPage = () => { isOpen={inviteModal} setIsOpen={setInviteModal} workspace_slug={workspaceSlug as string} - members={members} user={user} />
From 0409aff0c2154d9bf47f90e2ed06718182504e46 Mon Sep 17 00:00:00 2001 From: anmolsinghbhatia Date: Fri, 14 Jul 2023 18:59:57 +0530 Subject: [PATCH 2/2] style: invite dropdown styling --- .../components/workspace/send-workspace-invitation-modal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/app/components/workspace/send-workspace-invitation-modal.tsx b/apps/app/components/workspace/send-workspace-invitation-modal.tsx index 5327606a4e1..a5ff08652bd 100644 --- a/apps/app/components/workspace/send-workspace-invitation-modal.tsx +++ b/apps/app/components/workspace/send-workspace-invitation-modal.tsx @@ -208,7 +208,7 @@ const SendWorkspaceInvitationModal: React.FC = ({ {fields.length > 1 && (