198 lines
7.2 KiB
JavaScript

import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../../contexts/AuthContext';
import axios from 'axios';
export default function Login() {
const [email, setEmail] = useState(''); // Remove pre-filled email
const [password, setPassword] = useState(''); // Remove pre-filled password
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const [authState, setAuthState] = useState({
hasToken: false,
hasUser: false,
tokenValue: null,
userValue: null
});
const navigate = useNavigate();
const { login, currentUser } = useAuth();
// Check and display current auth state for debugging
useEffect(() => {
const token = localStorage.getItem('token');
const user = localStorage.getItem('user');
try {
setAuthState({
hasToken: !!token,
hasUser: !!user,
tokenValue: token ? `${token.substring(0, 10)}...` : null,
userValue: user ? JSON.parse(user) : null
});
console.log('Login page loaded with auth state:', {
hasToken: !!token,
hasUser: !!user,
currentUser
});
} catch (error) {
console.error('Error parsing user data:', error);
}
}, [currentUser]);
const handleSubmit = async (e) => {
e.preventDefault();
try {
setError('');
setLoading(true);
console.log('Attempting login with:', { email, password: '***' });
// Try direct API call first
try {
const response = await axios.post('/api/auth/login', { email, password });
console.log('Login response:', response.data);
// Check if the response has the expected structure
if (response.data && response.data.success === true) {
const { token, user } = response.data;
console.log('Extracted token and user:', { tokenExists: !!token, user });
// Save token to localStorage
localStorage.setItem('token', token);
// Set axios default headers for future requests
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
// Update auth context manually
localStorage.setItem('user', JSON.stringify(user));
console.log('Login successful, redirecting based on role:', user.role);
// Force reload to ensure auth context is properly updated
window.location.href = '/dashboard';
return;
} else {
console.error('Unexpected response structure:', response.data);
throw new Error('Invalid response structure from server');
}
} catch (directApiError) {
console.error('Direct API call failed:', directApiError);
console.error('Error details:', directApiError.response ? directApiError.response.data : 'No response data');
// If the error is a 401, show appropriate message
if (directApiError.response?.status === 401) {
setError('Invalid email or password');
return;
}
throw directApiError;
}
} catch (error) {
setError('Failed to log in. Please check your credentials.');
console.error('Login error:', error);
} finally {
setLoading(false);
}
};
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-blue-50 via-white to-purple-50 py-12 px-4 sm:px-6 lg:px-8">
<div className="max-w-md w-full space-y-8 animate-fadeIn">
{/* Logo and Title */}
<div className="text-center">
<div className="mx-auto h-20 w-20 bg-gradient-to-br from-blue-600 to-purple-600 rounded-2xl flex items-center justify-center shadow-2xl">
<span className="text-white text-3xl font-bold">II</span>
</div>
<h2 className="mt-6 text-4xl font-extrabold text-gray-900 tracking-tight">
InInventer
</h2>
<p className="mt-2 text-base text-gray-600">
Sign in to manage your inventory
</p>
</div>
{/* Login Form */}
<div className="mt-8 bg-white rounded-2xl shadow-2xl overflow-hidden">
<div className="px-8 py-10">
{error && (
<div className="alert alert-error mb-6 animate-fadeIn">
<svg className="w-5 h-5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" />
</svg>
<span>{error}</span>
</div>
)}
<form className="space-y-6" onSubmit={handleSubmit}>
<div>
<label htmlFor="email" className="form-label">
Email address
</label>
<input
id="email"
name="email"
type="email"
autoComplete="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
className="form-input"
placeholder="Enter your email"
/>
</div>
<div>
<label htmlFor="password" className="form-label">
Password
</label>
<input
id="password"
name="password"
type="password"
autoComplete="current-password"
required
value={password}
onChange={(e) => setPassword(e.target.value)}
className="form-input"
placeholder="Enter your password"
/>
</div>
<div>
<button
type="submit"
disabled={loading}
className="w-full btn btn-primary text-base py-3"
>
{loading ? (
<div className="flex items-center justify-center">
<svg className="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" 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>
Signing in...
</div>
) : (
'Sign in'
)}
</button>
</div>
</form>
</div>
{/* Footer */}
<div className="px-8 py-4 bg-gray-50 border-t border-gray-100">
<p className="text-xs text-center text-gray-500">
© 2025 InInventer. All rights reserved.
</p>
</div>
</div>
</div>
</div>
);
}