CreateFirebaseAuthDialog.tsx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import { zodResolver } from '@hookform/resolvers/zod'
  2. import { useParams } from 'common'
  3. import { Trash } from 'lucide-react'
  4. import { useEffect } from 'react'
  5. import { SubmitHandler, useForm } from 'react-hook-form'
  6. import { toast } from 'sonner'
  7. import {
  8. Button,
  9. Dialog,
  10. DialogContent,
  11. DialogFooter,
  12. DialogHeader,
  13. DialogSection,
  14. DialogTitle,
  15. Form,
  16. FormControl,
  17. FormField,
  18. Input,
  19. Separator,
  20. } from 'ui'
  21. import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
  22. import * as z from 'zod'
  23. import { useCreateThirdPartyAuthIntegrationMutation } from '@/data/third-party-auth/integration-create-mutation'
  24. interface CreateFirebaseAuthIntegrationProps {
  25. visible: boolean
  26. onClose: () => void
  27. // TODO: Remove this if this Dialog is only used for creating.
  28. onDelete: () => void
  29. }
  30. const FORM_ID = 'create-firebase-auth-integration-form'
  31. const FormSchema = z.object({
  32. enabled: z.boolean(),
  33. firebaseProjectId: z
  34. .string()
  35. .trim()
  36. .min(1)
  37. .regex(/^[A-Za-z0-9-]+$/, 'The project ID contains invalid characters.'), // Only allow alphanumeric characters and hyphens.
  38. })
  39. export const CreateFirebaseAuthIntegrationDialog = ({
  40. visible,
  41. onClose,
  42. onDelete,
  43. }: CreateFirebaseAuthIntegrationProps) => {
  44. // TODO: Remove this if this Dialog is only used for creating.
  45. const isCreating = true
  46. const { ref: projectRef } = useParams()
  47. const { mutate: createAuthIntegration, isPending } = useCreateThirdPartyAuthIntegrationMutation({
  48. onSuccess: () => {
  49. toast.success(`Successfully created a new Firebase Auth integration.`)
  50. onClose()
  51. },
  52. })
  53. const form = useForm<z.infer<typeof FormSchema>>({
  54. resolver: zodResolver(FormSchema as any),
  55. defaultValues: {
  56. enabled: true,
  57. firebaseProjectId: '',
  58. },
  59. })
  60. useEffect(() => {
  61. if (visible) {
  62. form.reset({
  63. enabled: true,
  64. firebaseProjectId: '',
  65. })
  66. // the form input doesn't exist when the form is reset
  67. setTimeout(() => {
  68. form.setFocus('firebaseProjectId')
  69. }, 25)
  70. }
  71. }, [visible])
  72. const onSubmit: SubmitHandler<z.infer<typeof FormSchema>> = async (values) => {
  73. createAuthIntegration({
  74. projectRef: projectRef!,
  75. oidcIssuerUrl: `https://securetoken.google.com/${values.firebaseProjectId}`,
  76. })
  77. }
  78. return (
  79. <Dialog open={visible} onOpenChange={() => onClose()}>
  80. <DialogContent>
  81. <DialogHeader>
  82. <DialogTitle className="truncate">
  83. {isCreating
  84. ? `Add new Firebase Auth connection`
  85. : `Update existing Firebase Auth connection`}
  86. </DialogTitle>
  87. </DialogHeader>
  88. <Separator />
  89. <DialogSection>
  90. <Form {...form}>
  91. <form id={FORM_ID} onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
  92. {/* Enabled flag can't be changed for now because there's no update API call for integrations */}
  93. {/* <FormField
  94. key="enabled"
  95. control={form.control}
  96. name="enabled"
  97. render={({ field }) => (
  98. <FormItemLayout
  99. className="px-8"
  100. label={`Enable Firebase Auth Connection`}
  101. layout="flex"
  102. >
  103. <FormControl>
  104. <Switch
  105. checked={field.value}
  106. onCheckedChange={field.onChange}
  107. disabled={field.disabled}
  108. />
  109. </FormControl>
  110. </FormItemLayout>
  111. )}
  112. />
  113. <Separator /> */}
  114. <p className="text-sm text-foreground-light">
  115. This will enable a JWT token from a specific Firebase project to access data from
  116. this Briven project.
  117. </p>
  118. <FormField
  119. key="firebaseProjectId"
  120. control={form.control}
  121. name="firebaseProjectId"
  122. render={({ field }) => (
  123. <FormItemLayout label="Firebase Auth Project ID">
  124. <FormControl>
  125. <Input {...field} />
  126. </FormControl>
  127. </FormItemLayout>
  128. )}
  129. />
  130. </form>
  131. </Form>
  132. </DialogSection>
  133. <DialogFooter>
  134. {!isCreating && (
  135. <div className="flex-1">
  136. <Button type="danger" onClick={() => onDelete()} icon={<Trash />}>
  137. Remove connection
  138. </Button>
  139. </div>
  140. )}
  141. <Button disabled={isPending} type="default" onClick={() => onClose()}>
  142. Cancel
  143. </Button>
  144. <Button form={FORM_ID} htmlType="submit" disabled={isPending} loading={isPending}>
  145. {isCreating ? 'Create connection' : 'Update connection'}
  146. </Button>
  147. </DialogFooter>
  148. </DialogContent>
  149. </Dialog>
  150. )
  151. }