2025-03-04 03:38:50 +08:00
|
|
|
import React, { useEffect, useState } from 'react';
|
|
|
|
import { useDispatch, useSelector } from 'react-redux';
|
|
|
|
import { Link, useNavigate } from 'react-router-dom';
|
|
|
|
import { checkAuthThunk, loginThunk } from '../../store/auth/auth.thunk';
|
|
|
|
|
|
|
|
export default function Login() {
|
|
|
|
const dispatch = useDispatch();
|
|
|
|
const navigate = useNavigate();
|
2025-03-04 07:22:05 +08:00
|
|
|
const [username, setUsername] = useState('member2');
|
|
|
|
const [password, setPassword] = useState('member123');
|
2025-03-04 03:38:50 +08:00
|
|
|
const [errors, setErrors] = useState({});
|
|
|
|
const [submitted, setSubmitted] = useState(false);
|
|
|
|
|
|
|
|
const { user } = useSelector((state) => state.auth);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
handleCheckAuth();
|
|
|
|
}, [dispatch]);
|
|
|
|
|
|
|
|
const handleCheckAuth = async () => {
|
2025-03-04 07:22:05 +08:00
|
|
|
console.log('login page handleCheckAuth');
|
|
|
|
try {
|
|
|
|
await dispatch(checkAuthThunk()).unwrap();
|
|
|
|
if (user) navigate('/');
|
|
|
|
} catch (error) {}
|
2025-03-04 03:38:50 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
const validateForm = () => {
|
|
|
|
const newErrors = {};
|
|
|
|
if (!username) {
|
|
|
|
newErrors.username = 'Username is required';
|
|
|
|
}
|
|
|
|
if (!password) {
|
|
|
|
newErrors.password = 'Password is required';
|
|
|
|
} else if (password.length < 6) {
|
|
|
|
newErrors.password = 'Password must be at least 6 characters';
|
|
|
|
}
|
|
|
|
setErrors(newErrors);
|
|
|
|
return Object.keys(newErrors).length === 0;
|
|
|
|
};
|
|
|
|
|
2025-03-04 07:22:05 +08:00
|
|
|
const handleSubmit = async (e) => {
|
2025-03-04 03:38:50 +08:00
|
|
|
e.preventDefault();
|
|
|
|
setSubmitted(true);
|
|
|
|
|
|
|
|
if (validateForm()) {
|
|
|
|
console.log('Form submitted successfully!');
|
|
|
|
console.log('Username:', username);
|
|
|
|
console.log('Password:', password);
|
2025-03-04 07:22:05 +08:00
|
|
|
try {
|
|
|
|
await dispatch(loginThunk({ username, password })).unwrap();
|
|
|
|
navigate('/');
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Login failed:', error);
|
|
|
|
}
|
2025-03-04 03:38:50 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
return (
|
|
|
|
<div className='position-absolute top-50 start-50 translate-middle d-flex flex-column gap-4 align-items-center'>
|
|
|
|
<div className='title text-center h1'>OOIN 智能知识库</div>
|
|
|
|
<form
|
|
|
|
className='auth-form login-form d-flex flex-column gap-3 align-items-center'
|
|
|
|
onSubmit={handleSubmit}
|
|
|
|
noValidate
|
|
|
|
>
|
|
|
|
<div className='input-group has-validation'>
|
|
|
|
<input
|
2025-03-04 07:22:05 +08:00
|
|
|
value={username}
|
2025-03-04 03:38:50 +08:00
|
|
|
type='text'
|
|
|
|
className={`form-control form-control-lg${submitted && errors.username ? ' is-invalid' : ''}`}
|
|
|
|
id='username'
|
|
|
|
placeholder='Username'
|
|
|
|
required
|
|
|
|
onChange={(e) => setUsername(e.target.value.trim())}
|
|
|
|
></input>
|
|
|
|
{submitted && errors.username && <div className='invalid-feedback'>{errors.username}</div>}
|
|
|
|
</div>
|
|
|
|
<div className='input-group has-validation'>
|
|
|
|
<input
|
2025-03-04 07:22:05 +08:00
|
|
|
value={password}
|
2025-03-04 03:38:50 +08:00
|
|
|
type='password'
|
|
|
|
id='password'
|
|
|
|
placeholder='Password'
|
|
|
|
required
|
|
|
|
className={`form-control form-control-lg${submitted && errors.password ? ' is-invalid' : ''}`}
|
|
|
|
aria-describedby='passwordHelpBlock'
|
|
|
|
onChange={(e) => setPassword(e.target.value.trim())}
|
|
|
|
></input>
|
|
|
|
{submitted && errors.password && <div className='invalid-feedback'>{errors.password}</div>}
|
|
|
|
</div>
|
|
|
|
<Link to='#' className='find-password text-body-secondary'>
|
|
|
|
Forgot password?
|
|
|
|
</Link>
|
|
|
|
<button type='submit' className='btn btn-dark btn-lg w-100'>
|
|
|
|
Login
|
|
|
|
</button>
|
|
|
|
</form>
|
|
|
|
<Link to='/signup' className='go-to-signup w-100 link-underline-light h5 text-center'>
|
|
|
|
Need Account?
|
|
|
|
</Link>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|