OrganizationDetailsForm.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import { zodResolver } from '@hookform/resolvers/zod'
  2. import { PermissionAction } from '@supabase/shared-types/out/constants'
  3. import { useQueryClient } from '@tanstack/react-query'
  4. import { useParams } from 'common'
  5. import { useEffect } from 'react'
  6. import { useForm } from 'react-hook-form'
  7. import { toast } from 'sonner'
  8. import { Card, CardContent, CardFooter, Form, FormControl, FormField, Input } from 'ui'
  9. import { Input as PasswordInput } from 'ui-patterns/DataInputs/Input'
  10. import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
  11. import * as z from 'zod'
  12. import { FormActions } from '@/components/ui/Forms/FormActions'
  13. import { useOrganizationUpdateMutation } from '@/data/organizations/organization-update-mutation'
  14. import { invalidateOrganizationsQuery } from '@/data/organizations/organizations-query'
  15. import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
  16. import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
  17. import type { ResponseError } from '@/types'
  18. const OrgDetailsSchema = z.object({
  19. name: z.string().min(1, 'Organization name is required'),
  20. })
  21. export const OrganizationDetailsForm = () => {
  22. const { slug } = useParams()
  23. const queryClient = useQueryClient()
  24. const { data: selectedOrganization } = useSelectedOrganizationQuery()
  25. const { can: canUpdateOrganization } = useAsyncCheckPermissions(
  26. PermissionAction.UPDATE,
  27. 'organizations'
  28. )
  29. const { mutate: updateOrganization, isPending: isUpdatingDetails } =
  30. useOrganizationUpdateMutation()
  31. const orgDetailsForm = useForm<z.infer<typeof OrgDetailsSchema>>({
  32. resolver: zodResolver(OrgDetailsSchema as any),
  33. defaultValues: { name: selectedOrganization?.name ?? '' },
  34. })
  35. const onUpdateOrganizationDetails = async (values: z.infer<typeof OrgDetailsSchema>) => {
  36. if (!canUpdateOrganization) {
  37. return toast.error('You do not have the required permissions to update this organization')
  38. }
  39. if (!slug) return console.error('Slug is required')
  40. updateOrganization(
  41. { slug, name: values.name },
  42. {
  43. onSuccess: () => {
  44. invalidateOrganizationsQuery(queryClient)
  45. toast.success('Successfully updated organization name')
  46. },
  47. onError: (error: ResponseError) => {
  48. toast.error(`Failed to update organization name: ${error.message}`)
  49. },
  50. }
  51. )
  52. }
  53. const permissionsHelperText = !canUpdateOrganization
  54. ? "You need additional permissions to manage this organization's settings"
  55. : undefined
  56. useEffect(() => {
  57. if (selectedOrganization && !isUpdatingDetails) {
  58. orgDetailsForm.reset({ name: selectedOrganization.name ?? '' })
  59. }
  60. }, [selectedOrganization, orgDetailsForm, isUpdatingDetails])
  61. return (
  62. <Form {...orgDetailsForm}>
  63. <form
  64. id="org-details-form"
  65. onSubmit={orgDetailsForm.handleSubmit(onUpdateOrganizationDetails)}
  66. >
  67. <Card>
  68. <CardContent>
  69. <FormField
  70. control={orgDetailsForm.control}
  71. name="name"
  72. render={({ field }) => (
  73. <FormItemLayout label="Organization name" layout="flex-row-reverse">
  74. <FormControl>
  75. <Input {...field} disabled={!canUpdateOrganization || isUpdatingDetails} />
  76. </FormControl>
  77. </FormItemLayout>
  78. )}
  79. />
  80. </CardContent>
  81. <CardContent>
  82. <FormItemLayout label="Organization slug" layout="flex-row-reverse">
  83. <PasswordInput copy disabled id="slug" value={selectedOrganization?.slug ?? ''} />
  84. </FormItemLayout>
  85. </CardContent>
  86. <CardFooter className="flex justify-end p-4 md:px-8">
  87. <FormActions
  88. form="org-details-form"
  89. isSubmitting={isUpdatingDetails}
  90. hasChanges={orgDetailsForm.formState.isDirty}
  91. handleReset={() => orgDetailsForm.reset()}
  92. helper={permissionsHelperText}
  93. disabled={!canUpdateOrganization}
  94. />
  95. </CardFooter>
  96. </Card>
  97. </form>
  98. </Form>
  99. )
  100. }