178 lines
4.6 KiB
TypeScript
178 lines
4.6 KiB
TypeScript
import {
|
||
TextField,
|
||
Box,
|
||
Button,
|
||
Typography,
|
||
Alert,
|
||
CircularProgress,
|
||
FormControlLabel,
|
||
Checkbox,
|
||
Paper,
|
||
} from "@mui/material";
|
||
import { authStore, userStore } from "@shared";
|
||
import { useState, useEffect } from "react";
|
||
import { useNavigate } from "react-router-dom";
|
||
import { toast } from "react-toastify";
|
||
|
||
export const LoginPage = () => {
|
||
const navigate = useNavigate();
|
||
const [email, setEmail] = useState("");
|
||
const [password, setPassword] = useState("");
|
||
const [rememberMe, setRememberMe] = useState(false);
|
||
const [error, setError] = useState<string | null>(null);
|
||
const [isLoading, setIsLoading] = useState(false);
|
||
const { login } = authStore;
|
||
const { getUsers } = userStore;
|
||
useEffect(() => {
|
||
const savedEmail = localStorage.getItem("rememberedEmail");
|
||
const savedPassword = localStorage.getItem("rememberedPassword");
|
||
if (savedEmail && savedPassword) {
|
||
setEmail(savedEmail);
|
||
setPassword(savedPassword);
|
||
setRememberMe(true);
|
||
}
|
||
}, []);
|
||
|
||
const handleSubmit = async (e: React.FormEvent) => {
|
||
e.preventDefault();
|
||
setError(null);
|
||
setIsLoading(true);
|
||
|
||
try {
|
||
await login(email, password);
|
||
|
||
if (rememberMe) {
|
||
localStorage.setItem("rememberedEmail", email);
|
||
localStorage.setItem("rememberedPassword", password);
|
||
} else {
|
||
localStorage.removeItem("rememberedEmail");
|
||
localStorage.removeItem("rememberedPassword");
|
||
}
|
||
|
||
navigate("/map");
|
||
try {
|
||
await getUsers();
|
||
} catch (err) {
|
||
console.error(err);
|
||
}
|
||
|
||
toast.success("Вход в систему выполнен успешно");
|
||
} catch (err) {
|
||
setError(
|
||
err instanceof Error ? err.message : "Ошибка при входе в систему"
|
||
);
|
||
toast.error(
|
||
err instanceof Error ? err.message : "Ошибка при входе в систему"
|
||
);
|
||
} finally {
|
||
setIsLoading(false);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<Box
|
||
sx={{
|
||
display: "flex",
|
||
flexDirection: "column",
|
||
alignItems: "center",
|
||
justifyContent: "center",
|
||
width: "100vw",
|
||
height: "100vh",
|
||
gap: 3,
|
||
p: 3,
|
||
backgroundImage: "url('/login-bg.png')",
|
||
backgroundSize: "cover",
|
||
backgroundPosition: "center",
|
||
backgroundRepeat: "no-repeat",
|
||
}}
|
||
>
|
||
<Paper
|
||
elevation={3}
|
||
sx={{
|
||
p: 4,
|
||
borderRadius: 2,
|
||
backgroundColor: "white",
|
||
width: "100%",
|
||
maxWidth: "400px",
|
||
}}
|
||
>
|
||
<Typography
|
||
variant="h4"
|
||
component="h1"
|
||
className="text-center pb-[50px]"
|
||
>
|
||
Вход в систему
|
||
</Typography>
|
||
<Box
|
||
component="form"
|
||
onSubmit={handleSubmit}
|
||
sx={{
|
||
display: "flex",
|
||
flexDirection: "column",
|
||
gap: 2,
|
||
width: "100%",
|
||
}}
|
||
>
|
||
{error && (
|
||
<Alert severity="error" sx={{ mb: 2 }}>
|
||
{error}
|
||
</Alert>
|
||
)}
|
||
<TextField
|
||
label="Email"
|
||
type="email"
|
||
variant="outlined"
|
||
fullWidth
|
||
required
|
||
autoComplete="email"
|
||
value={email}
|
||
onChange={(e) => setEmail(e.target.value)}
|
||
disabled={isLoading}
|
||
error={!!error}
|
||
/>
|
||
<TextField
|
||
label="Пароль"
|
||
type="password"
|
||
variant="outlined"
|
||
fullWidth
|
||
required
|
||
autoComplete="current-password"
|
||
value={password}
|
||
onChange={(e) => setPassword(e.target.value)}
|
||
disabled={isLoading}
|
||
error={!!error}
|
||
/>
|
||
<FormControlLabel
|
||
control={
|
||
<Checkbox
|
||
checked={rememberMe}
|
||
onChange={(e) => setRememberMe(e.target.checked)}
|
||
disabled={isLoading}
|
||
/>
|
||
}
|
||
label="Запомнить пароль"
|
||
/>
|
||
<Button
|
||
variant="contained"
|
||
color="primary"
|
||
size="large"
|
||
type="submit"
|
||
disabled={isLoading}
|
||
sx={{
|
||
width: "100%",
|
||
height: "50px",
|
||
position: "relative",
|
||
display: "flex",
|
||
alignItems: "center",
|
||
justifyContent: "center",
|
||
borderRadius: "10px",
|
||
}}
|
||
>
|
||
{isLoading ? <CircularProgress size={24} sx={{}} /> : "Войти"}
|
||
</Button>
|
||
</Box>
|
||
</Paper>
|
||
</Box>
|
||
);
|
||
};
|