diff --git a/src/pages/authentication/auth-forms/AuthLogin.js b/src/pages/authentication/auth-forms/AuthLogin.js
index 55d45a5..2876d1c 100644
--- a/src/pages/authentication/auth-forms/AuthLogin.js
+++ b/src/pages/authentication/auth-forms/AuthLogin.js
@@ -5,7 +5,6 @@ import { useDispatch } from 'react-redux';
// material-ui
import {
Button,
- FormHelperText,
Grid,
InputLabel,
Stack,
@@ -50,142 +49,136 @@ const AuthLogin = () => {
// 2FA States
const [twoFAModalOpen, setTwoFAModalOpen] = useState(false);
- const [twoFAMode, setTwoFAMode] = useState('login'); // 'login' or 'setup'
+ const [twoFAMode, setTwoFAMode] = useState('login');
const [qrUrl, setQrUrl] = useState('');
const [twoFACode, setTwoFACode] = useState('');
const [twoFAError, setTwoFAError] = useState('');
- const [partialToken, setPartialToken] = useState(''); // If backend uses partial session
- const handleClickShowPassword = () => {
- setShowPassword(!showPassword);
- };
-
- const handleMouseDownPassword = (event) => {
- event.preventDefault();
- };
+ const handleClickShowPassword = () => setShowPassword(!showPassword);
+ const handleMouseDownPassword = (event) => event.preventDefault();
const onUserNameChange = (e) => setUserName(e.target.value);
const onPasswordChange = (e) => setUserPassword(e.target.value);
+ // === CENTRALIZED LOGIN & REDIRECT FUNCTION ===
+ const performLoginAndRedirect = async (loginPayload, is2FA = false) => {
+ await dispatch(handleLogin(loginPayload));
+
+ // Determine target path using abilities from payload
+ const abilities = loginPayload.abilities || [];
+ let targetPath = '/client';
+
+ const hasMaintainClient = abilities.some(a => a.startsWith('MAINTAIN') && a.includes('CLIENT'));
+ const hasViewUser = abilities.some(a => a.startsWith('VIEW') && a.includes('USER'));
+
+ if (!is2FA && loginPayload.twoFactorEnabled === false) {
+ targetPath = '/profile';
+ } else if (hasMaintainClient) {
+ targetPath = '/client';
+ } else if (hasViewUser) {
+ targetPath = '/userSearchview';
+ }
+
+ const lastPath = localStorage.getItem('lastVisitedPath');
+ if (lastPath && targetPath === '/client') {
+ targetPath = lastPath;
+ }
+ localStorage.removeItem('lastVisitedPath');
+
+ // Full page redirect to force AbilityProvider to rebuild
+ window.location.href = targetPath;
+ };
+
const tryLogin = () => {
const formErrors = {};
-
if (!userName) formErrors.loginError = 'Username is required.';
if (!userPassword) formErrors.passwordError = 'Password is required.';
-
setErrors(formErrors);
if (Object.keys(formErrors).length === 0) {
axios
- .post(`${apiPath}${LOGIN_PATH}`, {
- username: userName,
- password: userPassword
- })
+ .post(`${apiPath}${LOGIN_PATH}`, { username: userName, password: userPassword })
.then(async (response) => {
const data = response.data;
- // Case 1: 2FA is required
if (data.requires2FA) {
- setPartialToken(data.partialToken || ''); // optional, depending on backend
setTwoFAMode('login');
setTwoFAModalOpen(true);
return;
}
- // Case 2: Login successful (no 2FA or already verified)
if (data.accessToken) {
- const userData = {
+ const loginPayload = {
id: data.id,
fullName: data.name,
email: data.email,
role: data.role,
- abilities: data.abilities,
+ abilities: data.abilities || [],
subDivisionId: data.subDivisionId,
- lotusNotesUser: data.lotusNotesUser
+ lotusNotesUser: data.lotusNotesUser,
+ accessToken: data.accessToken,
+ refreshToken: data.refreshToken,
+ twoFactorEnabled: data.twoFactorEnabled ?? false
};
- await dispatch(handleLogin({ ...userData, accessToken: data.accessToken, refreshToken: data.refreshToken }));
-
- const lastPath = localStorage.getItem('lastVisitedPath');
- navigate(lastPath || '/client');
- window.location.reload();
- localStorage.removeItem('lastVisitedPath');
-
- // Optional: Prompt to setup 2FA if not enabled
- if (!data.twoFactorEnabled) {
- setTimeout(() => {
- if (window.confirm('For extra security, would you like to enable 2FA with Microsoft Authenticator?')) {
- start2FASetup();
- }
- }, 1000);
- }
+ await performLoginAndRedirect(loginPayload);
}
})
.catch((error) => {
- const formErrors = {};
- formErrors.passwordError = error.response?.data?.message || 'Invalid credentials';
- setErrors(formErrors);
+ setErrors({ passwordError: error.response?.data?.message || 'Invalid credentials' });
});
}
};
- const start2FASetup = () => {
- axios
- .post(`${apiPath}/2fa/setup`) // Requires user to be authenticated
- .then((res) => {
- setQrUrl(res.data.otpauthUrl);
- setTwoFAMode('setup');
- setTwoFAModalOpen(true);
- setTwoFAError('');
- })
- .catch((err) => {
- alert('Failed to start 2FA setup: ' + (err.response?.data?.message || err.message));
- });
- };
-
const handle2FASubmit = () => {
if (twoFACode.length !== 6 || !/^\d+$/.test(twoFACode)) {
- setTwoFAError('Please enter a valid 6-digit code');
- return;
+ setTwoFAError('Please enter a valid 6-digit code');
+ return;
}
const endpoint = twoFAMode === 'setup' ? '/2fa/verify-setup' : '/2fa/verify-login';
-
- // Use the actual username from login form, NOT hard-coded '2fi'
- const payload = {
- code: twoFACode,
- username: userName // ← This is your state from
- };
+ const payload = { code: twoFACode, username: userName };
axios
- .post(`${apiPath}${endpoint}`, payload)
- .then(async (res) => {
+ .post(`${apiPath}${endpoint}`, payload)
+ .then(async (res) => {
+ const data = res.data;
+
if (twoFAMode === 'setup') {
- alert('2FA enabled!');
- setTwoFAModalOpen(false);
- } else {
- // Full login - use the exact same structure as normal login
- await dispatch(handleLogin(res.data)); // res.data should be JwtResponse
- setTwoFAModalOpen(false);
- const lastPath = localStorage.getItem('lastVisitedPath');
- navigate(lastPath || '/client');
- window.location.reload();
+ alert('2FA enabled!');
+ setTwoFAModalOpen(false);
+ return;
}
+
+ const loginPayload = {
+ id: data.id,
+ fullName: data.name,
+ email: data.email,
+ role: data.role,
+ abilities: data.abilities || [],
+ subDivisionId: data.subDivisionId || null,
+ lotusNotesUser: data.lotusNotesUser || null,
+ accessToken: data.accessToken,
+ refreshToken: data.refreshToken,
+ twoFactorEnabled: true
+ };
+
+ await performLoginAndRedirect(loginPayload, true);
+
+ setTwoFAModalOpen(false);
setTwoFACode('');
- })
- .catch((err) => {
- setTwoFAError(err.response?.data?.message || 'Invalid or expired code');
- });
- };
+ setTwoFAError('');
+ })
+ .catch((err) => {
+ console.error('2FA verification failed:', err);
+ setTwoFAError(err.response?.data?.message || 'Invalid or expired code');
+ });
+ };
return (
<>
{
User Name
{
id="password-login"
type={showPassword ? 'text' : 'password'}
value={userPassword}
- name="password"
onBlur={handleBlur}
onChange={onPasswordChange}
InputProps={{
endAdornment: (
{
)}
- {/* 2FA Modal */}