"use client" import { zodResolver } from "@hookform/resolvers/zod" import type { Organization } from "better-auth/plugins/organization" import { Loader2 } from "lucide-react" import { type ComponentProps, useContext, useMemo } from "react" import { useForm } from "react-hook-form" import * as z from "zod" import { AuthUIContext } from "../../lib/auth-ui-provider" import { cn, getLocalizedError } from "../../lib/utils" import type { AuthLocalization } from "../../localization/auth-localization" import type { SettingsCardClassNames } from "../settings/shared/settings-card" import { Button } from "../ui/button" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "../ui/dialog" import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form" import { Input } from "../ui/input" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/select" export interface InviteMemberDialogProps extends ComponentProps { classNames?: SettingsCardClassNames localization?: AuthLocalization organization: Organization } export function InviteMemberDialog({ classNames, localization: localizationProp, onOpenChange, organization, ...props }: InviteMemberDialogProps) { const { teams: teamOptions, authClient, hooks: { useListInvitations, useListMembers, useSession, useListTeams }, localization: contextLocalization, toast, organization: organizationOptions, localizeErrors } = useContext(AuthUIContext) const { enabled: teamsEnabled } = teamOptions || {} const localization = useMemo( () => ({ ...contextLocalization, ...localizationProp }), [contextLocalization, localizationProp] ) const { data } = useListMembers({ query: { organizationId: organization.id } }) const { refetch } = useListInvitations({ query: { organizationId: organization.id } }) const members = data?.members const { data: sessionData } = useSession() const membership = members?.find((m) => m.userId === sessionData?.user.id) const builtInRoles = [ { role: "owner", label: localization.OWNER }, { role: "admin", label: localization.ADMIN }, { role: "member", label: localization.MEMBER } ] as const const roles = [...builtInRoles, ...(organizationOptions?.customRoles || [])] const availableRoles = roles.filter( (role) => membership?.role === "owner" || role.role !== "owner" ) const { data: teams } = teamsEnabled ? useListTeams({ organizationId: organization.id }) : { data: undefined } const formSchema = z.object({ email: z .string() .min(1, { message: localization.EMAIL_REQUIRED }) .email({ message: localization.INVALID_EMAIL }), role: z.string().min(1, { message: `${localization.ROLE} ${localization.IS_REQUIRED}` }), teamId: z.string().optional() }) const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { email: "", role: "member", teamId: "" } }) const isSubmitting = form.formState.isSubmitting async function onSubmit({ email, role, teamId }: z.infer) { try { await authClient.organization.inviteMember({ email, role: role as (typeof builtInRoles)[number]["role"], organizationId: organization.id, fetchOptions: { throw: true }, ...(teamsEnabled && { teamId }) }) await refetch?.() onOpenChange?.(false) form.reset() toast({ variant: "success", message: localization.SEND_INVITATION_SUCCESS || "Invitation sent successfully" }) } catch (error) { toast({ variant: "error", message: getLocalizedError({ error, localization, localizeErrors }) }) } } return ( {localization.INVITE_MEMBER} {localization.INVITE_MEMBER_DESCRIPTION}
( {localization.EMAIL} )} />
( {localization.ROLE} )} /> {teamsEnabled && ( ( {localization.TEAM} )} /> )}
) }