Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions AdminDashboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import logo from './assets/logo-tecpap.png';

function AdminDashboard({ onLogout }) {
return (
<div className="auth-container">
<div className="auth-box admin-box">
<div className="dashboard-header">
<img src={logo} alt="Logo de TECPAP" className="logo" />
<button
onClick={onLogout}
className="logout-btn"
aria-label="Se déconnecter de l'application" // Améliore l'accessibilité
>
Se déconnecter
</button>
</div>

<h2>🎛️ Tableau de bord Administrateur</h2>
<p className="dashboard-subtitle">Bienvenue dans l’espace admin. Vous avez un accès complet à la gestion des utilisateurs, des documents BAT, et à la traçabilité.</p>

{/* Vous pouvez ajouter plus de fonctionnalités ou liens vers différentes sections du tableau de bord */}
<div className="admin-functions">
<ul>
<li><button>Gérer les utilisateurs</button></li>
<li><button>Voir les documents BAT</button></li>
<li><button>Suivi de la traçabilité</button></li>
</ul>
</div>
</div>
</div>
);
}

export default AdminDashboard;
184 changes: 184 additions & 0 deletions App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
:root {
--primary-color: #218838;
--primary-dark-color: #1a6e2b;
--secondary-color: #007BFF;
--secondary-dark-color: #0056b3;
--danger-color: #dc3545;
}

body {
margin: 0;
font-family: Arial, sans-serif;
background:
linear-gradient(rgba(0,0,0,0.3), rgba(0,0,0,0.3)),
url('./assets/slider-1.jpg'); /* Fixed path */
background-size: cover;
background-position: center;
background-attachment: fixed;
}

.auth-container {
display: flex;
justify-content: center;
align-items: flex-start;
min-height: 100vh;
padding: 40px 20px;
overflow-y: auto;
box-sizing: border-box;
}

.auth-box {
background:
linear-gradient(rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.3)),
url('./assets/slider-1.jpg'); /* Already correct */
background-size: cover;
background-position: center;
background-attachment: fixed;
font-family: 'Segoe UI', Tahoma, sans-serif;
}

.auth-box form {
display: flex;
flex-direction: column;
gap: 15px;
text-align: left;
}

input,
select,
button {
padding: 12px;
border-radius: 6px;
border: 1px solid #ccc;
transition: background-color 0.3s ease-in-out, transform 0.2s ease-in-out;
}

button {
background: var(--primary-color);
color: white;
cursor: pointer;
}

button:hover {
background: var(--primary-dark-color);
transform: scale(1.05);
}

.error-message {
color: #dc3545;
font-size: 0.9em;
font-weight: bold;
margin-top: 10px;
padding: 8px;
background: #f8d7da;
border: 1px solid #f5c6cb;
border-radius: 5px;
}

/* Responsive Design */
@media (max-width: 768px) {
.auth-box {
padding: 30px 20px;
max-width: 100%;
}

.form-grid {
grid-template-columns: 1fr;
}

.form-grid label,
.form-grid input,
.form-grid select {
grid-column: 1;
}
}

@media (max-width: 480px) {
.auth-box {
padding: 20px;
}

.form-grid {
grid-template-columns: 1fr;
}

.form-grid label,
.form-grid input,
.form-grid select {
grid-column: 1;
}
}

.error-message {
color: #dc3545;
background-color: #f8d7da;
padding: 10px;
border-radius: 5px;
margin-bottom: 20px;
}

.success-message {
color: green;
font-weight: bold;
margin-top: 10px;
}

.admin-box {
padding: 20px;
background-color: #f4f7fb;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

.dashboard-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}

.dashboard-header .logo {
width: 120px;
}

.dashboard-subtitle {
font-size: 1.2em;
color: #333;
margin-top: 15px;
}

.admin-functions ul {
list-style-type: none;
padding: 0;
}

.admin-functions li {
margin: 10px 0;
}

.admin-functions button {
padding: 10px 20px;
background-color: #218838;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background 0.3s;
}

.admin-functions button:hover {
background-color: #1a6e2b;
}

.logout-btn {
padding: 8px 15px;
background-color: #dc3545;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}

.logout-btn:hover {
background-color: #c82333;
}
97 changes: 97 additions & 0 deletions App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React, { useState } from 'react';
import './App.css';
import logo from './assets/logo-tecpap.png';
import sliderImage from './assets/slider-1.jpg'; // Ajout de l'import
import { auth, db } from './firebase-config';
import { signInWithEmailAndPassword, signOut } from 'firebase/auth';
import { doc, getDoc } from 'firebase/firestore';
import Login from './login';
import AdminDashboard from './AdminDashboard';
import QualiteDashboard from './QualiteDashboard';
import OperateurDashboard from './OperateurDashboard';

function App() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [role, setRole] = useState('');

const handleLogin = async (e) => {
e.preventDefault();
try {
const userCredential = await signInWithEmailAndPassword(auth, email, password);
const uid = userCredential.user.uid;

const userDoc = await getDoc(doc(db, 'users', uid));
if (userDoc.exists()) {
const userData = userDoc.data();
setRole(userData.role);
setIsLoggedIn(true);
} else {
alert("Aucun rôle trouvé pour cet utilisateur.");
}
} catch (error) {
alert(error.code === 'auth/user-not-found' ? "Utilisateur non trouvé" : "Erreur de connexion : " + error.message);
}
};

const handleLogout = async () => {
try {
await signOut(auth);
setEmail('');
setPassword('');
setIsLoggedIn(false);
setRole('');
} catch (error) {
alert("Erreur lors de la déconnexion : " + error.message);
}
};

if (isLoggedIn) {
return (
<div className="auth-container" style={{ backgroundImage: `linear-gradient(rgba(0,0,0,0.3), rgba(0,0,0,0.3)), url(${sliderImage})` }}>
{role === 'admin' && <AdminDashboard onLogout={handleLogout} />}
{role === 'qualite' && <QualiteDashboard onLogout={handleLogout} />}
{role === 'operateur' && <OperateurDashboard onLogout={handleLogout} />}
{!['admin', 'qualite', 'operateur'].includes(role) && (
<div className="auth-box" style={{ backgroundImage: `linear-gradient(rgba(0,0,0,0.3), rgba(0,0,0,0.3)), url(${sliderImage})` }}>
<img src={logo} alt="TECPAP Logo" className="logo" />
<h2>Rôle inconnu</h2>
<p>Ce rôle n’est pas reconnu.</p>
<button onClick={handleLogout}>Se déconnecter</button>
</div>
)}
</div>
);
}

return (
<div className="auth-container" style={{ backgroundImage: `linear-gradient(rgba(0,0,0,0.3), rgba(0,0,0,0.3)), url(${sliderImage})` }}>
<div className="auth-box" style={{ backgroundImage: `linear-gradient(rgba(0,0,0,0.3), rgba(0,0,0,0.3)), url(${sliderImage})` }}>
<img src={logo} alt="TECPAP Logo" className="logo" />
<h2>Connexion sécurisée</h2>
<form onSubmit={handleLogin}>
<label>Email professionnel</label>
<input
type="email"
placeholder="prenom.nom@tecpap.ma"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
<label>Mot de passe</label>
<input
type="password"
placeholder="••••••••"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
<button type="submit">Se connecter</button>
</form>
</div>
</div>
);
}

export default App;
Loading