mirror of
https://github.com/arcan1s/ahriman.git
synced 2026-04-07 11:03:37 +00:00
99 lines
3.8 KiB
TypeScript
99 lines
3.8 KiB
TypeScript
import React, { useCallback, useState } from "react";
|
|
import {
|
|
Dialog, DialogContent, DialogActions, Button, TextField,
|
|
InputAdornment, IconButton,
|
|
} from "@mui/material";
|
|
import DialogHeader from "components/common/DialogHeader";
|
|
import VisibilityIcon from "@mui/icons-material/Visibility";
|
|
import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
|
|
import PersonIcon from "@mui/icons-material/Person";
|
|
import { useAuth } from "hooks/useAuth";
|
|
import { useNotification } from "hooks/useNotification";
|
|
import { useDialogClose } from "hooks/useDialogClose";
|
|
import { ApiError } from "api/client/ApiError";
|
|
|
|
interface LoginDialogProps {
|
|
open: boolean;
|
|
onClose: () => void;
|
|
}
|
|
|
|
export default function LoginDialog({ open, onClose }: LoginDialogProps): React.JSX.Element {
|
|
const [username, setUsername] = useState("");
|
|
const [password, setPassword] = useState("");
|
|
const [showPassword, setShowPassword] = useState(false);
|
|
const { login } = useAuth();
|
|
const { showSuccess, showError } = useNotification();
|
|
|
|
const onOpen = useCallback(() => {
|
|
setUsername("");
|
|
setPassword("");
|
|
setShowPassword(false);
|
|
}, []);
|
|
|
|
const { isOpen, requestClose, transitionProps } = useDialogClose(open, onClose, onOpen);
|
|
|
|
const handleSubmit = async (): Promise<void> => {
|
|
if (!username || !password) {
|
|
return;
|
|
}
|
|
try {
|
|
await login(username, password);
|
|
requestClose();
|
|
showSuccess("Logged in", `Successfully logged in as ${username}`);
|
|
window.location.reload();
|
|
} catch (e) {
|
|
const detail = ApiError.errorDetail(e);
|
|
if (username === "admin" && password === "admin") {
|
|
showError("Login error", "You've entered a password for user \"root\", did you make a typo in username?");
|
|
} else {
|
|
showError("Login error", `Could not login as ${username}: ${detail}`);
|
|
}
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Dialog open={isOpen} onClose={requestClose} maxWidth="xs" fullWidth slotProps={{ transition: transitionProps }}>
|
|
<DialogHeader onClose={requestClose}>
|
|
Login
|
|
</DialogHeader>
|
|
<DialogContent>
|
|
<TextField
|
|
label="username"
|
|
fullWidth
|
|
margin="normal"
|
|
value={username}
|
|
onChange={(e) => setUsername(e.target.value)}
|
|
autoFocus
|
|
/>
|
|
<TextField
|
|
label="password"
|
|
fullWidth
|
|
margin="normal"
|
|
type={showPassword ? "text" : "password"}
|
|
value={password}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
onKeyDown={(e) => {
|
|
if (e.key === "Enter") {
|
|
void handleSubmit();
|
|
}
|
|
}}
|
|
slotProps={{
|
|
input: {
|
|
endAdornment: (
|
|
<InputAdornment position="end">
|
|
<IconButton aria-label={showPassword ? "Hide password" : "Show password"} onClick={() => setShowPassword(!showPassword)} edge="end" size="small">
|
|
{showPassword ? <VisibilityOffIcon /> : <VisibilityIcon />}
|
|
</IconButton>
|
|
</InputAdornment>
|
|
),
|
|
},
|
|
}}
|
|
/>
|
|
</DialogContent>
|
|
<DialogActions>
|
|
<Button onClick={() => void handleSubmit()} variant="contained" startIcon={<PersonIcon />}>login</Button>
|
|
</DialogActions>
|
|
</Dialog>
|
|
);
|
|
}
|