Files
projet_gestion_commande/frontend-prep/src/pages/LoginPageCabinne/LoginPage.tsx
T

261 lines
8.4 KiB
TypeScript

import { useState } from 'react';
import { Lock, User, Eye, EyeOff, MessageCircle } from 'lucide-react';
import './LoginPage.css';
import { loginAdmin, syncAdminUsernameFromJWT } from '../../api/api_admin';
import { useNavigate } from 'react-router-dom';
interface AdminLoginRequest {
username: string;
password: string;
}
const LoginCabine = () => {
const navigate = useNavigate();
const [formData, setFormData] = useState<AdminLoginRequest>({
username: '',
password: ''
});
const [showPassword, setShowPassword] = useState(false);
const [errors, setErrors] = useState<{ username?: string; password?: string }>({});
const [isLoading, setIsLoading] = useState(false);
const [apiError, setApiError] = useState<string>('');
/**
* ✅ Valider le formulaire
*/
const validateForm = (): boolean => {
const newErrors: { username?: string; password?: string } = {};
console.log('🔍 [ADMIN_LOGIN] Validation - Username:', `"${formData.username}"`);
console.log('🔍 [ADMIN_LOGIN] Après trim:', `"${formData.username.trim()}"`);
if (!formData.username.trim()) {
newErrors.username = 'L\'username admin est requis';
} else if (formData.username.trim().length < 3) {
newErrors.username = 'Username invalide (minimum 3 caractères)';
}
if (!formData.password) {
newErrors.password = 'Le mot de passe est requis';
} else if (formData.password.length < 6) {
newErrors.password = 'Le mot de passe doit contenir au moins 6 caractères';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
/**
* ✅ Soumettre le formulaire
*/
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!validateForm()) return;
setIsLoading(true);
setApiError('');
try {
console.log('🔐 [ADMIN_LOGIN] Appel API avec:', {
username: formData.username,
password: '***'
});
// ✅ Appeler la fonction de login admin sécurisée
const result = await loginAdmin(formData.username, formData.password);
console.log('📋 [ADMIN_LOGIN] Résultat:', {
success: result.success,
message: result.message,
hasToken: !!result.access_token,
role: result.user?.role
});
if (result.success && result.access_token) {
console.log('✅ [ADMIN_LOGIN] Connexion admin réussie!');
// ✅ La synchronisation JWT est AUTOMATIQUE dans loginAdmin()
// Pas besoin de le faire ici
console.log('✅ [ADMIN_LOGIN] Token et username admin synchronisés');
// ✅ Vérifier la synchronisation
const syncedUsername = syncAdminUsernameFromJWT();
console.log('✅ [ADMIN_LOGIN] Username admin synchronisé:', syncedUsername);
// ✅ Redirection vers dashboard admin
console.log('✅ [ADMIN_LOGIN] Redirection vers /admin/dashboard');
navigate('/cabine/dashboard');
} else {
// ❌ Erreur API
const errorMessage = result.message || 'Identifiants admin incorrects';
console.error('❌ [ADMIN_LOGIN] Erreur API:', errorMessage);
setApiError(errorMessage);
setErrors({ username: errorMessage });
}
} catch (err) {
console.error('💥 [ADMIN_LOGIN] Erreur catch:', err);
const errorMessage = err instanceof Error ? err.message : 'Erreur de connexion admin';
setApiError(errorMessage);
setErrors({ username: errorMessage });
} finally {
setIsLoading(false);
}
};
/**
* ✅ Gérer les changements d'input
*/
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
// Effacer l'erreur de ce champ
if (errors[name as keyof typeof errors]) {
setErrors(prev => ({
...prev,
[name]: undefined
}));
}
// Effacer l'erreur API si l'utilisateur recommence à saisir
if (apiError) {
setApiError('');
}
};
return (
<div className="login-container">
<div className="login-content">
<div className="login-header">
<div className="login-logo">
<MessageCircle className="w-8 h-8 text-white" />
</div>
<h1 className="login-title">Connexion cabine</h1>
<p className="login-subtitle">Accédez au panneau cabine</p>
</div>
<div className="login-card">
<form className="login-form" onSubmit={handleSubmit}>
{/* ✅ Erreur API globale */}
{apiError && (
<div className="error-banner" style={{
padding: '12px',
marginBottom: '16px',
backgroundColor: '#fee',
borderLeft: '4px solid #f44',
borderRadius: '4px',
color: '#c33'
}}>
⚠️ {apiError}
</div>
)}
{/* Username Admin */}
<div className="form-group">
<label htmlFor="username" className="form-label">
Username Administrateur
</label>
<div className="input-wrapper">
<User className="input-icon" style={{ width: '20px', height: '20px' }} />
<input
type="text"
id="username"
name="username"
value={formData.username}
onChange={handleChange}
className={`form-input ${errors.username ? 'error' : ''}`}
placeholder="Username admin"
style={{ paddingLeft: '3rem' }}
disabled={isLoading}
autoComplete="username"
/>
</div>
{errors.username && (
<p className="error-message">{errors.username}</p>
)}
</div>
{/* Password */}
<div className="form-group">
<label htmlFor="password" className="form-label">
Mot de passe
</label>
<div className="input-wrapper">
<Lock className="input-icon" style={{ width: '20px', height: '20px' }} />
<input
type={showPassword ? 'text' : 'password'}
id="password"
name="password"
value={formData.password}
onChange={handleChange}
className={`form-input ${errors.password ? 'error' : ''}`}
placeholder="••••••••"
style={{ paddingLeft: '3rem', paddingRight: '3rem' }}
disabled={isLoading}
autoComplete="current-password"
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="password-toggle"
disabled={isLoading}
>
{showPassword ? (
<EyeOff style={{ width: '20px', height: '20px' }} />
) : (
<Eye style={{ width: '20px', height: '20px' }} />
)}
</button>
</div>
{errors.password && (
<p className="error-message">{errors.password}</p>
)}
</div>
{/* Submit Button */}
<button
type="submit"
disabled={isLoading}
className="submit-button"
style={{
opacity: isLoading ? 0.6 : 1,
cursor: isLoading ? 'not-allowed' : 'pointer'
}}
>
{isLoading ? (
<span className="loading-spinner">
Connexion en cours...
</span>
) : (
'Se connecter'
)}
</button>
</form>
{/* Info sécurité */}
<div className="signup-section">
<p className="signup-text" style={{ color: '#9ca3af', fontSize: '0.8rem' }}>
Accès réservé aux administrateurs
</p>
</div>
</div>
{/* Footer */}
<div className="login-footer">
<p>
Besoin d'aide ? Contactez le support technique
</p>
</div>
</div>
</div>
);
};
export default LoginCabine;