import React, { useState, useEffect } from 'react';
import { login, getUserStatus, logout } from '../services/apiService';
const LoginPage = () => {
const [user, setUser] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
// We now look for a 'user_id' in the URL, which is provided by the backend
// after a successful OIDC login and callback.
const params = new URLSearchParams(window.location.search);
const userIdFromUrl = params.get('user_id');
// First, check localStorage for a saved user ID for persistent login
const storedUserId = localStorage.getItem('userId');
const userId = userIdFromUrl || storedUserId;
if (userId) {
setIsLoading(true);
// Fetch the full user details using the user ID from the URL.
// This is a more secure and robust way to handle the final callback.
const fetchUserDetails = async () => {
try {
const userStatus = await getUserStatus(userId);
setUser(userStatus);
// Store the user ID for future requests (e.g., in localStorage)
localStorage.setItem('userId', userStatus.id);
// Clean up the URL by removing the query parameter
window.history.replaceState({}, document.title, window.location.pathname);
} catch (err) {
setError('Failed to get user status. Please try again.');
console.error(err);
} finally {
setIsLoading(false);
}
};
fetchUserDetails();
}
}, []);
const handleLogin = () => {
// Redirect to the backend's /users/login endpoint
// The backend handles the OIDC redirect from there.
login();
};
const handleLogout = async () => {
setIsLoading(true);
try {
await logout();
localStorage.removeItem('userId');
setUser(null);
setError(null);
} catch (err) {
setError('Failed to log out. Please try again.');
console.error(err);
} finally {
setIsLoading(false);
}
};
const renderContent = () => {
if (isLoading) {
return (
<div className="flex items-center justify-center p-4">
<svg className="animate-spin h-5 w-5 mr-3 text-blue-500" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
<span className="text-gray-600 dark:text-gray-400">Processing login...</span>
</div>
);
}
if (error) {
return (
<div className="p-4 bg-red-100 dark:bg-red-900 border border-red-400 dark:border-red-600 rounded-lg text-red-700 dark:text-red-300">
<p className="font-bold">Error:</p>
<p>{error}</p>
</div>
);
}
if (user) {
return (
<div className="p-4 text-green-700 dark:text-green-300 bg-green-100 dark:bg-green-900 border border-green-400 dark:border-green-600 rounded-lg">
<h3 className="text-xl font-bold mb-2">Login Successful!</h3>
<p>Welcome, <span className="font-semibold">{user.email}</span>.</p>
<p>User ID: <span className="font-mono text-sm break-all">{user.id}</span></p>
<button
onClick={handleLogout}
className="mt-4 w-full bg-red-600 hover:bg-red-700 text-white font-bold py-3 px-4 rounded-lg transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-opacity-50"
>
Log Out
</button>
</div>
);
}
return (
<>
<h2 className="text-3xl font-bold mb-4">Login</h2>
<p className="mb-6 text-gray-600 dark:text-gray-400">
Click the button below to log in using OpenID Connect (OIDC).
</p>
<button
onClick={handleLogin}
className="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-4 rounded-lg transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50"
>
Login with OIDC
</button>
</>
);
};
return (
<div className="flex flex-col items-center justify-center h-full min-h-screen bg-gray-100 dark:bg-gray-900 text-gray-900 dark:text-gray-100">
<div className="bg-white dark:bg-gray-800 p-8 rounded-lg shadow-xl text-center max-w-sm w-full">
{renderContent()}
</div>
</div>
);
};
export default LoginPage;