Files
supabase/apps/studio/components/interfaces/SignIn/SignInSSOForm.tsx
T
Joshen Lim 1aa371a9d7 Add sign in event for email password login (#31395)
* Add sign in event for email password login

* Also add event track for sign in with SSO

* Remove unused variable
2024-12-28 10:51:04 +08:00

126 lines
3.7 KiB
TypeScript

import HCaptcha from '@hcaptcha/react-hcaptcha'
import * as Sentry from '@sentry/nextjs'
import { useQueryClient } from '@tanstack/react-query'
import { useRef, useState } from 'react'
import { toast } from 'sonner'
import { object, string } from 'yup'
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
import { useLastSignIn } from 'hooks/misc/useLastSignIn'
import { BASE_PATH } from 'lib/constants'
import { TelemetryActions } from 'lib/constants/telemetry'
import { auth, buildPathWithParams } from 'lib/gotrue'
import { Button, Form, Input } from 'ui'
const WHITELIST_ERRORS = ['No SSO provider assigned for this domain']
const SignInSSOForm = () => {
const queryClient = useQueryClient()
const captchaRef = useRef<HCaptcha>(null)
const [captchaToken, setCaptchaToken] = useState<string | null>(null)
const [_, setLastSignInUsed] = useLastSignIn()
const signInSchema = object({
email: string().email('Must be a valid email').required('Email is required'),
})
const { mutate: sendEvent } = useSendEventMutation()
const onSignIn = async ({ email }: { email: string }) => {
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`
)
const { data, error } = await auth.signInWithSSO({
domain: email.split('@')[1],
options: {
captchaToken: token ?? undefined,
redirectTo,
},
})
if (!error) {
sendEvent({ action: TelemetryActions.SIGN_IN, properties: { category: 'account' } })
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 })
if (!WHITELIST_ERRORS.includes(error.message)) {
Sentry.captureMessage('[CRITICAL] Failed to sign in via SSO: ' + error.message)
}
}
}
return (
<Form
validateOnBlur
id="signIn-form"
initialValues={{ email: '' }}
validationSchema={signInSchema}
onSubmit={onSignIn}
>
{({ isSubmitting }: { isSubmitting: boolean }) => {
return (
<div className="flex flex-col gap-4">
<Input
id="email"
name="email"
type="email"
label="Email"
placeholder="gavin@hooli.com"
disabled={isSubmitting}
/>
<div className="self-center">
<HCaptcha
ref={captchaRef}
sitekey={process.env.NEXT_PUBLIC_HCAPTCHA_SITE_KEY!}
size="invisible"
onVerify={(token) => {
setCaptchaToken(token)
}}
onExpire={() => {
setCaptchaToken(null)
}}
/>
</div>
<Button
block
form="signIn-form"
htmlType="submit"
size="large"
disabled={isSubmitting}
loading={isSubmitting}
>
Sign In
</Button>
</div>
)
}}
</Form>
)
}
export default SignInSSOForm