131 lines
4.1 KiB
React
131 lines
4.1 KiB
React
import { useContext, useEffect, useState } from 'react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { ROLES, SERVER_URL } from '../../constants.js';
|
|
import { fetchData } from '../../fetching/Fetch.js';
|
|
import { UserContext } from '../../context/UserContext.jsx';
|
|
import { clearSession, getToken, setSession } from '../../utils/session.js';
|
|
import './LoginPage.css';
|
|
|
|
const TELLER_ROLES = [
|
|
ROLES.ROLE_USER,
|
|
ROLES.ROLE_SUPER_ADMIN,
|
|
ROLES.ROLE_BRANCH_ADMIN,
|
|
];
|
|
|
|
function canAccessTellerApp(userData) {
|
|
const roles = Array.isArray(userData?.roles) ? userData.roles : [];
|
|
return roles.some((role) => TELLER_ROLES.includes(role));
|
|
}
|
|
|
|
export default function LoginPage() {
|
|
const navigate = useNavigate();
|
|
const { user, setUser } = useContext(UserContext);
|
|
|
|
const [email, setEmail] = useState('');
|
|
const [password, setPassword] = useState('');
|
|
const [error, setError] = useState('');
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (user && getToken()) {
|
|
navigate('/', { replace: true });
|
|
}
|
|
}, [user, navigate]);
|
|
|
|
async function handleSubmit(event) {
|
|
event.preventDefault();
|
|
|
|
if (!email.trim()) {
|
|
setError('Email is required.');
|
|
return;
|
|
}
|
|
|
|
if (!password.trim()) {
|
|
setError('Password is required.');
|
|
return;
|
|
}
|
|
|
|
setLoading(true);
|
|
setError('');
|
|
|
|
try {
|
|
const { data, success } = await fetchData(`${SERVER_URL}/api/v1/auth/login`, 'POST', {
|
|
email: email.trim(),
|
|
password: password.trim(),
|
|
});
|
|
|
|
if (!success || !data) {
|
|
setError('Your credentials are incorrect.');
|
|
return;
|
|
}
|
|
|
|
const userData = data.userData ?? data;
|
|
const token = data.token;
|
|
|
|
if (!canAccessTellerApp(userData)) {
|
|
clearSession();
|
|
setUser(null);
|
|
setError('This account cannot access the teller app.');
|
|
return;
|
|
}
|
|
|
|
if (!token) {
|
|
setError('Two-factor login is not supported in the teller app yet. Disable 2FA for this account or use an account without 2FA.');
|
|
return;
|
|
}
|
|
|
|
if (!userData?.tenantCode) {
|
|
setError('Login succeeded but tenant information is missing.');
|
|
return;
|
|
}
|
|
|
|
setSession({ userData, token });
|
|
setUser(userData);
|
|
navigate('/', { replace: true });
|
|
} catch (err) {
|
|
console.error(err);
|
|
setError('An error occurred. Please try again.');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div id="teller-login-form">
|
|
<h1>Teller Login</h1>
|
|
<form onSubmit={handleSubmit}>
|
|
<div className="form-group">
|
|
<label htmlFor="email">Email</label>
|
|
<input
|
|
id="email"
|
|
type="email"
|
|
value={email}
|
|
autoComplete="username"
|
|
onChange={(event) => {
|
|
setEmail(event.target.value);
|
|
setError('');
|
|
}}
|
|
/>
|
|
</div>
|
|
<div className="form-group">
|
|
<label htmlFor="password">Password</label>
|
|
<input
|
|
id="password"
|
|
type="password"
|
|
value={password}
|
|
autoComplete="current-password"
|
|
onChange={(event) => {
|
|
setPassword(event.target.value);
|
|
setError('');
|
|
}}
|
|
/>
|
|
</div>
|
|
{error ? <p className="error">{error}</p> : null}
|
|
<button type="submit" disabled={loading}>
|
|
{loading ? 'Signing in…' : 'Sign in'}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
);
|
|
}
|