import HCaptcha from '@hcaptcha/react-hcaptcha' import { zodResolver } from '@hookform/resolvers/zod' import { useQueryClient } from '@tanstack/react-query' import { useRef, useState } from 'react' import { useForm, type SubmitHandler } from 'react-hook-form' import { toast } from 'sonner' import { Button, Form, FormControl, FormField, Input } from 'ui' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import z from 'zod' import { useLastSignIn } from '@/hooks/misc/useLastSignIn' import { BASE_PATH } from '@/lib/constants' import { captureCriticalError } from '@/lib/error-reporting' import { auth, buildPathWithParams } from '@/lib/gotrue' const schema = z.object({ email: z.string().min(1, 'Email is required').email('Must be a valid email'), }) const formId = 'sso-sign-in-form' export const SignInSSOForm = () => { const queryClient = useQueryClient() const captchaRef = useRef(null) const [captchaToken, setCaptchaToken] = useState(null) const [_, setLastSignInUsed] = useLastSignIn() const form = useForm>({ resolver: zodResolver(schema as any), defaultValues: { email: '' }, }) const isSubmitting = form.formState.isSubmitting const onSubmit: SubmitHandler> = async ({ email }) => { const toastId = toast.loading('Signing in...') let token = captchaToken if (!token) { const captchaResponse = await captchaRef.current?.execute({ async: true }) token = captchaResponse?.response ?? null } // redirects to /sign-in to check if the user has MFA setup (handled in SignInLayout.tsx) const redirectTo = buildPathWithParams( `${ process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview' ? location.origin : process.env.NEXT_PUBLIC_SITE_URL }${BASE_PATH}/sign-in-mfa?method=sso` ) const { data, error } = await auth.signInWithSSO({ domain: email.split('@')[1], options: { captchaToken: token ?? undefined, redirectTo, }, }) if (!error) { await queryClient.resetQueries() setLastSignInUsed('sso') if (data) { // redirect to SSO identity provider page window.location.href = data.url } } else { setCaptchaToken(null) captchaRef.current?.resetCaptcha() toast.error(`Failed to sign in: ${error.message}`, { id: toastId }) captureCriticalError(error, 'sign in via SSO') } } return (
( )} />
{ setCaptchaToken(token) }} onExpire={() => { setCaptchaToken(null) }} />
) }