Ajout page login non fonctionnelle
This commit is contained in:
@@ -1,12 +1,71 @@
|
||||
import React from 'react';
|
||||
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
|
||||
import { AuthProvider, useAuth } from './context/AuthContext';
|
||||
import Login from './components/Login';
|
||||
import RHDashboard from './components/RHDashboard';
|
||||
|
||||
// Composant pour protéger les routes
|
||||
const ProtectedRoute = ({ children }) => {
|
||||
const { isAuthorized } = useAuth();
|
||||
|
||||
return isAuthorized ? children : <Navigate to="/login" replace />;
|
||||
};
|
||||
|
||||
// Composant pour rediriger si déjà connecté
|
||||
const PublicRoute = ({ children }) => {
|
||||
const { isAuthorized } = useAuth();
|
||||
|
||||
return !isAuthorized ? children : <Navigate to="/dashboard" replace />;
|
||||
};
|
||||
|
||||
function AppContent() {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50">
|
||||
<Routes>
|
||||
{/* Route de login - accessible seulement si non connecté */}
|
||||
<Route
|
||||
path="/login"
|
||||
element={
|
||||
<PublicRoute>
|
||||
<Login />
|
||||
</PublicRoute>
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Route du dashboard - accessible seulement si connecté */}
|
||||
<Route
|
||||
path="/dashboard"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<RHDashboard />
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Route par défaut - redirige vers login ou dashboard selon l'état */}
|
||||
<Route
|
||||
path="/"
|
||||
element={<Navigate to="/login" replace />}
|
||||
/>
|
||||
|
||||
{/* Route catch-all pour les URLs non trouvées */}
|
||||
<Route
|
||||
path="*"
|
||||
element={<Navigate to="/login" replace />}
|
||||
/>
|
||||
</Routes>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50">
|
||||
<RHDashboard />
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<AuthProvider>
|
||||
<Router>
|
||||
<AppContent />
|
||||
</Router>
|
||||
</AuthProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
129
GTFRRH/project/src/components/Login.tsx
Normal file
129
GTFRRH/project/src/components/Login.tsx
Normal file
@@ -0,0 +1,129 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { AlertTriangle, Users } from 'lucide-react';
|
||||
|
||||
const Login = () => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
const navigate = useNavigate();
|
||||
const { loginWithO365, isAuthorized } = useAuth();
|
||||
|
||||
// Redirection si déjà connecté
|
||||
useEffect(() => {
|
||||
if (isAuthorized) {
|
||||
navigate('/dashboard');
|
||||
}
|
||||
}, [isAuthorized]);
|
||||
|
||||
const handleO365Login = async () => {
|
||||
setIsLoading(true);
|
||||
setError('');
|
||||
|
||||
try {
|
||||
const success = await loginWithO365();
|
||||
|
||||
if (!success) {
|
||||
setError("Erreur lors de la connexion Office 365");
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Récupération du token
|
||||
const token = localStorage.getItem("o365_token");
|
||||
|
||||
// Simulation synchronisation groupes
|
||||
const data = { success: true };
|
||||
console.log("Résultat syncGroups :", data);
|
||||
|
||||
if (!data.success) {
|
||||
setError("Erreur de synchronisation des groupes : " + data.message);
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Redirection vers dashboard
|
||||
navigate('/dashboard');
|
||||
|
||||
} catch (err) {
|
||||
console.error('Erreur O365:', err);
|
||||
|
||||
if (err.message?.includes('non autorisé') || err.message?.includes('Accès refusé')) {
|
||||
setError('Accès refusé : Vous devez être membre d\'un groupe autorisé dans votre organisation.');
|
||||
} else if (err.message?.includes('AADSTS')) {
|
||||
setError('Erreur d\'authentification Azure AD. Contactez votre administrateur.');
|
||||
} else {
|
||||
setError(err.message || "Erreur lors de la connexion Office 365");
|
||||
}
|
||||
}
|
||||
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-100 flex items-center justify-center p-4">
|
||||
<div className="max-w-md w-full">
|
||||
<div className="bg-white rounded-lg shadow-md p-8">
|
||||
|
||||
{/* En-tête */}
|
||||
<div className="text-center mb-8">
|
||||
<div className="w-16 h-16 bg-[#7e5aa2] rounded-lg flex items-center justify-center mx-auto mb-4">
|
||||
<Users className="w-8 h-8 text-white" />
|
||||
</div>
|
||||
<h1 className="text-2xl font-bold text-gray-900 mb-2">GTF - Espace RH</h1>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Bouton de connexion Office 365 */}
|
||||
<button
|
||||
onClick={handleO365Login}
|
||||
disabled={isLoading}
|
||||
className="w-full bg-[#7e5aa2] hover:bg-[#6d4a91] text-white py-3 px-4 rounded-lg font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center space-x-2"
|
||||
>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin"></div>
|
||||
<span>Connexion...</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M23.5 12c0-.813-.069-1.613-.2-2.4H12v4.54h6.458c-.28 1.488-1.13 2.75-2.41 3.6v2.988h3.908c2.28-2.1 3.594-5.194 3.594-8.728z" />
|
||||
<path d="M12 24c3.24 0 5.956-1.075 7.944-2.906l-3.908-2.988c-1.075.725-2.456 1.156-4.036 1.156-3.106 0-5.744-2.1-6.681-4.919H1.294v3.081C3.281 21.394 7.344 24 12 24z" />
|
||||
<path d="M5.319 14.343c-.238-.725-.375-1.494-.375-2.343s.138-1.619.375-2.344V6.575H1.294C.469 8.225 0 10.044 0 12s.469 3.775 1.294 5.425l4.025-3.082z" />
|
||||
<path d="M12 4.781c1.75 0 3.319.6 4.556 1.781l3.419-3.419C17.944 1.194 15.231 0 12 0 7.344 0 3.281 2.606 1.294 6.575l4.025 3.081C6.256 6.881 8.894 4.781 12 4.781z" />
|
||||
</svg>
|
||||
<span>Se connecter avec Office 365</span>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
|
||||
{/* Message d'erreur */}
|
||||
{error && (
|
||||
<div className="mt-6 p-4 bg-red-50 border border-red-200 rounded-lg">
|
||||
<div className="flex items-start space-x-2">
|
||||
<AlertTriangle className="w-5 h-5 text-red-500 flex-shrink-0 mt-0.5" />
|
||||
<div>
|
||||
<p className="text-red-800 font-medium text-sm">
|
||||
{error.includes('Accès refusé') ? 'Accès refusé' : 'Erreur de connexion'}
|
||||
</p>
|
||||
<p className="text-red-700 text-xs mt-1">{error}</p>
|
||||
{error.includes('groupe autorisé') && (
|
||||
<p className="text-red-700 text-xs mt-2">
|
||||
Contactez votre administrateur pour être ajouté aux groupes appropriés.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Note */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Login;
|
||||
File diff suppressed because it is too large
Load Diff
120
GTFRRH/project/src/context/AuthContext.tsx
Normal file
120
GTFRRH/project/src/context/AuthContext.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
import React, { createContext, useContext, useState, useEffect } from 'react';
|
||||
|
||||
const AuthContext = createContext();
|
||||
|
||||
export const useAuth = () => {
|
||||
const context = useContext(AuthContext);
|
||||
if (!context) {
|
||||
throw new Error('useAuth must be used within an AuthProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
export const AuthProvider = ({ children }) => {
|
||||
const [isAuthorized, setIsAuthorized] = useState(false);
|
||||
const [user, setUser] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
// Vérifier l'état d'authentification au chargement
|
||||
useEffect(() => {
|
||||
const token = localStorage.getItem('token') || localStorage.getItem('o365_token');
|
||||
const userData = localStorage.getItem('user');
|
||||
|
||||
if (token && userData) {
|
||||
setUser(JSON.parse(userData));
|
||||
setIsAuthorized(true);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
}, []);
|
||||
|
||||
// Connexion classique (email/password)
|
||||
const login = async (email, password) => {
|
||||
try {
|
||||
const response = await fetch('http://localhost:3002/api/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ email, password }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Identifiants incorrects');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
localStorage.setItem('token', data.token);
|
||||
localStorage.setItem('user', JSON.stringify(data.user));
|
||||
|
||||
setUser(data.user);
|
||||
setIsAuthorized(true);
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Erreur de connexion:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Connexion Office 365
|
||||
const loginWithO365 = async () => {
|
||||
try {
|
||||
// Simuler l'authentification Office 365
|
||||
// Remplacez cette partie par votre vraie logique O365
|
||||
const mockUser = {
|
||||
id: '1',
|
||||
email: 'user@office365.com',
|
||||
name: 'Utilisateur O365',
|
||||
role: 'rh'
|
||||
};
|
||||
|
||||
const mockToken = 'mock-o365-token';
|
||||
|
||||
localStorage.setItem('o365_token', mockToken);
|
||||
localStorage.setItem('user', JSON.stringify(mockUser));
|
||||
|
||||
setUser(mockUser);
|
||||
setIsAuthorized(true);
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Erreur connexion O365:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Déconnexion
|
||||
const logout = () => {
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('o365_token');
|
||||
localStorage.removeItem('user');
|
||||
|
||||
setUser(null);
|
||||
setIsAuthorized(false);
|
||||
};
|
||||
|
||||
const value = {
|
||||
isAuthorized,
|
||||
user,
|
||||
login,
|
||||
loginWithO365,
|
||||
logout,
|
||||
loading
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={value}>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user