diff --git a/AdminDashboard.js b/AdminDashboard.js new file mode 100644 index 0000000..c5410ec --- /dev/null +++ b/AdminDashboard.js @@ -0,0 +1,35 @@ +import React from 'react'; +import logo from './assets/logo-tecpap.png'; + +function AdminDashboard({ onLogout }) { + return ( +
+
+
+ Logo de TECPAP + +
+ +

🎛️ Tableau de bord Administrateur

+

Bienvenue dans l’espace admin. Vous avez un accès complet à la gestion des utilisateurs, des documents BAT, et à la traçabilité.

+ + {/* Vous pouvez ajouter plus de fonctionnalités ou liens vers différentes sections du tableau de bord */} +
+
    +
  • +
  • +
  • +
+
+
+
+ ); +} + +export default AdminDashboard; diff --git a/App.css b/App.css new file mode 100644 index 0000000..09f42fd --- /dev/null +++ b/App.css @@ -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; +} \ No newline at end of file diff --git a/App.js b/App.js new file mode 100644 index 0000000..c4ad111 --- /dev/null +++ b/App.js @@ -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 ( +
+ {role === 'admin' && } + {role === 'qualite' && } + {role === 'operateur' && } + {!['admin', 'qualite', 'operateur'].includes(role) && ( +
+ TECPAP Logo +

Rôle inconnu

+

Ce rôle n’est pas reconnu.

+ +
+ )} +
+ ); + } + + return ( +
+
+ TECPAP Logo +

Connexion sécurisée

+
+ + setEmail(e.target.value)} + required + /> + + setPassword(e.target.value)} + required + /> + +
+
+
+ ); +} + +export default App; \ No newline at end of file diff --git a/BatForm.js b/BatForm.js new file mode 100644 index 0000000..9a73617 --- /dev/null +++ b/BatForm.js @@ -0,0 +1,158 @@ +import React, { useState } from 'react'; +import { db } from './firebase-config'; +import { collection, addDoc } from 'firebase/firestore'; +import './App.css'; + +function BatForm() { + const [formData, setFormData] = useState({ + commercial: '', + date: '', + client: '', + motif: '', + typeCommande: '', + format: '', + papier: '', + poignee: '', + couleurs: '', + pantone: '', + poses: '', + manchons: '', + machine: '', + fichier: null + }); + + const handleChange = (e) => { + const { name, value, files } = e.target; + if (name === "fichier") { + setFormData(prev => ({ ...prev, fichier: files[0] })); + } else { + setFormData(prev => ({ ...prev, [name]: value })); + } + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + + try { + const { fichier, ...dataToSend } = formData; + await addDoc(collection(db, "bat"), dataToSend); + alert("✅ B.A.T enregistré avec succès !"); + setFormData({ + commercial: '', + date: '', + client: '', + motif: '', + typeCommande: '', + format: '', + papier: '', + poignee: '', + couleurs: '', + pantone: '', + poses: '', + manchons: '', + machine: '', + fichier: null + }); + } catch (error) { + alert("❌ Erreur : " + error.message); + } + }; + + return ( +
+

📄 Formulaire B.A.T

+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+
+ ); +} + +export default BatForm; diff --git a/Dashboard.js b/Dashboard.js new file mode 100644 index 0000000..00dcfa6 --- /dev/null +++ b/Dashboard.js @@ -0,0 +1,52 @@ +import React from 'react'; +import BatList from './BatList'; + +function Dashboard({ user, onLogout }) { + if (!user) { + return

Utilisateur non trouvé, veuillez vous connecter.

; + } + + const { email, role } = user; + + // Fonction pour rendre le contenu en fonction du rôle + const renderContent = () => { + switch (role) { + case 'admin': + return ( +
+

Vous pouvez gérer les utilisateurs, consulter les statistiques globales et exporter les BAT.

+ {/* Ajouter plus de composants ou actions pour l'admin ici */} +
+ ); + case 'qualite': + return ( +
+

Vous pouvez valider les fiches BAT, effectuer des contrôles et suivre les non-conformités.

+ {/* Ajouter des actions spécifiques à la qualité ici */} +
+ ); + case 'operateur': + return ( +
+

Vous pouvez consulter les ordres de fabrication et suivre les étapes de production.

+ {/* Ajouter des actions spécifiques à l'opérateur ici */} +
+ ); + default: + return

Rôle non défini.

