web/front/LoginForm.tsx
import Router from 'next/router'
import React from 'react'
import Script from 'next/script'
import { LOGIN_ACTION, REGISTER_ACTION, useCtrlEnterSubmit, setCookie, setupUserLocalStorage } from 'front'
import { AppContext } from 'front'
import config from 'front/config'
import MapErrors from 'front/MapErrors'
import Label from 'front/Label'
import { webApi } from 'front/api'
import routes from 'front/routes'
const LoginForm = ({ register = false }) => {
const [isLoading, setLoading] = React.useState(false);
const [errors, setErrors] = React.useState([]);
const { prevPageNoSignup } = React.useContext(AppContext)
let email, setEmail;
let displayName, setDisplayName;
if (register) {
[email, setEmail] = React.useState("");
[displayName, setDisplayName] = React.useState("");
}
const [username, setUsername] = React.useState("");
const [password, setPassword] = React.useState("");
let handleEmailChange, handleDisplayNameChange;
if (register) {
handleEmailChange = React.useCallback(
(e) => setEmail(e.target.value),
[]
);
handleDisplayNameChange = React.useCallback(
(e) => setDisplayName(e.target.value),
[]
);
}
const handleUsernameChange = React.useCallback(
(e) => setUsername(e.target.value),
[]
);
const handlePasswordChange = React.useCallback(
(e) => setPassword(e.target.value),
[]
);
const useCaptcha = register && config.useCaptcha
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
let recaptchaToken
if (useCaptcha) {
recaptchaToken = await new Promise((resolve, reject) => {
grecaptcha.ready(function() {
grecaptcha.execute(process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY, {action: 'submit'}).then(function(token) {
resolve(token)
});
});
})
}
try {
let data, status;
if (register) {
({ data, status } = await webApi.userCreate({ displayName, username, email, password }, recaptchaToken));
if (status === 200) {
Router.push(routes.userVerify(data.user.email))
}
} else {
({ data, status } = await webApi.userLogin({ username, password }));
if (status === 200) {
if (data.verified) {
if (data.user) {
await setupUserLocalStorage(data.user, setErrors)
// Can't simply user Router.back() here because our default redirection pattern now
// is page -> signup -> signin, so after signin user goes back to signup, making it
// feel like the signin failed.
//Router.back()
Router.push(prevPageNoSignup ? prevPageNoSignup : routes.home())
}
} else {
Router.push(routes.userVerify(data.user.email))
}
}
}
if (status !== 200 && data.errors) {
setErrors(data.errors);
}
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
};
useCtrlEnterSubmit(handleSubmit)
return (
<>
<MapErrors errors={errors} />
<form onSubmit={handleSubmit}>
{register &&
<Label label="Display name">
<input
autoComplete="name"
type="text"
placeholder="John Smith"
value={displayName}
onChange={handleDisplayNameChange}
/>
</Label>
}
<Label label={ register ? "Username (cannot be modified later)" : "Username or email" }>
<input
autoComplete="username"
type="text"
placeholder="a-z, 0-9, '-', e.g.: john-smith, johnsmith123"
value={username}
onChange={handleUsernameChange}
/>
</Label>
{register &&
<Label label="Email">
<input
autoComplete="email"
type="email"
placeholder="john.smith@mail.com"
value={email}
onChange={handleEmailChange}
/>
</Label>
}
<Label label="Password">
<input
autoComplete={register ? "new-password" : "current-password"}
type="password"
placeholder="Password"
value={password}
onChange={handlePasswordChange}
/>
</Label>
<button
className="btn"
type="submit"
disabled={isLoading}
>
{`${register ? REGISTER_ACTION : LOGIN_ACTION}`}
</button>
</form>
{useCaptcha &&
<Script src={`https://www.google.com/recaptcha/api.js?render=${process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY}`} />
}
</>
);
};
export default LoginForm;