126 lines
3.3 KiB
TypeScript
126 lines
3.3 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import { currentUser, login, User } from "./api";
|
|
import Header from "./Header";
|
|
import { useLocation, useNavigate } from "react-router";
|
|
import { Eye, EyeSlash } from "./Icons";
|
|
|
|
export interface LoginProps {
|
|
onLogin: (user: User) => void;
|
|
}
|
|
|
|
export const Login = ({ onLogin }: LoginProps) => {
|
|
const [username, setUsername] = useState("");
|
|
const [password, setPassword] = useState("");
|
|
const [error, setError] = useState("");
|
|
const [loading, setLoading] = useState(false);
|
|
const [visible, setVisible] = useState(false);
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
|
|
async function doLogin() {
|
|
setLoading(true);
|
|
setError("");
|
|
const timeout = new Promise((r) => setTimeout(r, 1000));
|
|
let user: User;
|
|
try {
|
|
await login({ username, password });
|
|
user = await currentUser();
|
|
} catch (e) {
|
|
await timeout;
|
|
setError("failed");
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
await timeout;
|
|
onLogin(user);
|
|
}
|
|
|
|
function handleSubmit(e: React.FormEvent) {
|
|
e.preventDefault();
|
|
doLogin();
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (location.state) {
|
|
const queryUsername = location.state.username;
|
|
const queryPassword = location.state.password;
|
|
if (queryUsername) setUsername(queryUsername);
|
|
if (queryPassword) setPassword(queryPassword);
|
|
navigate(location.pathname, { replace: true });
|
|
}
|
|
}, []);
|
|
|
|
return (
|
|
<>
|
|
<Header />
|
|
<form onSubmit={handleSubmit}>
|
|
<div
|
|
style={{
|
|
position: "relative",
|
|
display: "flex",
|
|
alignItems: "end",
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
width: "100%",
|
|
marginRight: "8px",
|
|
display: "flex",
|
|
justifyContent: "center",
|
|
flexDirection: "column",
|
|
}}
|
|
>
|
|
<div>
|
|
<input
|
|
type="text"
|
|
id="username"
|
|
name="username"
|
|
placeholder="username"
|
|
required
|
|
value={username}
|
|
onChange={(evt) => {
|
|
setError("");
|
|
setUsername(evt.target.value);
|
|
}}
|
|
/>
|
|
</div>
|
|
<div>
|
|
<input
|
|
type={visible ? "text" : "password"}
|
|
id="password"
|
|
name="password"
|
|
placeholder="password"
|
|
minLength={8}
|
|
value={password}
|
|
required
|
|
onChange={(evt) => {
|
|
setError("");
|
|
setPassword(evt.target.value);
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div
|
|
style={{
|
|
position: "absolute",
|
|
right: "-1em",
|
|
margin: "auto 4px",
|
|
background: "unset",
|
|
fontSize: "x-large",
|
|
cursor: "pointer",
|
|
}}
|
|
onClick={() => setVisible(!visible)}
|
|
>
|
|
{visible ? <Eye /> : <EyeSlash />}
|
|
</div>
|
|
</div>
|
|
{error && <span style={{ color: "red" }}>{error}</span>}
|
|
<button type="submit" value="login" style={{ fontSize: "small" }}>
|
|
login
|
|
</button>
|
|
{loading && <span className="loader" />}
|
|
</form>
|
|
</>
|
|
);
|
|
};
|