InviteUserModal.tsx99 lines · main
1import { zodResolver } from '@hookform/resolvers/zod'
2import { PermissionAction } from '@supabase/shared-types/out/constants'
3import { useParams } from 'common'
4import { SubmitHandler, useForm } from 'react-hook-form'
5import { toast } from 'sonner'
6import { Button, Form, FormControl, FormField, Input, Modal } from 'ui'
7import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
8import * as z from 'zod'
9
10import { useUserInviteMutation } from '@/data/auth/user-invite-mutation'
11import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
12
13export type InviteUserModalProps = {
14 visible: boolean
15 setVisible: (visible: boolean) => void
16}
17
18const formSchema = z.object({
19 email: z.string().min(1, 'Please enter a valid email').email('Please enter a valid email'),
20})
21const formId = 'invite-user-form'
22
23const InviteUserModal = ({ visible, setVisible }: InviteUserModalProps) => {
24 const { ref: projectRef } = useParams()
25 const form = useForm<z.infer<typeof formSchema>>({
26 resolver: zodResolver(formSchema as any),
27 defaultValues: {
28 email: '',
29 },
30 })
31
32 const handleToggle = () => setVisible(!visible)
33 const { mutate: inviteUser, isPending: isInviting } = useUserInviteMutation({
34 onSuccess: (_, variables) => {
35 toast.success(`Sent invite email to ${variables.email}`)
36 setVisible(false)
37 },
38 })
39 const { can: canInviteUsers } = useAsyncCheckPermissions(
40 PermissionAction.AUTH_EXECUTE,
41 'invite_user'
42 )
43
44 const onInviteUser: SubmitHandler<z.infer<typeof formSchema>> = async (values) => {
45 if (!projectRef) return console.error('Project ref is required')
46 inviteUser(
47 { projectRef, email: values.email },
48 {
49 onSuccess: () => {
50 form.reset()
51 },
52 }
53 )
54 }
55
56 return (
57 <Modal
58 hideFooter
59 size="small"
60 key="invite-user-modal"
61 visible={visible}
62 header="Invite a new user"
63 onCancel={handleToggle}
64 >
65 <Form {...form}>
66 <Modal.Content>
67 <form id={formId} onSubmit={form.handleSubmit(onInviteUser)} noValidate>
68 <FormField
69 control={form.control}
70 name="email"
71 render={({ field }) => (
72 <FormItemLayout layout="vertical" label="User email">
73 <FormControl className="relative col-span-6">
74 <Input {...field} />
75 </FormControl>
76 </FormItemLayout>
77 )}
78 />
79 </form>
80 </Modal.Content>
81
82 <Modal.Content>
83 <Button
84 form={formId}
85 block
86 size="small"
87 htmlType="submit"
88 loading={isInviting}
89 disabled={!canInviteUsers || isInviting}
90 >
91 Invite user
92 </Button>
93 </Modal.Content>
94 </Form>
95 </Modal>
96 )
97}
98
99export default InviteUserModal