Skip to main content
Glama
sign-in-form.tsx6.68 kB
import { typeboxResolver } from '@hookform/resolvers/typebox'; import { Static, Type } from '@sinclair/typebox'; import { useMutation } from '@tanstack/react-query'; import { t } from 'i18next'; import { useState } from 'react'; import { SubmitHandler, useForm } from 'react-hook-form'; import { Link, Navigate } from 'react-router-dom'; import { Button } from '@/components/ui/button'; import { Form, FormField, FormItem, FormMessage } from '@/components/ui/form'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { flagsHooks } from '@/hooks/flags-hooks'; import { HttpError, api } from '@/lib/api'; import { authenticationApi } from '@/lib/authentication-api'; import { authenticationSession } from '@/lib/authentication-session'; import { useRedirectAfterLogin } from '@/lib/navigation-utils'; import { formatUtils } from '@/lib/utils'; import { OtpType } from '@activepieces/ee-shared'; import { ApEdition, ApFlagId, AuthenticationResponse, ErrorCode, isNil, SignInRequest, } from '@activepieces/shared'; import { CheckEmailNote } from './check-email-note'; const SignInSchema = Type.Object({ email: Type.String({ pattern: formatUtils.emailRegex.source, errorMessage: t('Email is invalid'), }), password: Type.String({ minLength: 1, errorMessage: t('Password is required'), }), }); type SignInSchema = Static<typeof SignInSchema>; const SignInForm: React.FC = () => { const [showCheckYourEmailNote, setShowCheckYourEmailNote] = useState(false); const form = useForm<SignInSchema>({ resolver: typeboxResolver(SignInSchema), defaultValues: { email: '', password: '', }, mode: 'onChange', }); const { data: edition } = flagsHooks.useFlag(ApFlagId.EDITION); const { data: userCreated } = flagsHooks.useFlag(ApFlagId.USER_CREATED); const redirectAfterLogin = useRedirectAfterLogin(); const { mutate, isPending } = useMutation< AuthenticationResponse, HttpError, SignInRequest >({ mutationFn: authenticationApi.signIn, onSuccess: (data) => { authenticationSession.saveResponse(data, false); redirectAfterLogin(); }, onError: (error) => { if (api.isError(error)) { const errorCode: ErrorCode | undefined = ( error.response?.data as { code: ErrorCode } )?.code; if (isNil(errorCode)) { form.setError('root.serverError', { message: t('Something went wrong, please try again later'), }); return; } switch (errorCode) { case ErrorCode.INVALID_CREDENTIALS: { form.setError('root.serverError', { message: t('Invalid email or password'), }); break; } case ErrorCode.USER_IS_INACTIVE: { form.setError('root.serverError', { message: t('User has been deactivated'), }); break; } case ErrorCode.EMAIL_IS_NOT_VERIFIED: { setShowCheckYourEmailNote(true); break; } case ErrorCode.DOMAIN_NOT_ALLOWED: { form.setError('root.serverError', { message: t(`Email domain is disallowed`), }); break; } case ErrorCode.EMAIL_AUTH_DISABLED: { form.setError('root.serverError', { message: t(`Email authentication has been disabled`), }); break; } default: { form.setError('root.serverError', { message: t('Something went wrong, please try again later'), }); } } } }, }); const onSubmit: SubmitHandler<SignInRequest> = (data) => { form.setError('root.serverError', { message: undefined, }); mutate(data); }; if (!userCreated) { return <Navigate to="/sign-up" />; } return ( <> <Form {...form}> <form className="grid space-y-4"> <FormField control={form.control} name="email" render={({ field }) => ( <FormItem className="grid space-y-2"> <Label htmlFor="email">{t('Email')}</Label> <Input {...field} required id="email" type="text" placeholder={'email@example.com'} className="rounded-sm" tabIndex={1} data-testid="sign-in-email" onChange={(e) => { field.onChange(e); setShowCheckYourEmailNote(false); }} /> <FormMessage /> </FormItem> )} /> <FormField control={form.control} name="password" render={({ field }) => ( <FormItem className="grid space-y-2"> <div className="flex items-center justify-between"> <Label htmlFor="password">{t('Password')}</Label> {edition !== ApEdition.COMMUNITY && ( <Link to="/forget-password" className="text-muted-foreground text-sm hover:text-primary transition-all duration-200" > {t('Forgot your password?')} </Link> )} </div> <Input {...field} required id="password" type="password" placeholder={'********'} className="rounded-sm" tabIndex={2} data-testid="sign-in-password" /> <FormMessage /> </FormItem> )} /> {form?.formState?.errors?.root?.serverError && ( <FormMessage> {form.formState.errors.root.serverError.message} </FormMessage> )} <Button loading={isPending} onClick={(e) => form.handleSubmit(onSubmit)(e)} tabIndex={3} data-testid="sign-in-button" > {t('Sign in')} </Button> </form> </Form> {showCheckYourEmailNote && ( <div className="mt-4"> <CheckEmailNote email={form.getValues().email} type={OtpType.EMAIL_VERIFICATION} /> </div> )} </> ); }; SignInForm.displayName = 'SignIn'; export { SignInForm };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/activepieces/activepieces'

If you have feedback or need assistance with the MCP directory API, please join our Discord server