174 lines
6.0 KiB
JavaScript

import { useState, useEffect } from 'react';
import { PublicClientApplication } from '@azure/msal-browser';
import { msalConfig, loginRequest } from '../msalConfig';
import './Login.css';
function Login({ onLoginSuccess, onSwitchToRegister }) {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const [msalInstance, setMsalInstance] = useState(null);
const [autoLoginAttempted, setAutoLoginAttempted] = useState (false);
useEffect(() => {
const initializeMasal = async () => {
const instance = new PublicClientApplication(msalConfig);
await instance.initialize();
setMsalInstance(instance);
};
initializeMasal();
}, []);
useEffect(() => {
const manualLogout = localStorage.getItem('manualLogout');
if (msalInstance && !autoLoginAttempted && manualLogout !== 'true') {
setAutoLoginAttempted(true);
handleMicrosoftLogin();
}
}, [msalInstance])
const handleSubmit = async (e) => {
e.preventDefault();
setError('');
setLoading(true);
try {
const response = await fetch('http://localhost:9000/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: username,
password: password
})
});
const data = await response.json();
if (response.ok) {
localStorage.removeItem('manualLogout');
onLoginSuccess(data.user, data.token);
} else {
setError(data.error || 'Login failed');
}
} catch (err) {
console.error('Login error:', err);
setError('Failed to connect to server');
} finally {
setLoading(false);
}
};
const handleMicrosoftLogin = async () => {
if (!msalInstance) {
setError('Microsoft login is initializing, please try again');
return;
}
setLoading(true);
setError('');
try {
// Trigger Microsoft login popup - this gets us the access token directly
const loginResponse = await msalInstance.loginPopup(loginRequest);
// Send the access token to your backend
const response = await fetch('http://localhost:9000/api/auth/microsoft', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
accessToken: loginResponse.accessToken,
idToken: loginResponse.idToken
})
});
const data = await response.json();
if (response.ok) {
localStorage.removeItem('manualLogout');
onLoginSuccess(data.user, data.token);
} else {
setError(data.error || 'Microsoft login failed');
}
} catch (err) {
console.error('Microsoft login error:', err);
setError('Failed to login with Microsoft');
} finally {
setLoading(false);
}
};
return (
<div className='login-container'>
<div className='login-box'>
<h2>Login to Knowledge Base</h2>
{error && <div className='error-message'>{error}</div>}
<form onSubmit={handleSubmit}>
<div className='form-group'>
<label htmlFor='username'>Username:</label>
<input
type='text'
id='username'
value={username}
onChange={(e) => setUsername(e.target.value)}
required
disabled={loading}
/>
</div>
<div className='form-group'>
<label htmlFor='password'>Password:</label>
<input
type='password'
id='password'
value={password}
onChange={(e) => setPassword(e.target.value)}
required
disabled={loading}
/>
</div>
<button type='submit' disabled={loading}>
{loading ? 'Logging in...': 'Login'}
</button>
</form>
<div className="divider">
<span>OR</span>
</div>
<button
type="button"
className="microsoft-login-button"
onClick={handleMicrosoftLogin}
disabled={loading}
>
<svg width="21" height="21" viewBox="0 0 21 21" fill="none">
<rect x="1" y="1" width="9" height="9" fill="#f25022"/>
<rect x="1" y="11" width="9" height="9" fill="#00a4ef"/>
<rect x="11" y="1" width="9" height="9" fill="#7fba00"/>
<rect x="11" y="11" width="9" height="9" fill="#ffb900"/>
</svg>
Sign in with Microsoft
</button>
<div className='switch-auth'>
<button
type='button'
className='link-button'
onClick={onSwitchToRegister}
disabled={loading}
>Register here</button>
</div>
</div>
</div>
);
}
export default Login;