Files
fredy/ui/src/views/login/Login.jsx

109 lines
3.0 KiB
React
Raw Normal View History

2025-07-23 08:47:26 +02:00
import React, { useEffect } from 'react';
import cityBackground from '../../assets/city_background.jpg';
import Logo from '../../components/logo/Logo';
2025-07-23 08:47:26 +02:00
import { xhrPost } from '../../services/xhr';
2025-09-02 20:18:37 +02:00
import { useNavigate } from 'react-router-dom';
import { useActions, useSelector } from '../../services/state/store';
import { Input, Button, Banner, Toast } from '@douyinfe/semi-ui';
import './login.less';
2025-07-23 08:47:26 +02:00
import { IconUser, IconLock } from '@douyinfe/semi-icons';
export default function Login() {
const actions = useActions();
2025-07-23 08:47:26 +02:00
const [username, setUserName] = React.useState('');
const [password, setPassword] = React.useState('');
const [error, setError] = React.useState(null);
const demoMode = useSelector((state) => state.demoMode.demoMode || false);
2025-09-02 20:18:37 +02:00
const navigate = useNavigate();
2025-07-23 08:47:26 +02:00
useEffect(() => {
async function init() {
await actions.demoMode.getDemoMode();
2025-07-23 08:47:26 +02:00
}
2025-07-23 08:47:26 +02:00
init();
}, []);
2025-07-23 08:47:26 +02:00
const tryLogin = async () => {
if (!username?.trim() || !password) {
2025-07-23 08:47:26 +02:00
setError('Username and password are mandatory.');
return;
}
setError(null);
2025-07-23 08:47:26 +02:00
try {
await xhrPost('/api/login', {
username: username.trim(),
2025-07-23 08:47:26 +02:00
password,
});
2025-09-03 14:22:04 +02:00
/* eslint-disable no-unused-vars */
} catch (ignored) {
Toast.error('Login unsuccessful…');
2025-07-23 08:47:26 +02:00
return;
}
Toast.success('Login successful!');
await actions.user.getCurrentUser();
2025-09-02 20:18:37 +02:00
navigate('/jobs');
2025-07-23 08:47:26 +02:00
};
2025-07-23 08:47:26 +02:00
return (
<div className="login">
<div className="login__bgImage" style={{ background: `url("${cityBackground}")` }} />
<Logo />
<form>
<div className="login__loginWrapper">
{error && <Banner type="danger" closeIcon={null} description={error} />}
<Input
size="large"
prefix={<IconUser />}
placeholder="Username"
value={username}
showClear
autoFocus
onChange={(value) => setUserName(value)}
onKeyPress={async (e) => {
if (e.key === 'Enter') {
await tryLogin();
}
}}
/>
2025-07-23 08:47:26 +02:00
<Input
size="large"
mode="password"
prefix={<IconLock />}
value={password}
placeholder="Password"
onChange={(value) => setPassword(value)}
onKeyPress={async (e) => {
if (e.key === 'Enter') {
await tryLogin();
}
}}
/>
<Button type="primary" onClick={tryLogin} theme="solid" style={{ marginTop: '1rem' }}>
2025-07-23 08:47:26 +02:00
Login
</Button>
2025-07-23 08:47:26 +02:00
{demoMode && (
<Banner
fullMode={true}
type="info"
bordered
closeIcon={null}
description="This is the demo version of Fredy. Use 'demo' as both the username and password to log in."
/>
)}
</div>
2025-07-23 08:47:26 +02:00
</form>
</div>
);
}
Login.displayName = 'Login';