{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "totp-multi-factor-enrollment-form",
  "type": "registry:block",
  "title": "TOTP Multi-Factor Enrollment Form",
  "description": "A form allowing users to enroll TOTP-based multi-factor authentication with QR code generation.",
  "dependencies": [
    "@invertase/firebaseui-react"
  ],
  "registryDependencies": [
    "form",
    "input",
    "button",
    "input-otp"
  ],
  "files": [
    {
      "path": "src/components/totp-multi-factor-enrollment-form.tsx",
      "content": "\"use client\";\n\nimport { useState } from \"react\";\nimport { TotpMultiFactorGenerator, type TotpSecret } from \"firebase/auth\";\nimport {\n  enrollWithMultiFactorAssertion,\n  FirebaseUIError,\n  generateTotpQrCode,\n  generateTotpSecret,\n  getTranslation,\n} from \"@invertase/firebaseui-core\";\nimport {\n  useMultiFactorTotpAuthNumberFormSchema,\n  useMultiFactorTotpAuthVerifyFormSchema,\n  useUI,\n} from \"@invertase/firebaseui-react\";\nimport { useForm } from \"react-hook-form\";\nimport { standardSchemaResolver } from \"@hookform/resolvers/standard-schema\";\n\nimport { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from \"@/components/ui/form\";\nimport { Input } from \"@/components/ui/input\";\nimport { Button } from \"@/components/ui/button\";\nimport { InputOTP, InputOTPGroup, InputOTPSlot } from \"@/components/ui/input-otp\";\n\ntype TotpMultiFactorSecretGenerationFormProps = {\n  onSubmit: (secret: TotpSecret, displayName: string) => void;\n};\n\nfunction TotpMultiFactorSecretGenerationForm(props: TotpMultiFactorSecretGenerationFormProps) {\n  const ui = useUI();\n  const schema = useMultiFactorTotpAuthNumberFormSchema();\n\n  const form = useForm<{ displayName: string }>({\n    resolver: standardSchemaResolver(schema),\n    defaultValues: {\n      displayName: \"\",\n    },\n  });\n\n  const onSubmit = async (values: { displayName: string }) => {\n    try {\n      const secret = await generateTotpSecret(ui);\n      props.onSubmit(secret, values.displayName);\n    } catch (error) {\n      const message = error instanceof FirebaseUIError ? error.message : String(error);\n      form.setError(\"root\", { message });\n    }\n  };\n\n  return (\n    <Form {...form}>\n      <form onSubmit={form.handleSubmit(onSubmit)} className=\"flex flex-col gap-y-4\">\n        <FormField\n          control={form.control}\n          name=\"displayName\"\n          render={({ field }) => (\n            <FormItem>\n              <FormLabel>{getTranslation(ui, \"labels\", \"displayName\")}</FormLabel>\n              <FormControl>\n                <Input {...field} type=\"text\" />\n              </FormControl>\n              <FormMessage />\n            </FormItem>\n          )}\n        />\n        <Button type=\"submit\" disabled={ui.state !== \"idle\"}>\n          {getTranslation(ui, \"labels\", \"generateQrCode\")}\n        </Button>\n        {form.formState.errors.root && <FormMessage>{form.formState.errors.root.message}</FormMessage>}\n      </form>\n    </Form>\n  );\n}\n\ntype MultiFactorEnrollmentVerifyTotpFormProps = {\n  secret: TotpSecret;\n  displayName: string;\n  onSuccess: () => void;\n};\n\nexport function MultiFactorEnrollmentVerifyTotpForm(props: MultiFactorEnrollmentVerifyTotpFormProps) {\n  const ui = useUI();\n  const schema = useMultiFactorTotpAuthVerifyFormSchema();\n\n  const form = useForm<{ verificationCode: string }>({\n    resolver: standardSchemaResolver(schema),\n    defaultValues: {\n      verificationCode: \"\",\n    },\n  });\n\n  const onSubmit = async (values: { verificationCode: string }) => {\n    try {\n      const assertion = TotpMultiFactorGenerator.assertionForEnrollment(props.secret, values.verificationCode);\n      await enrollWithMultiFactorAssertion(ui, assertion, values.verificationCode);\n      props.onSuccess();\n    } catch (error) {\n      const message = error instanceof FirebaseUIError ? error.message : String(error);\n      form.setError(\"root\", { message });\n    }\n  };\n\n  const qrCodeDataUrl = generateTotpQrCode(ui, props.secret, props.displayName);\n\n  return (\n    <div className=\"space-y-4\">\n      <div className=\"flex flex-col gap-y-4 items-center justify-center\">\n        <img src={qrCodeDataUrl} alt=\"TOTP QR Code\" className=\"mx-auto\" />\n        <code className=\"text-xs text-muted-foreground text-center\">{props.secret.secretKey.toString()}</code>\n        <p className=\"text-xs text-muted-foreground text-center\">\n          {getTranslation(ui, \"prompts\", \"mfaTotpQrCodePrompt\")}\n        </p>\n      </div>\n      <Form {...form}>\n        <form onSubmit={form.handleSubmit(onSubmit)} className=\"flex flex-col gap-y-4\">\n          <FormField\n            control={form.control}\n            name=\"verificationCode\"\n            render={({ field }) => (\n              <FormItem>\n                <FormLabel>{getTranslation(ui, \"labels\", \"verificationCode\")}</FormLabel>\n                <FormControl>\n                  <InputOTP maxLength={6} {...field}>\n                    <InputOTPGroup>\n                      <InputOTPSlot index={0} />\n                      <InputOTPSlot index={1} />\n                      <InputOTPSlot index={2} />\n                      <InputOTPSlot index={3} />\n                      <InputOTPSlot index={4} />\n                      <InputOTPSlot index={5} />\n                    </InputOTPGroup>\n                  </InputOTP>\n                </FormControl>\n                <FormMessage />\n              </FormItem>\n            )}\n          />\n          <Button type=\"submit\" disabled={ui.state !== \"idle\"}>\n            {getTranslation(ui, \"labels\", \"verifyCode\")}\n          </Button>\n          {form.formState.errors.root && <FormMessage>{form.formState.errors.root.message}</FormMessage>}\n        </form>\n      </Form>\n    </div>\n  );\n}\n\nexport type TotpMultiFactorEnrollmentFormProps = {\n  onSuccess?: () => void;\n};\n\nexport function TotpMultiFactorEnrollmentForm(props: TotpMultiFactorEnrollmentFormProps) {\n  const ui = useUI();\n\n  const [enrollment, setEnrollment] = useState<{\n    secret: TotpSecret;\n    displayName: string;\n  } | null>(null);\n\n  if (!ui.auth.currentUser) {\n    throw new Error(\"User must be authenticated to enroll with multi-factor authentication\");\n  }\n\n  if (!enrollment) {\n    return (\n      <TotpMultiFactorSecretGenerationForm onSubmit={(secret, displayName) => setEnrollment({ secret, displayName })} />\n    );\n  }\n\n  return (\n    <MultiFactorEnrollmentVerifyTotpForm\n      {...enrollment}\n      onSuccess={() => {\n        props.onSuccess?.();\n      }}\n    />\n  );\n}\n",
      "type": "registry:component"
    }
  ],
  "meta": {
    "version": "0.0.2"
  }
}