Files
stream.graff.tech-client/src/PersonalAreaLoginPage.tsx
T
2023-08-07 15:05:18 +05:00

141 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* eslint-disable @typescript-eslint/no-explicit-any */
import ky from "ky";
import useAuthStore from "./stores/useAuthStore";
import { FormEvent, useRef, useState } from "react";
type User = {
id: string;
username: string;
};
interface IResult {
error?: number;
accessToken?: string;
user?: User;
}
function PersonalAreaLoginPage() {
const [setAccessToken, setUser] = useAuthStore((state) => [
state.setAccessToken,
state.setUser,
]);
const [username, setUsername] = useState<string>("");
const [password, setPassword] = useState<string>("");
const [error, setError] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(false);
const usernameRef = useRef<HTMLInputElement>(null);
const passwordRef = useRef<HTMLInputElement>(null);
async function auth(e: FormEvent<HTMLFormElement>) {
e.preventDefault();
setIsLoading(true);
try {
const result: IResult = await ky
.post(import.meta.env.VITE_COORD_URL + "/login", {
json: { username, password },
})
.json();
setIsLoading(false);
if (result.error) {
passwordRef.current?.focus();
setPassword("");
setError("Неверное имя пользователя или пароль");
return;
}
if (!result.accessToken || !result.user) {
setError("Не удалось получить данные");
return;
}
setAccessToken(result.accessToken);
setUser(result.user);
} catch (error) {
setIsLoading(false);
if (error instanceof Error) {
if (error.message === "Failed to fetch") {
setError("Нет соединения с сервером, попробуйте позже");
} else {
setError(error.message);
}
}
}
}
return (
<div className="p-8 min-h-screen flex flex-col justify-center items-center text-[#F2F2F2]">
<div className="space-y-12 w-[400px] bg-[#151619] p-8 rounded-lg shadow">
<p className="text-2xl font-gilroy">Вход в личный кабинет</p>
<form onSubmit={auth} className="flex flex-col gap-12">
<div className="flex flex-col gap-8">
<div className="space-y-1">
<p className="text-[#C5C7CE] text-sm">Имя пользователя</p>
<input
ref={usernameRef}
required
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
className="px-3 py-2 rounded bg-[#1C1D21] outline-none focus:outline-[#BC75FF] w-full transition-all"
/>
</div>
<div className="space-y-1">
<p className="text-[#C5C7CE] text-sm">Пароль</p>
<input
ref={passwordRef}
required
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="px-3 py-2 rounded bg-[#1C1D21] outline-none focus:outline-[#BC75FF] w-full transition-all"
/>
</div>
</div>
<button
type="submit"
disabled={isLoading}
className="px-4 py-2 rounded bg-gradient outline-none opacity-95 hover:opacity-100 transition-all disabled:opacity-50 flex justify-center items-center h-10"
>
{isLoading ? (
<svg
className="animate-spin h-5 w-5"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
></circle>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
) : (
<span>Войти</span>
)}
</button>
</form>
<p className="text-sm text-red-500 min-h-[40px]">{error && error}</p>
</div>
</div>
);
}
export default PersonalAreaLoginPage;