140 lines
3.7 KiB
TypeScript
140 lines
3.7 KiB
TypeScript
import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
|
|
import { Alert } from "@mui/material";
|
|
import Avatar from "@mui/material/Avatar";
|
|
import Box from "@mui/material/Box";
|
|
import Button from "@mui/material/Button";
|
|
import CssBaseline from "@mui/material/CssBaseline";
|
|
import Grid from "@mui/material/Grid";
|
|
import Link from "@mui/material/Link";
|
|
import Paper from "@mui/material/Paper";
|
|
import TextField from "@mui/material/TextField";
|
|
import Typography from "@mui/material/Typography";
|
|
import * as React from "react";
|
|
import { useAlert } from "../hooks/context_providers/AlertDialogProvider";
|
|
import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider";
|
|
import { AuthApi } from "../api/AuthApi";
|
|
|
|
function Copyright(props: any) {
|
|
return (
|
|
<Typography
|
|
variant="body2"
|
|
color="text.secondary"
|
|
align="center"
|
|
{...props}
|
|
>
|
|
{"Copyright © "}
|
|
<Link color="inherit" href="https://0ph.fr/">
|
|
Pierre HUBERT
|
|
</Link>{" "}
|
|
{new Date().getFullYear()}
|
|
{"."}
|
|
</Typography>
|
|
);
|
|
}
|
|
|
|
export function LoginRoute() {
|
|
const loadingMessage = useLoadingMessage();
|
|
|
|
const [user, setUser] = React.useState("");
|
|
const [password, setPassword] = React.useState("");
|
|
|
|
const [error, setError] = React.useState<string | undefined>();
|
|
|
|
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
|
event.preventDefault();
|
|
try {
|
|
loadingMessage.show("Signing in...");
|
|
setError(undefined);
|
|
|
|
await AuthApi.AuthWithPassword(user, password);
|
|
|
|
location.href = "/";
|
|
} catch (e) {
|
|
console.error("Failed to perform login!", e);
|
|
setError(`Failed to authenticate! ${e}`);
|
|
} finally {
|
|
loadingMessage.hide();
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Grid container component="main" sx={{ height: "100vh" }}>
|
|
<CssBaseline />
|
|
<Grid
|
|
item
|
|
xs={false}
|
|
sm={4}
|
|
md={7}
|
|
sx={{
|
|
backgroundImage: 'url("/sun.jpg")',
|
|
backgroundColor: (t) =>
|
|
t.palette.mode === "light"
|
|
? t.palette.grey[50]
|
|
: t.palette.grey[900],
|
|
backgroundSize: "cover",
|
|
backgroundPosition: "left",
|
|
}}
|
|
/>
|
|
<Grid item xs={12} sm={8} md={5} component={Paper} elevation={6} square>
|
|
<Box
|
|
sx={{
|
|
my: 8,
|
|
mx: 4,
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
alignItems: "center",
|
|
}}
|
|
>
|
|
<Avatar sx={{ m: 1, bgcolor: "secondary.main" }}>
|
|
<LockOutlinedIcon />
|
|
</Avatar>
|
|
<Typography component="h1" variant="h5">
|
|
SolarEnergy
|
|
</Typography>
|
|
|
|
{error && <Alert severity="error">{error}</Alert>}
|
|
|
|
<Box
|
|
component="form"
|
|
noValidate
|
|
onSubmit={handleSubmit}
|
|
sx={{ mt: 1 }}
|
|
>
|
|
<TextField
|
|
margin="normal"
|
|
required
|
|
fullWidth
|
|
label="Username"
|
|
autoFocus
|
|
value={user}
|
|
onChange={(v) => setUser(v.target.value)}
|
|
/>
|
|
|
|
<TextField
|
|
margin="normal"
|
|
required
|
|
fullWidth
|
|
label="Password"
|
|
type="password"
|
|
autoComplete="current-password"
|
|
value={password}
|
|
onChange={(v) => setPassword(v.target.value)}
|
|
/>
|
|
|
|
<Button
|
|
type="submit"
|
|
fullWidth
|
|
variant="contained"
|
|
sx={{ mt: 3, mb: 2 }}
|
|
>
|
|
Sign In
|
|
</Button>
|
|
|
|
<Copyright sx={{ mt: 5 }} />
|
|
</Box>
|
|
</Box>
|
|
</Grid>
|
|
</Grid>
|
|
);
|
|
}
|