'use client'; import { useState, useTransition } from 'react'; import { zodResolver } from '@hookform/resolvers/zod'; import { Plus, X } from 'lucide-react'; import { useFieldArray, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { Button } from '@kit/ui/button'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, } from '@kit/ui/dialog'; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from '@kit/ui/form'; import { If } from '@kit/ui/if'; import { Input } from '@kit/ui/input'; import { toast } from '@kit/ui/sonner'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from '@kit/ui/tooltip'; import { Trans } from '@kit/ui/trans'; import { InviteMembersSchema } from '../../schema/invite-members.schema'; import { createInvitationsAction } from '../../server/actions/team-invitations-server-actions'; import { MembershipRoleSelector } from './membership-role-selector'; import { RolesDataProvider } from './roles-data-provider'; type InviteModel = ReturnType; type Role = string; /** * The maximum number of invites that can be sent at once. * Useful to avoid spamming the server with too large payloads */ const MAX_INVITES = 5; export function InviteMembersDialogContainer({ accountSlug, userRoleHierarchy, children, }: React.PropsWithChildren<{ accountSlug: string; userRoleHierarchy: number; }>) { const [pending, startTransition] = useTransition(); const [isOpen, setIsOpen] = useState(false); const { t } = useTranslation('teams'); return ( {children} e.preventDefault()}> {(roles) => ( { startTransition(() => { const promise = createInvitationsAction({ accountSlug, invitations: data.invitations, }); toast.promise(() => promise, { loading: t('invitingMembers'), success: t('inviteMembersSuccessMessage'), error: t('inviteMembersErrorMessage'), }); setIsOpen(false); }); }} /> )} ); } function InviteMembersForm({ onSubmit, roles, pending, }: { onSubmit: (data: { invitations: InviteModel[] }) => void; pending: boolean; roles: string[]; }) { const { t } = useTranslation('teams'); const form = useForm({ resolver: zodResolver(InviteMembersSchema), shouldUseNativeValidation: true, reValidateMode: 'onSubmit', defaultValues: { invitations: [createEmptyInviteModel()], }, }); const fieldArray = useFieldArray({ control: form.control, name: 'invitations', }); return (
{fieldArray.fields.map((field, index) => { const isFirst = index === 0; const emailInputName = `invitations.${index}.email` as const; const roleInputName = `invitations.${index}.role` as const; return (
{ return ( {t('emailLabel')} ); }} />
{ return ( { form.setValue(field.name, role); }} /> ); }} />
{t('removeInviteButtonLabel')}
); })}
); } function createEmptyInviteModel() { return { email: '', role: 'member' as Role }; }