"use client"; import { Button } from "@app/components/ui/button"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@app/components/ui/form"; import { Input } from "@app/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@app/components/ui/select"; import { toast } from "@app/hooks/useToast"; import { zodResolver } from "@hookform/resolvers/zod"; import { InviteUserBody, InviteUserResponse } from "@server/routers/user"; import { AxiosResponse } from "axios"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; import CopyTextBox from "@app/components/CopyTextBox"; import { Credenza, CredenzaBody, CredenzaClose, CredenzaContent, CredenzaDescription, CredenzaFooter, CredenzaHeader, CredenzaTitle } from "@app/components/Credenza"; import { useOrgContext } from "@app/hooks/useOrgContext"; import { ListRolesResponse } from "@server/routers/role"; import { formatAxiosError } from "@app/lib/api"; import { createApiClient } from "@app/lib/api"; import { useEnvContext } from "@app/hooks/useEnvContext"; import { Checkbox } from "@app/components/ui/checkbox"; type InviteUserFormProps = { open: boolean; setOpen: (open: boolean) => void; }; const formSchema = z.object({ email: z.string().email({ message: "Invalid email address" }), validForHours: z.string().min(1, { message: "Please select a duration" }), roleId: z.string().min(1, { message: "Please select a role" }) }); export default function InviteUserForm({ open, setOpen }: InviteUserFormProps) { const { org } = useOrgContext(); const { env } = useEnvContext(); const api = createApiClient({ env }); const [inviteLink, setInviteLink] = useState(null); const [loading, setLoading] = useState(false); const [expiresInDays, setExpiresInDays] = useState(1); const [roles, setRoles] = useState<{ roleId: number; name: string }[]>([]); const [sendEmail, setSendEmail] = useState(env.email.emailEnabled); const validFor = [ { hours: 24, name: "1 day" }, { hours: 48, name: "2 days" }, { hours: 72, name: "3 days" }, { hours: 96, name: "4 days" }, { hours: 120, name: "5 days" }, { hours: 144, name: "6 days" }, { hours: 168, name: "7 days" } ]; const form = useForm>({ resolver: zodResolver(formSchema), defaultValues: { email: "", validForHours: "72", roleId: "" } }); useEffect(() => { if (open) { setSendEmail(env.email.emailEnabled); form.reset(); setInviteLink(null); setExpiresInDays(1); } }, [open, env.email.emailEnabled, form]); useEffect(() => { if (!open) { return; } async function fetchRoles() { const res = await api .get< AxiosResponse >(`/org/${org?.org.orgId}/roles`) .catch((e) => { console.error(e); toast({ variant: "destructive", title: "Failed to fetch roles", description: formatAxiosError( e, "An error occurred while fetching the roles" ) }); }); if (res?.status === 200) { setRoles(res.data.data.roles); } } fetchRoles(); }, [open]); async function onSubmit(values: z.infer) { setLoading(true); const res = await api .post>( `/org/${org?.org.orgId}/create-invite`, { email: values.email, roleId: parseInt(values.roleId), validHours: parseInt(values.validForHours), sendEmail: sendEmail } as InviteUserBody ) .catch((e) => { if (e.response?.status === 409) { toast({ variant: "destructive", title: "User Already Exists", description: "This user is already a member of the organization." }); } else { toast({ variant: "destructive", title: "Failed to invite user", description: formatAxiosError( e, "An error occurred while inviting the user" ) }); } }); if (res && res.status === 200) { setInviteLink(res.data.data.inviteLink); toast({ variant: "default", title: "User invited", description: "The user has been successfully invited." }); setExpiresInDays(parseInt(values.validForHours) / 24); } setLoading(false); } return ( <> { setOpen(val); if (!val) { setInviteLink(null); setLoading(false); setExpiresInDays(1); form.reset(); } }} > Invite User Give new users access to your organization
{!inviteLink && (
( Email )} /> {env.email.emailEnabled && (
setSendEmail( e as boolean ) } />
)} ( Role )} /> ( Valid For )} /> )} {inviteLink && (
{sendEmail && (

An email has been sent to the user with the access link below. They must access the link to accept the invitation.

)} {!sendEmail && (

The user has been invited. They must access the link below to accept the invitation.

)}

The invite will expire in{" "} {expiresInDays}{" "} {expiresInDays === 1 ? "day" : "days"} .

)}
); }