; + } + }; + + return ( +
+
+

Bienvenue, {email.split('@')[0]}

+

Rôle : {role}

+ {renderContent()} + +
+
+ ); +} + +export default Dashboard; diff --git a/OperateurDashboard.js b/OperateurDashboard.js new file mode 100644 index 0000000..c1967f7 --- /dev/null +++ b/OperateurDashboard.js @@ -0,0 +1,39 @@ +import React, { useState } from 'react'; +import logo from './assets/logo-tecpap.png'; +import BatForm from './BatForm'; +import './App.css'; + +function OperateurDashboard({ onLogout }) { + const [message, setMessage] = useState(''); // Gère les messages dynamiques + + const handleLogout = () => { + setMessage('Vous avez été déconnecté avec succès.'); + onLogout(); // Appel à la fonction de déconnexion + }; + + return ( +
+
+
+ Logo de TECPAP + +
+ +

🛠️ Espace Opérateur

+

Bienvenue, merci de compléter le formulaire BAT.

+ + {message &&

{message}

} {/* Affiche un message si nécessaire */} + + {/* Formulaire pour l'opérateur */} +
+
+ ); +} + +export default OperateurDashboard; diff --git a/QualiteDashboard.js b/QualiteDashboard.js new file mode 100644 index 0000000..59787a0 --- /dev/null +++ b/QualiteDashboard.js @@ -0,0 +1,15 @@ +import React from 'react'; +import logo from './assets/logo-tecpap.png'; + +function QualiteDashboard({ onLogout }) { + return ( +
+ TECPAP Logo +

📋 Espace Qualité

+

Bienvenue dans l’espace qualité. Accédez au contrôle BAT, check-lists de conformité, suivi des défauts, et validation finale.

+ +
+ ); +} + +export default QualiteDashboard; diff --git a/firebase-config.js b/firebase-config.js new file mode 100644 index 0000000..a69f27f --- /dev/null +++ b/firebase-config.js @@ -0,0 +1,19 @@ +// src/firebase-config.js +import { initializeApp } from "firebase/app"; +import { getAuth } from "firebase/auth"; +import { getFirestore } from "firebase/firestore"; + +const firebaseConfig = { + apiKey: "AIzaSyDkpEKKs9GR8SNxZxTy3wgOsdu7Ywlouu4", + authDomain: "tecpap-digital.firebaseapp.com", + projectId: "tecpap-digital", + storageBucket: "tecpap-digital.firebasestorage.app", + messagingSenderId: "1085503988391", + appId: "1:1085503988391:web:819f7cdfe0dffcc128b182" +}; +// Initialiser Firebase +const app = initializeApp(firebaseConfig); + +// Exporter les services +export const auth = getAuth(app); +export const db = getFirestore(app); diff --git a/index.css b/index.css new file mode 100644 index 0000000..224d436 --- /dev/null +++ b/index.css @@ -0,0 +1,20 @@ +/* Reset and global styles */ +*, +*::before, +*::after { + box-sizing: border-box; /* Simplifie le calcul des tailles */ + margin: 0; /* Supprime la marge par défaut */ +} + +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; + -webkit-font-smoothing: antialiased; /* Améliore la lisibilité des polices sur MacOS */ + -moz-osx-font-smoothing: grayscale; /* Idem pour Firefox sur MacOS */ +} + +code { + font-family: 'Source Code Pro', Menlo, Monaco, Consolas, 'Courier New', monospace; + white-space: pre; /* Assurez-vous que l'espace blanc est respecté */ +} diff --git a/index.js b/index.js new file mode 100644 index 0000000..aaa9e53 --- /dev/null +++ b/index.js @@ -0,0 +1,14 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import './index.css'; // Votre CSS global +import App from './App'; // Composant principal de l'application + +// Récupération de l'élément root dans le fichier HTML +const root = ReactDOM.createRoot(document.getElementById('root')); + +// Rendu de l'application dans l'élément root +root.render( + + + +); diff --git a/login.js b/login.js new file mode 100644 index 0000000..e0f3c56 --- /dev/null +++ b/login.js @@ -0,0 +1,70 @@ +import React, { useState } from 'react'; +import './App.css'; +import logo from './assets/logo-tecpap.png'; // Ajoutez cet import +import { signInWithEmailAndPassword } from 'firebase/auth'; +import { doc, getDoc } from 'firebase/firestore'; +import { auth, db } from './firebase-config'; + +function Login({ onLogin }) { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const handleLogin = async (e) => { + e.preventDefault(); + setLoading(true); + setError(null); + + try { + const userCredential = await signInWithEmailAndPassword(auth, email, password); + const user = userCredential.user; + const userDoc = await getDoc(doc(db, 'users', user.uid)); + const role = userDoc.exists() ? userDoc.data().role : null; + + if (!role) { + setError("Aucun rôle défini pour cet utilisateur."); + setLoading(false); + return; + } + + onLogin(user, role); + } catch (error) { + setError("Erreur de connexion : " + error.message); + setLoading(false); + } + }; + + return ( +
+
+ TECPAP Logo +

Connexion sécurisée

+ {error &&
{error}
} +
+ + setEmail(e.target.value)} + required + /> + + setPassword(e.target.value)} + required + /> + +
+
+
+ ); +} + +export default Login; \ No newline at end of file diff --git a/logo.svg b/logo.svg new file mode 100644 index 0000000..9dfc1c0 --- /dev/null +++ b/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file