From bd0999dce65bde2b99f4934041026d646915ff41 Mon Sep 17 00:00:00 2001 From: andrymodeste Date: Tue, 18 Nov 2025 06:33:50 +0100 Subject: [PATCH] push 18112025 --- database/Models/Etudiants.backup.js | 2 +- database/Models/Etudiants.js | 6 +- database/database.js | 16 +- database/import/Etudiants.js | 266 +++++++------------ src/renderer/src/assets/logorelever.png | Bin 10008 -> 39567 bytes src/renderer/src/components/AddNotes.jsx | 23 +- src/renderer/src/components/ReleverNotes.jsx | 140 ++++++---- src/renderer/src/components/Student.jsx | 165 ++++++++---- 8 files changed, 327 insertions(+), 291 deletions(-) diff --git a/database/Models/Etudiants.backup.js b/database/Models/Etudiants.backup.js index 40a5b52..b8435b2 100644 --- a/database/Models/Etudiants.backup.js +++ b/database/Models/Etudiants.backup.js @@ -62,7 +62,7 @@ async function insertEtudiant( * @returns JSON */ async function getAllEtudiants() { - const query = database.prepare('SELECT * FROM etudiants ORDER BY annee_scolaire DESC') + const query = database.prepare('SELECT e.*, m.uniter AS mentionUnite, m.nom As nomMention FROM etudiants e JOIN mentions m ON e.mention_id = m.id ORDER BY annee_scolaire DESC') try { let response = await query.all() diff --git a/database/Models/Etudiants.js b/database/Models/Etudiants.js index dc35667..73423bf 100644 --- a/database/Models/Etudiants.js +++ b/database/Models/Etudiants.js @@ -65,7 +65,7 @@ async function insertEtudiant( * @returns JSON */ async function getAllEtudiants() { - const sql = 'SELECT * FROM etudiants ORDER BY annee_scolaire DESC' + const sql = 'SELECT e.*, m.uniter AS mentionUnite, m.nom As nomMention FROM etudiants e JOIN mentions m ON e.mention_id = m.id ORDER BY annee_scolaire DESC' try { let [rows] = await pool.query(sql) @@ -83,7 +83,7 @@ async function getAllEtudiants() { * @returns Promise */ async function getSingleEtudiant(id) { - const sql = 'SELECT e.*, m.uniter AS mentionUnite FROM etudiants e JOIN mentions m ON e.mention_id = m.id WHERE e.id = ?' + const sql = 'SELECT e.*, m.uniter AS mentionUnite, m.nom As nomMention FROM etudiants e JOIN mentions m ON e.mention_id = m.id WHERE e.id = ?' try { const [rows] = await pool.query(sql, [id]) @@ -100,7 +100,7 @@ async function getSingleEtudiant(id) { * @returns JSON */ async function FilterDataByNiveau(niveau) { - const sql = 'SELECT * FROM etudiants WHERE niveau = ? ORDER BY annee_scolaire DESC' + const sql = 'SELECT e.*, m.uniter AS mentionUnite, m.nom As nomMention FROM etudiants e JOIN mentions m ON e.mention_id = m.id WHERE niveau = ? ORDER BY annee_scolaire DESC' try { let [rows] = await pool.query(sql, [niveau]) diff --git a/database/database.js b/database/database.js index 4260948..c10b0dd 100644 --- a/database/database.js +++ b/database/database.js @@ -1,14 +1,14 @@ const mysql = require('mysql2/promise') const bcrypt = require('bcryptjs') - const pool = mysql.createPool({ - host: '192.168.200.200', - user: 'root', - password: 'stephane1313', - database: 'university', - waitForConnections: true, - connectionLimit: 10, - queueLimit: 0 +const pool = mysql.createPool({ + host: '192.168.200.200', + user: 'root', + password: 'stephane1313', + database: 'university', +waitForConnections: true, +connectionLimit: 10, +queueLimit: 0 }) async function createTables() { diff --git a/database/import/Etudiants.js b/database/import/Etudiants.js index d4a351c..8ae1420 100644 --- a/database/import/Etudiants.js +++ b/database/import/Etudiants.js @@ -8,7 +8,7 @@ const dayjs = require('dayjs'); const customParseFormat = require('dayjs/plugin/customParseFormat'); dayjs.extend(customParseFormat); -// ✅ Fonction de correction d'encodage +// ---------- Fonctions utilitaires ---------- function fixEncoding(str) { if (typeof str !== 'string') return str; return str @@ -21,156 +21,105 @@ function fixEncoding(str) { .replace(/â€/g, '…') .replace(/â€/g, '-'); } + function convertToISODate(input) { if (!input) return null; - console.log('🔍 Input original:', input, 'Type:', typeof input); - - // Si input est un objet Date valide if (input instanceof Date && !isNaN(input)) { - const result = dayjs(input).format('YYYY-MM-DD'); - console.log('📅 Date object convertie:', result); - return result; + return dayjs(input).format('YYYY-MM-DD'); } - // Si input est un nombre (numéro de série Excel) if (typeof input === 'number') { - // Formule Excel: (numéro - 25569) * 86400 * 1000 - const excelDate = new Date((input - 25569) * 86400 * 1000); - const result = dayjs(excelDate).format('YYYY-MM-DD'); - console.log('📊 Numéro Excel', input, 'converti en:', result); - return result; + return dayjs(new Date((input - 25569) * 86400 * 1000)).format('YYYY-MM-DD'); } - // Si input est une chaîne if (typeof input === 'string') { const cleanInput = input.trim(); - - // Cas spécial "vers YYYY" const versMatch = cleanInput.match(/vers\s*(\d{4})/i); - if (versMatch) { - const result = `${versMatch[1]}-01-01`; - console.log('📝 "Vers" détecté:', result); - return result; - } + if (versMatch) return `${versMatch[1]}-01-01`; - // Formats à tester dans l'ordre de priorité const formats = [ - 'DD/MM/YYYY', 'D/M/YYYY', // Format français prioritaire - 'YYYY-MM-DD', // Format ISO - 'DD-MM-YYYY', 'D-M-YYYY', // Format français avec tirets - 'MM/DD/YYYY', 'M/D/YYYY', // Format américain - 'MM-DD-YYYY', 'M-D-YYYY', // Format américain avec tirets - 'DD/MM/YY', 'D/M/YY', // Années courtes + 'DD/MM/YYYY', 'D/M/YYYY', + 'YYYY-MM-DD', + 'DD-MM-YYYY', 'D-M-YYYY', + 'MM/DD/YYYY', 'M/D/YYYY', + 'MM-DD-YYYY', 'M-D-YYYY', + 'DD/MM/YY', 'D/M/YY', 'MM/DD/YY', 'M/D/YY', 'DD-MM-YY', 'D-M-YY', 'MM-DD-YY', 'M-D-YY' ]; - // Test avec parsing strict pour éviter les interprétations erronées - for (const format of formats) { - const parsedDate = dayjs(cleanInput, format, true); // true = strict parsing - if (parsedDate.isValid()) { - const result = parsedDate.format('YYYY-MM-DD'); - console.log(`✅ Format "${format}" réussi:`, cleanInput, '->', result); - - // Vérification supplémentaire pour les dates invalides comme 29/02 en année non-bissextile - if (format.includes('DD/MM') || format.includes('D/M')) { - const day = parsedDate.date(); - const month = parsedDate.month() + 1; // dayjs month is 0-indexed - const year = parsedDate.year(); - - // Vérifier si c'est le 29 février d'une année non-bissextile - if (month === 2 && day === 29 && !isLeapYear(year)) { - console.warn('⚠️ Date invalide détectée: 29 février en année non-bissextile'); - return null; // ou retourner une date par défaut - } - } - - return result; - } + for (const fmt of formats) { + const parsed = dayjs(cleanInput, fmt, true); + if (parsed.isValid()) return parsed.format('YYYY-MM-DD'); } - // Si aucun format strict ne fonctionne, essayer le parsing libre en dernier recours - const freeParseDate = dayjs(cleanInput); - if (freeParseDate.isValid()) { - const result = freeParseDate.format('YYYY-MM-DD'); - console.log('🆓 Parsing libre réussi:', cleanInput, '->', result); - return result; - } + const freeParse = dayjs(cleanInput); + if (freeParse.isValid()) return freeParse.format('YYYY-MM-DD'); } - console.error('❌ Impossible de convertir:', input); return null; } -// Fonction utilitaire pour vérifier les années bissextiles +// Vérifie année bissextile function isLeapYear(year) { return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0); } -// ✅ Mise à jour d'un étudiant existant +// ---------- UPDATE étudiant ---------- async function updateEtudiant(row) { - const sql = ` - UPDATE etudiants SET - nom = ?, - prenom = ?, - photos = ?, - date_de_naissances = ?, - niveau = ?, - annee_scolaire = ?, - status = ?, - mention_id = ?, - num_inscription = ?, - sexe = ?, - date_delivrance = ?, - nationalite = ?, - annee_bacc = ?, - serie = ?, - boursier = ?, - domaine = ?, - contact = ?, - parcours = ? - WHERE cin = ? OR (LOWER(nom) = ? AND LOWER(prenom) = ?) - `; + const fields = []; + const params = []; - const params = [ - row.nom, - row.prenom, - getCompressedDefaultImage(), - convertToISODate(row.date_naissance), - row.niveau, - row.annee_scolaire, - row.code_redoublement, - row.mention, - row.num_inscription.toString(), - row.sexe, - convertToISODate(row.date_de_delivrance), - row.nationaliter, - parseInt(row.annee_baccalaureat, 10), - row.serie, - row.boursier, - fixEncoding(row.domaine), - row.contact, - null, - row.cin, - row.nom.toLowerCase().trim(), - row.prenom.toLowerCase().trim() - ]; + function addFieldIfValue(field, value) { + if (value !== undefined && value !== null && value !== '') { + fields.push(`${field} = ?`); + params.push(value); + } + } + + addFieldIfValue('nom', row.nom); + addFieldIfValue('prenom', row.prenom); + addFieldIfValue('date_de_naissances', convertToISODate(row.date_naissance)); + addFieldIfValue('niveau', row.niveau); + addFieldIfValue('annee_scolaire', row.annee_scolaire); + addFieldIfValue('status', row.code_redoublement); + addFieldIfValue('mention_id', row.mention); + addFieldIfValue('num_inscription', row.num_inscription?.toString()); + addFieldIfValue('sexe', row.sexe); + addFieldIfValue('date_delivrance', convertToISODate(row.date_de_delivrance)); + addFieldIfValue('nationalite', row.nationaliter); + addFieldIfValue('annee_bacc', parseInt(row.annee_baccalaureat, 10)); + addFieldIfValue('serie', row.serie); + addFieldIfValue('boursier', row.boursier); + addFieldIfValue('domaine', fixEncoding(row.domaine)); + addFieldIfValue('contact', row.contact); + + if (fields.length === 0) return { success: false, error: 'Aucun champ valide à mettre à jour' }; + + let sql, whereParams; + + if (row.cin && row.cin.toString().trim() !== '') { + sql = `UPDATE etudiants SET ${fields.join(', ')} WHERE cin = ?`; + whereParams = [row.cin]; + } else { + sql = `UPDATE etudiants SET ${fields.join(', ')} WHERE LOWER(TRIM(nom)) = ? AND LOWER(TRIM(prenom)) = ?`; + whereParams = [row.nom.toLowerCase().trim(), row.prenom.toLowerCase().trim()]; + } try { - const [result] = await pool.query(sql, params); - console.log(`Update effectué pour CIN ${row.cin} ou nom ${row.nom} ${row.prenom}, affectedRows=${result.affectedRows}`); + const [result] = await pool.query(sql, [...params, ...whereParams]); return { success: true, affectedRows: result.affectedRows }; } catch (error) { - console.error('❌ Erreur MySQL update :', error.message); return { success: false, error: error.message }; } } - -// ✅ Insertion réelle multiple +// ---------- INSERT multiple étudiants ---------- async function insertMultipleEtudiants(etudiants) { + if (!etudiants || etudiants.length === 0) return { success: true, affectedRows: 0 }; + const sql = ` INSERT INTO etudiants ( nom, prenom, photos, date_de_naissances, niveau, annee_scolaire, status, @@ -190,7 +139,7 @@ async function insertMultipleEtudiants(etudiants) { row.mention, row.num_inscription.toString(), row.sexe, - row.cin, + row.cin || null, convertToISODate(row.date_de_delivrance), row.nationaliter, parseInt(row.annee_baccalaureat, 10), @@ -205,31 +154,26 @@ async function insertMultipleEtudiants(etudiants) { const [result] = await pool.query(sql, [values]); return { success: true, affectedRows: result.affectedRows }; } catch (error) { - console.error('❌ Erreur MySQL :', error.message); return { success: false, error: error.message }; } } -// ✅ Import fichier vers base +// ---------- IMPORT fichier ---------- async function importFileToDatabase(filePath) { - const fileExtension = path.extname(filePath).toLowerCase(); let records; + const ext = path.extname(filePath).toLowerCase(); - if (fileExtension === '.xlsx') { + if (ext === '.xlsx') { const workbook = XLSX.readFile(filePath); const worksheet = workbook.Sheets[workbook.SheetNames[0]]; - // raw: true pour garder les valeurs brutes, surtout pour les dates - records = XLSX.utils.sheet_to_json(worksheet, { defval: ''}); - } else if (fileExtension === '.csv') { - const fileContent = fs.readFileSync(filePath, 'utf8'); - records = parse(fileContent, { columns: true, skip_empty_lines: true }); - }else { - console.error('Unsupported file format.'); - return { error: true, message: 'Format de fichier non supporté.' }; + records = XLSX.utils.sheet_to_json(worksheet, { defval: '' }); + } else if (ext === '.csv') { + const content = fs.readFileSync(filePath, 'utf8'); + records = parse(content, { columns: true, skip_empty_lines: true }); + } else { + return { error: true, message: 'Format de fichier non supporté' }; } - console.log(`📄 Nombre de lignes : ${records.length}`); - // Vérifier champs obligatoires const requiredFields = [ 'nom', 'date_naissance', 'niveau', 'annee_scolaire', @@ -239,12 +183,8 @@ async function importFileToDatabase(filePath) { ]; for (const [i, row] of records.entries()) { - for (const field of requiredFields) { - if (!row[field]) { - const msg = `Le champ '${field}' est manquant à la ligne ${i + 2}`; - console.error(msg); - return { error: true, message: msg }; - } + for (const f of requiredFields) { + if (!row[f]) return { error: true, message: `Le champ '${f}' est manquant à la ligne ${i + 2}` }; } } @@ -253,64 +193,48 @@ async function importFileToDatabase(filePath) { const etudiantsToInsert = []; const doublons = []; - console.log(records); for (const row of records) { - // Mapping mention - console.log('Avant conversion date_naissance:', row.date_naissance); row.date_naissance = convertToISODate(row.date_naissance); - console.log('Après conversion date_naissance:', row.date_naissance); + + // Mapping mention const matchedMention = mentionRows.find( - m => m.nom.toUpperCase() === row.mention.toUpperCase() || - m.uniter.toUpperCase() === row.mention.toUpperCase() + m => m.nom.toUpperCase() === row.mention.toUpperCase() || m.uniter.toUpperCase() === row.mention.toUpperCase() ); if (matchedMention) row.mention = matchedMention.id; - // Gestion code_redoublement -> status id - if (row.code_redoublement) { - row.code_redoublement = row.code_redoublement.trim().substring(0, 1); - } else { - row.code_redoublement = 'N'; - } - const statusMatch = statusRows.find( - s => s.nom.toLowerCase().startsWith(row.code_redoublement.toLowerCase()) - ); + // Mapping status + row.code_redoublement = (row.code_redoublement ? row.code_redoublement.trim().substring(0, 1) : 'N'); + const statusMatch = statusRows.find(s => s.nom.toLowerCase().startsWith(row.code_redoublement.toLowerCase())); if (statusMatch) row.code_redoublement = statusMatch.id; - // Vérification doublons (extraction complet) - const nomComplet = (row.nom + ' ' + row.prenom).toLowerCase().trim(); - - const [existing] = await pool.query( - 'SELECT * FROM etudiants WHERE LOWER(CONCAT(nom, " ", prenom)) = ? OR cin = ?', - [nomComplet, row.cin] - ); + // Détection doublons (ignorer CIN vide) + let existing; + if (row.cin && row.cin.toString().trim() !== '') { + [existing] = await pool.query('SELECT * FROM etudiants WHERE cin = ?', [row.cin]); + } else { + [existing] = await pool.query( + 'SELECT * FROM etudiants WHERE LOWER(TRIM(nom)) = ? AND LOWER(TRIM(prenom)) = ?', + [row.nom.toLowerCase().trim(), row.prenom.toLowerCase().trim()] + ); + } if (existing.length > 0) { doublons.push({ nom: row.nom, prenom: row.prenom, cin: row.cin }); - // Mise à jour const updateResult = await updateEtudiant(row); - if (!updateResult.success) { - return { error: true, message: `Erreur lors de la mise à jour de ${row.nom} ${row.prenom} : ${updateResult.error}` }; - } - continue; + if (!updateResult.success) return { error: true, message: `Erreur update ${row.nom} ${row.prenom}: ${updateResult.error}` }; + } else { + etudiantsToInsert.push(row); } - - etudiantsToInsert.push(row); } - console.log(etudiantsToInsert); + console.log('✅ Nouveaux à insérer :', etudiantsToInsert.map(e => e.nom + ' ' + e.prenom)); + console.log('🔄 Étudiants mis à jour :', doublons.map(e => e.nom + ' ' + e.prenom)); - // Insertion des nouveaux - let insertResult = { success: true, affectedRows: 0 }; - if (etudiantsToInsert.length > 0) { - insertResult = await insertMultipleEtudiants(etudiantsToInsert); - if (!insertResult.success) { - return { error: true, message: `Erreur lors de l'insertion : ${insertResult.error}` }; - } - } + const insertResult = await insertMultipleEtudiants(etudiantsToInsert); + if (!insertResult.success) return { error: true, message: insertResult.error }; - let msg = `Importation réussie. ${etudiantsToInsert.length} nouvel(le)(s) étudiant(s) inséré(s). ${doublons.length} étudiant(s) mis à jour.`; - return { error: false, message: msg }; + return { error: false, message: `Importation réussie. ${etudiantsToInsert.length} nouvel(le)(s) inséré(s), ${doublons.length} mis à jour.` }; } module.exports = { importFileToDatabase }; diff --git a/src/renderer/src/assets/logorelever.png b/src/renderer/src/assets/logorelever.png index 952d3a256d659885a9b9d0e579e347fc4837a561..99938210a76f1455faa25841acf41943017ac63d 100644 GIT binary patch literal 39567 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 literal 10008 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 { const { id, niveau, mention_id, parcours } = useParams() @@ -22,6 +23,9 @@ const AddNotes = () => { setOpenModal1(false) } + const location = useLocation() +const previousFilter = location.state?.selectedNiveau + /** * Fetching the matieres */ @@ -83,7 +87,7 @@ const AddNotes = () => { let valid = validateAddNote() let annee_scolaire = AnneeScolaireEtudiant let mention_id = etudiants.mention_id - + if (valid) { let response = await window.notes.insertNote({ etudiant_id, @@ -92,21 +96,33 @@ const AddNotes = () => { formData, annee_scolaire }) + if (response.success) { + // ✅ Ici on sauvegarde le filtre avant d'ouvrir le modal + if (previousFilter) { + localStorage.setItem('selectedNiveau', previousFilter) + } + setOpen(true) setStatut(200) setDisabled(true) + + // Reset du formulaire const resetFormData = matieres.reduce((acc, mat) => { - acc[mat.id] = '' // Reset each field to an empty string + acc[mat.id] = '' return acc }, {}) setFormData(resetFormData) + } else { + setOpen(true) + setStatut(400) } } else { setOpen(true) setStatut(400) } } + const [statut, setStatut] = useState(200) @@ -123,9 +139,10 @@ const AddNotes = () => { } const handleClose2 = () => { - navigate('/notes') + navigate('/student', { state: { selectedNiveau: previousFilter } }) setOpen(false) } + /** * function to return the view Modal diff --git a/src/renderer/src/components/ReleverNotes.jsx b/src/renderer/src/components/ReleverNotes.jsx index 4cde1f4..e525797 100644 --- a/src/renderer/src/components/ReleverNotes.jsx +++ b/src/renderer/src/components/ReleverNotes.jsx @@ -192,10 +192,10 @@ const ReleverNotes = ({ id, anneescolaire, niveau, sessionType = 'ensemble', ref {Object.entries(groupedDataBySemestre).map(([semestre, matieres]) => { // Group by unite_enseignement inside each semestre const groupedByUnite = matieres.reduce((acc, matiere) => { - if (!acc[matiere.unite_enseignement]) { - acc[matiere.unite_enseignement] = [] + if (!acc[matiere.ue]) { + acc[matiere.ue] = [] } - acc[matiere.unite_enseignement].push(matiere) + acc[matiere.ue].push(matiere) return acc }, {}) @@ -218,7 +218,6 @@ const ReleverNotes = ({ id, anneescolaire, niveau, sessionType = 'ensemble', ref paddingTop: '8px', borderRight: 'solid 1px black', borderBottom: 'solid 1px black', - background: '#bdbcbc', borderLeft: 'solid 1px black' }} > @@ -255,6 +254,24 @@ const ReleverNotes = ({ id, anneescolaire, niveau, sessionType = 'ensemble', ref {matiere.note} + {/* Moyenne UE pour session normale */} + {matiereIndex === 0 && ( + + {( + matieres.reduce((total, matiere) => total + matiere.note, 0) / + matieres.length + ).toFixed(2)} + + )} )} @@ -266,6 +283,24 @@ const ReleverNotes = ({ id, anneescolaire, niveau, sessionType = 'ensemble', ref {matiere.noterepech} + {/* Moyenne UE pour session rattrapage */} + {matiereIndex === 0 && ( + + {( + matieres.reduce((total, matiere) => total + matiere.noterepech, 0) / + matieres.length + ).toFixed(2)} + + )} )} @@ -289,7 +324,7 @@ const ReleverNotes = ({ id, anneescolaire, niveau, sessionType = 'ensemble', ref matieres.reduce((total, matiere) => total + matiere.noterepech, 0) / matieres.length ).toFixed(2), - sessionType // MODIFICATION: Passer le sessionType + sessionType )} )} @@ -298,7 +333,7 @@ const ReleverNotes = ({ id, anneescolaire, niveau, sessionType = 'ensemble', ref {/* Add Total Row for 'unite_enseignement' */} - Total de Credit et Moyenne des Notes + Total de Credit {sessionType !== 'rattrapage' && ( @@ -327,19 +362,14 @@ const ReleverNotes = ({ id, anneescolaire, niveau, sessionType = 'ensemble', ref {matieres.reduce((total, matiere) => total + matiere.credit, 0)} - {( - matieres.reduce((total, matiere) => total + matiere.note, 0) / - matieres.length - ).toFixed(2)} - + > )} @@ -356,19 +386,14 @@ const ReleverNotes = ({ id, anneescolaire, niveau, sessionType = 'ensemble', ref {matieres.reduce((total, matiere) => total + matiere.credit, 0)} - {( - matieres.reduce((total, matiere) => total + matiere.noterepech, 0) / - matieres.length - ).toFixed(2)} - + > )} @@ -390,20 +415,20 @@ const ReleverNotes = ({ id, anneescolaire, niveau, sessionType = 'ensemble', ref ) } - // MODIFICATION: Fonction totalNotes mise à jour pour tenir compte du sessionType + // MODIFICATION: Fonction totalNotes mise à jour pour utiliser les nouvelles classes const totalNotes = () => { - let totalNotes = document.querySelectorAll('.moyenneNotes') - let totalNotesRepech = document.querySelectorAll('.moyenneNotesRattrapage') + let totalNotesNormale = document.querySelectorAll('.moyenneUENormale') + let totalNotesRattrapage = document.querySelectorAll('.moyenneUERattrapage') let TotalNoteNumber = 0 let TotalNoteNumberRepech = 0 - totalNotes.forEach((notes) => { - TotalNoteNumber += Number(notes.textContent) / totalNotes.length + totalNotesNormale.forEach((notes) => { + TotalNoteNumber += Number(notes.textContent) / totalNotesNormale.length }) - totalNotesRepech.forEach((notes) => { - TotalNoteNumberRepech += Number(notes.textContent) / totalNotesRepech.length + totalNotesRattrapage.forEach((notes) => { + TotalNoteNumberRepech += Number(notes.textContent) / totalNotesRattrapage.length }) // Retourner la note selon le type de session @@ -440,12 +465,32 @@ const ReleverNotes = ({ id, anneescolaire, niveau, sessionType = 'ensemble', ref ref={Telever} >
-
- image en tete - image en tete +
+ logo gauche + +
+
+ REPOBLIKAN'I MADAGASIKARA +
+

Fitiavana – Tanindrazana – Fandrosoana

+

+ MINISTÈRE DE L'ENSEIGNEMENT SUPÉRIEUR
+ ET DE LA RECHERCHE SCIENTIFIQUE +

+

UNIVERSITÉ DE TOAMASINA

+

ÉCOLE SUPÉRIEURE POLYTECHNIQUE

+ + logo droite +
+

Releve de notes @@ -489,7 +534,7 @@ const ReleverNotes = ({ id, anneescolaire, niveau, sessionType = 'ensemble', ref {/* droite gauche */}
- Annee U + Annee Sco
@@ -517,9 +562,8 @@ const ReleverNotes = ({ id, anneescolaire, niveau, sessionType = 'ensemble', ref Normale @@ -544,8 +588,8 @@ const ReleverNotes = ({ id, anneescolaire, niveau, sessionType = 'ensemble', ref {sessionType !== 'normale' && ( Rattrapage @@ -558,20 +602,21 @@ const ReleverNotes = ({ id, anneescolaire, niveau, sessionType = 'ensemble', ref - + semestre - UE - EC + Unités
d'Enseignement
(UE) + Éléments
constitutifs
(EC) {sessionType !== 'rattrapage' && ( <> crédit Notes + Moyenne )} @@ -579,6 +624,7 @@ const ReleverNotes = ({ id, anneescolaire, niveau, sessionType = 'ensemble', ref <> crédit Notes + Moyenne )} @@ -602,7 +648,7 @@ const ReleverNotes = ({ id, anneescolaire, niveau, sessionType = 'ensemble', ref {note.toFixed(2)} /20 - + {getmentionAfterNotes(note)}
- + Décision du Jury:{' '} diff --git a/src/renderer/src/components/Student.jsx b/src/renderer/src/components/Student.jsx index 62e55ef..9064b67 100644 --- a/src/renderer/src/components/Student.jsx +++ b/src/renderer/src/components/Student.jsx @@ -27,6 +27,7 @@ import { MdVerified } from 'react-icons/md' import warning from '../assets/warning.svg' import success from '../assets/success.svg' import { useAuthContext } from '../contexts/AuthContext' // Import du contexte d'authentification +import { useLocation } from 'react-router-dom' const Student = () => { // Récupération de l'utilisateur connecté @@ -59,22 +60,56 @@ const Student = () => { const [status, setStatus] = useState([]) const [mention, setMention] = useState([]) + const [filterModel, setFilterModel] = useState({ items: [] }) + const [sortModel, setSortModel] = useState([]) + const location = useLocation() + const savedFilter = localStorage.getItem('selectedNiveau') || '' + const initialFilter = location.state?.selectedNiveau || savedFilter + + const [selectedNiveau, setSelectedNiveau] = useState(initialFilter) + + useEffect(() => { + if (initialFilter) { + setSelectedNiveau(initialFilter) + FilterData({ target: { value: initialFilter } }) // applique le filtre initial + } + }, [initialFilter]) + + /** * hook for displaying the students */ + const [allEtudiants, setAllEtudiants] = useState([]) const [etudiants, setEtudiants] = useState([]) const [notes, setNotes] = useState([]) useEffect(() => { window.etudiants.getEtudiants().then((response) => { - setEtudiants(response) + setAllEtudiants(response) + + if (selectedNiveau && selectedNiveau !== '') { + setEtudiants(response.filter(e => e.niveau === selectedNiveau)) + } else { + setEtudiants(response) + } }) - + window.notes.getMoyenneVerify().then((response) => { setNotes(response) }) + }, [selectedNiveau]) + + useEffect(() => { + const savedFilters = localStorage.getItem('datagridFilters') + const savedSort = localStorage.getItem('datagridSort') + const savedPagination = localStorage.getItem('datagridPagination') + + if (savedFilters) setFilterModel(JSON.parse(savedFilters)) + if (savedSort) setSortModel(JSON.parse(savedSort)) + if (savedPagination) setPaginationModel(JSON.parse(savedPagination)) }, []) + const [niveaus, setNiveau] = useState([]) @@ -222,15 +257,21 @@ const Student = () => { ) : ( - - - Ajouter un notes à cet étudiant - - + to={`/addnotes/${params.value}/${params.row.niveau}/${params.row.mention_id}/${params.row.parcour}`} + state={{ selectedNiveau: selectedNiveau }} // <-- on envoie le filtre +> + + + Ajouter un notes à cet étudiant + + + )}
) @@ -277,6 +318,7 @@ const Student = () => { { field: 'status', headerName: 'Status', width: 140 }, { field: 'num_inscription', headerName: "Numéro d'inscription", width: 160 }, { field: 'parcour', headerName: 'Parcours', width: 150 }, + { field: 'nomMention', headerName: 'Mention', width: 150 }, { field: 'photos', headerName: 'Image', @@ -501,6 +543,7 @@ const Student = () => { contact: etudiant.contact, mention_id: etudiant.mention_id, mentionUnite: etudiant.mentionUnite, + nomMention: etudiant.nomMention, action: etudiant.id // Ensure this is a valid URL for the image })) @@ -518,21 +561,20 @@ const Student = () => { /** * ✅ Fonction de filtrage avec reset de pagination */ - const FilterData = async (e) => { - let niveau = e.target.value - if (niveau !== '') { - let data = await window.etudiants.FilterDataByNiveau({ niveau }) - setEtudiants(data) - // Reset vers la première page après filtrage - setPaginationModel(prev => ({ ...prev, page: 0 })) + const FilterData = (e) => { + const niveau = e.target.value + setSelectedNiveau(niveau) + + if (niveau === '') { + setEtudiants(allEtudiants) } else { - window.etudiants.getEtudiants().then((response) => { - setEtudiants(response) - // Reset vers la première page - setPaginationModel(prev => ({ ...prev, page: 0 })) - }) + const filtered = allEtudiants.filter(student => student.niveau === niveau) + setEtudiants(filtered) } + + setPaginationModel(prev => ({ ...prev, page: 0 })) } + const [openModal, setOpenModal] = useState(false) const [openModal2, setOpenModal2] = useState(false) @@ -645,36 +687,31 @@ const Student = () => { Niveau + labelId="demo-select-small-label" + id="demo-select-small" + label="Niveau" + color="warning" + name="niveau" + value={selectedNiveau} // ✅ ici + onChange={FilterData} // ✅ ici + startAdornment={ + + + + } + sx={{ background: 'white', display: 'flex', alignItems: 'center', '& .MuiSelect-icon': { marginLeft: 'auto' } }} +> + + Tous les étudiants + + {niveaus.map((niveau) => ( + + {niveau.nom} + + ))} + + +

@@ -700,11 +737,23 @@ const Student = () => { }} > { + setFilterModel(newModel) + localStorage.setItem('datagridFilters', JSON.stringify(newModel)) + }} + sortModel={sortModel} // ✅ Restaure le tri + onSortModelChange={(newModel) => { + setSortModel(newModel) + localStorage.setItem('datagridSort', JSON.stringify(newModel)) + }} + paginationModel={paginationModel} + onPaginationModelChange={(newModel) => { + handlePaginationModelChange(newModel) + localStorage.setItem('datagridPagination', JSON.stringify(newModel)) + }} sx={{ border: 0, width: 'auto', // Ensures the DataGrid takes full width