import React, { useState, useEffect, useCallback, } from 'react'; import { useTranslation } from 'next-i18next'; import { useRouter } from 'next/router'; import ReactCardFlip from 'react-card-flip'; import { apiv3Post } from '~/client/util/apiv3-client'; import { LoginErrorCode } from '~/interfaces/errors/login-form-error'; import { IErrorV3 } from '~/interfaces/errors/v3-error'; type LoginFormProps = { username?: string, name?: string, email?: string, isRegistrationEnabled: boolean, isEmailAuthenticationEnabled: boolean, registrationMode?: string, registrationWhiteList: string[], isPasswordResetEnabled: boolean, isLocalStrategySetup: boolean, isLdapStrategySetup: boolean, objOfIsExternalAuthEnableds?: any, isMailerSetup?: boolean } export const LoginForm = (props: LoginFormProps): JSX.Element => { const { t } = useTranslation(); const router = useRouter(); const { isLocalStrategySetup, isLdapStrategySetup, isPasswordResetEnabled, isRegistrationEnabled, isEmailAuthenticationEnabled, registrationMode, registrationWhiteList, isMailerSetup, objOfIsExternalAuthEnableds, } = props; const isLocalOrLdapStrategiesEnabled = isLocalStrategySetup || isLdapStrategySetup; const isSomeExternalAuthEnabled = Object.values(objOfIsExternalAuthEnableds).some(elem => elem); // states const [isRegistering, setIsRegistering] = useState(false); // For Login const [usernameForLogin, setUsernameForLogin] = useState(''); const [passwordForLogin, setPasswordForLogin] = useState(''); const [loginErrors, setLoginErrors] = useState([]); // For Register const [usernameForRegister, setUsernameForRegister] = useState(''); const [nameForRegister, setNameForRegister] = useState(''); const [emailForRegister, setEmailForRegister] = useState(''); const [passwordForRegister, setPasswordForRegister] = useState(''); const [registerErrors, setRegisterErrors] = useState([]); useEffect(() => { const { hash } = window.location; if (hash === '#register') { setIsRegistering(true); } }, []); // functions const handleLoginWithExternalAuth = useCallback((e) => { const auth = e.currentTarget.id; window.location.href = `/passport/${auth}`; }, []); const resetLoginErrors = useCallback(() => { if (loginErrors.length === 0) return; setLoginErrors([]); }, [loginErrors.length]); const handleLoginWithLocalSubmit = useCallback(async(e) => { e.preventDefault(); resetLoginErrors(); const loginForm = { username: usernameForLogin, password: passwordForLogin, }; try { const res = await apiv3Post('/login', { loginForm }); const { redirectTo } = res.data; router.push(redirectTo); } catch (err) { setLoginErrors(err); } return; }, [passwordForLogin, resetLoginErrors, router, usernameForLogin]); const renderLoginErrors = useCallback((errors, isWithDangerouslySetinnerHtml = false) => { if (errors.length === 0) return; return isWithDangerouslySetinnerHtml ? (
{errors.map((err, index) => { return ( ); })}
) : ( ); }, [t]); const renderLocalOrLdapLoginForm = useCallback(() => { const { isLdapStrategySetup } = props; const errorsWithDangerouslySetInnerHTML: IErrorV3[] = []; const errorsWithoutDanderouslySetInnerHTML: IErrorV3[] = []; loginErrors.forEach((e) => { if (e.code === LoginErrorCode.PROVIDER_DUPLICATED_USERNAME_EXCEPTION) { errorsWithDangerouslySetInnerHTML.push(e); } else { errorsWithoutDanderouslySetInnerHTML.push(e); } }); return ( <> {renderLoginErrors(errorsWithDangerouslySetInnerHTML, true)} {renderLoginErrors(errorsWithoutDanderouslySetInnerHTML, false)}
{ setUsernameForLogin(e.target.value) }} name="usernameForLogin" /> {isLdapStrategySetup && (
LDAP
)}
{ setPasswordForLogin(e.target.value) }} name="passwordForLogin" />
); }, [handleLoginWithLocalSubmit, loginErrors, props, t]); const renderExternalAuthInput = useCallback((auth) => { const authIconNames = { google: 'google', github: 'github', facebook: 'facebook', twitter: 'twitter', oidc: 'openid', saml: 'key', basic: 'lock', }; return (
by {auth} Account
); }, [handleLoginWithExternalAuth, t]); const renderExternalAuthLoginForm = useCallback(() => { const { isLocalStrategySetup, isLdapStrategySetup, objOfIsExternalAuthEnableds } = props; const isExternalAuthCollapsible = isLocalStrategySetup || isLdapStrategySetup; const collapsibleClass = isExternalAuthCollapsible ? 'collapse collapse-external-auth' : ''; return ( <>
{Object.keys(objOfIsExternalAuthEnableds).map((auth) => { if (!objOfIsExternalAuthEnableds[auth]) { return; } return renderExternalAuthInput(auth); })}
); }, [props, renderExternalAuthInput]); const handleRegisterFormSubmit = useCallback(async(e, requestPath) => { e.preventDefault(); const registerForm = { username: usernameForRegister, name: nameForRegister, email: emailForRegister, password: passwordForRegister, }; try { const res = await apiv3Post(requestPath, { registerForm }); const { redirectTo } = res.data; router.push(redirectTo); } catch (err) { // Execute if error exists if (err != null || err.length > 0) { setRegisterErrors(err); } } return; }, [emailForRegister, nameForRegister, passwordForRegister, router, usernameForRegister]); const resetRegisterErrors = useCallback(() => { if (registerErrors.length === 0) return; setRegisterErrors([]); }, [registerErrors.length]); const switchForm = useCallback(() => { setIsRegistering(!isRegistering); resetLoginErrors(); resetRegisterErrors(); }, [isRegistering, resetLoginErrors, resetRegisterErrors]); const renderRegisterForm = useCallback(() => { let registerAction = '/register'; let submitText = t('Sign up'); if (isEmailAuthenticationEnabled) { registerAction = '/user-activation/register'; submitText = t('page_register.send_email'); } return ( {registrationMode === 'Restricted' && (

{t('page_register.notice.restricted')}
{t('page_register.notice.restricted_defail')}

)} { (!isMailerSetup && isEmailAuthenticationEnabled) && (

{t('security_settings.Local.please_enable_mailer')}

)} { registerErrors != null && registerErrors.length > 0 && (

{registerErrors.map((err, index) => { return ( {t(err.message)}
); })}

) }
handleRegisterFormSubmit(e, registerAction) } id="register-form"> {!isEmailAuthenticationEnabled && (
{/* username */} { setUsernameForRegister(e.target.value) }} placeholder={t('User ID')} name="username" defaultValue={props.username} required />

{/* name */} { setNameForRegister(e.target.value) }} placeholder={t('Name')} name="name" defaultValue={props.name} required />
)}
{/* email */} { setEmailForRegister(e.target.value) }} placeholder={t('Email')} name="email" defaultValue={props.email} required />
{registrationWhiteList.length > 0 && ( <>

{t('page_register.form_help.email')}

    {registrationWhiteList.map((elem) => { return (
  • {elem}
  • ); })}
)} {!isEmailAuthenticationEnabled && (
{/* Password */} { setPasswordForRegister(e.target.value) }} placeholder={t('Password')} name="password" required />
)} {/* Sign up button (submit) */}
{t('Sign in is here')}
); }, [handleRegisterFormSubmit, isEmailAuthenticationEnabled, isMailerSetup, props.email, props.name, props.username, registerErrors, registrationMode, registrationWhiteList, switchForm, t]); return (
{isLocalOrLdapStrategiesEnabled && renderLocalOrLdapLoginForm()} {isSomeExternalAuthEnabled && renderExternalAuthLoginForm()} {isLocalOrLdapStrategiesEnabled && isPasswordResetEnabled && ( )} {/* Sign up link */} {isRegistrationEnabled && ( )}
{/* Register form for /login#register */} {isRegistrationEnabled && renderRegisterForm()}
GROWI.ORG
); };