Browse Source

derniere version

master
andrymodeste 4 months ago
parent
commit
08e11d0bf6
  1. 10
      database/Models/AnneeScolaire.js
  2. 2
      database/Models/Etudiants.backup.js
  3. 24
      database/Models/Etudiants.js
  4. 8
      database/Models/Matieres.js
  5. 8
      database/Models/Mentions.js
  6. 4
      database/Models/NoteSysrem.js
  7. 8
      database/Models/Parcours.js
  8. 4
      database/database.backup.js
  9. 4
      database/database.js
  10. 4
      database/database2.js
  11. 4
      database/function/System.js
  12. 8
      src/renderer/src/components/AddAnneeScolaire.jsx
  13. 8
      src/renderer/src/components/AddStudent.jsx
  14. 4
      src/renderer/src/components/AnneeScolaire.jsx
  15. 8
      src/renderer/src/components/ExportEtudiants.jsx
  16. 4
      src/renderer/src/components/Home.jsx
  17. 159
      src/renderer/src/components/Login.jsx
  18. 6
      src/renderer/src/components/ModalAddEtudiants.jsx
  19. 4
      src/renderer/src/components/ModalAddProf.jsx
  20. 6
      src/renderer/src/components/ModalCertificate.jsx
  21. 2
      src/renderer/src/components/ModalExportFichr.jsx
  22. 2
      src/renderer/src/components/ModalRecepice.jsx
  23. 2
      src/renderer/src/components/ModalStage.jsx
  24. 109
      src/renderer/src/components/Noteclasse.jsx
  25. 2
      src/renderer/src/components/Notes.jsx
  26. 208
      src/renderer/src/components/Param.jsx
  27. 263
      src/renderer/src/components/ReleverNotes.jsx
  28. 562
      src/renderer/src/components/Resultat.jsx
  29. 84
      src/renderer/src/components/Sidenav.jsx
  30. 6
      src/renderer/src/components/SingleAnneeScolaire.jsx
  31. 8
      src/renderer/src/components/SingleEtudiant.jsx
  32. 21
      src/renderer/src/components/Student.jsx
  33. 8
      src/renderer/src/components/SystemeNote.jsx
  34. 4
      src/renderer/src/components/TesteDatagrid.jsx
  35. 4
      src/renderer/src/components/UpdateModalProf.jsx
  36. 6
      src/renderer/src/components/function/PDFEditor.js
  37. 69
      src/renderer/src/components/function/PDFEditorV2.js
  38. 2
      src/renderer/src/components/validation/ValidationAddAnneeScolaire.js
  39. 80
      src/renderer/src/contexts/AuthContext.jsx
  40. 2
      src/renderer/src/test/qr.html
  41. 2
      src/renderer/src/test/relever.html
  42. 2
      text.txt

10
database/Models/AnneeScolaire.js

@ -23,7 +23,7 @@ async function createAnneeScolaire(code, debut, fin) {
}
/**
* function to get all année scolaire
* function to get all Année Univesitaire
* @returns promise
*/
async function getAnneeScolaire() {
@ -71,13 +71,13 @@ async function deleteAnneeScolaire(id) {
if (result.affectedRows === 0) {
return {
success: false,
message: 'Année Scolaire non trouvé.'
message: 'Année universitaire non trouvé.'
}
}
return {
success: true,
message: 'Année Scolaire supprimé avec succès.'
message: 'Année universitaire supprimé avec succès.'
}
} catch (error) {
return { success: false, error: 'Erreur veullez réeseyer' }
@ -93,13 +93,13 @@ async function updateAnneeScolaire(id, code, debut, fin) {
if (result.affectedRows === 0) {
return {
success: false,
message: 'Année Scolaire non trouvé ou aucune modification effectuée.'
message: 'Année universitaire non trouvé ou aucune modification effectuée.'
}
}
return {
success: true,
message: 'Année Scolaire mis à jour avec succès.'
message: 'Année universitaire mis à jour avec succès.'
}
} catch (error) {
return { success: false, error: 'Erreur veullez réeseyer' }

2
database/Models/Etudiants.backup.js

@ -191,7 +191,7 @@ async function updateEtudiant(
async function getDataToDashboard() {
const query = database.prepare('SELECT * FROM niveaus')
const query2 = database.prepare('SELECT * FROM etudiants')
const query3 = database.prepare('SELECT DISTINCT annee_scolaire FROM etudiants') // get all année scolaire sans doublan
const query3 = database.prepare('SELECT DISTINCT annee_scolaire FROM etudiants') // get all Année Univesitaire sans doublan
try {
let niveau = query.all()

24
database/Models/Etudiants.js

@ -83,7 +83,7 @@ async function getAllEtudiants() {
* @returns Promise
*/
async function getSingleEtudiant(id) {
const sql = 'SELECT * FROM etudiants WHERE id = ?'
const sql = 'SELECT e.*, m.uniter AS mentionUnite FROM etudiants e JOIN mentions m ON e.mention_id = m.id WHERE e.id = ?'
try {
const [rows] = await pool.query(sql, [id])
@ -176,13 +176,13 @@ async function updateEtudiant(
if (result.affectedRows === 0) {
return {
success: false,
message: 'Année Scolaire non trouvé.'
message: 'Année Univesitaire non trouvé.'
}
}
return {
success: true,
message: 'Année Scolaire supprimé avec succès.'
message: 'Année Univesitaire supprimé avec succès.'
}
} catch (error) {
return error
@ -197,7 +197,7 @@ async function updateEtudiant(
async function getDataToDashboard() {
const query = 'SELECT * FROM niveaus'
const query2 = 'SELECT * FROM etudiants'
const query3 = 'SELECT DISTINCT annee_scolaire FROM etudiants' // get all année scolaire sans doublan
const query3 = 'SELECT DISTINCT annee_scolaire FROM etudiants' // get all Année Univesitaire sans doublan
try {
let [rows] = await pool.query(query)
@ -222,13 +222,13 @@ async function changePDP(photos, id) {
if (result.affectedRows === 0) {
return {
success: false,
message: 'Année Scolaire non trouvé.'
message: 'Année Univesitaire non trouvé.'
}
}
return {
success: true,
message: 'Année Scolaire supprimé avec succès.'
message: 'Année Univesitaire supprimé avec succès.'
}
} catch (error) {
return error
@ -244,13 +244,13 @@ async function updateParcours(parcours, id) {
if (result.affectedRows === 0) {
return {
success: false,
message: 'Année Scolaire non trouvé.'
message: 'Année Univesitaire non trouvé.'
}
}
return {
success: true,
message: 'Année Scolaire supprimé avec succès.'
message: 'Année Univesitaire supprimé avec succès.'
}
} catch (error) {
return error
@ -294,13 +294,13 @@ async function updateTranche(id, tranchename, montant) {
if (result.affectedRows === 0) {
return {
success: false,
message: 'Année Scolaire non trouvé.'
message: 'Année Univesitaire non trouvé.'
}
}
return {
success: true,
message: 'Année Scolaire supprimé avec succès.'
message: 'Année Univesitaire supprimé avec succès.'
}
} catch (error) {
console.log('resultat error:',error);
@ -317,13 +317,13 @@ async function deleteTranche(id) {
if (result.affectedRows === 0) {
return {
success: false,
message: 'Année Scolaire non trouvé.'
message: 'Année Univesitaire non trouvé.'
}
}
return {
success: true,
message: 'Année Scolaire supprimé avec succès.'
message: 'Année Univesitaire supprimé avec succès.'
}
} catch (error) {
return error

8
database/Models/Matieres.js

@ -125,13 +125,13 @@ async function updateMatiere(nom, id, credit, uniter, ue) {
if (result.affectedRows === 0) {
return {
success: false,
message: 'Année Scolaire non trouvé ou aucune modification effectuée.'
message: 'Année Univesitaire non trouvé ou aucune modification effectuée.'
}
}
return {
success: true,
message: 'Année Scolaire mis à jour avec succès.'
message: 'Année Univesitaire mis à jour avec succès.'
}
} catch (error) {
return { success: false, error: 'Erreur veullez réeseyer' + error }
@ -448,13 +448,13 @@ async function updateProf(matiere_id, nom, prenom, contact, date) {
if (result.affectedRows === 0) {
return {
success: false,
message: 'Année Scolaire non trouvé.'
message: 'Année Univesitaire non trouvé.'
}
}
return {
success: true,
message: 'Année Scolaire supprimé avec succès.'
message: 'Année Univesitaire supprimé avec succès.'
}
} catch (error) {
console.error(error)

8
database/Models/Mentions.js

@ -24,13 +24,13 @@ async function deleteMention(id) {
if (result.affectedRows === 0) {
return {
success: false,
message: 'Année Scolaire non trouvé.'
message: 'Année Univesitaire non trouvé.'
}
}
return {
success: true,
message: 'Année Scolaire supprimé avec succès.'
message: 'Année Univesitaire supprimé avec succès.'
}
} catch (error) {
return { success: false, error: 'Erreur veullez réeseyer' + error }
@ -70,13 +70,13 @@ async function updateMention(nom, uniter, id) {
if (result.affectedRows === 0) {
return {
success: false,
message: 'Année Scolaire non trouvé ou aucune modification effectuée.'
message: 'Année Univesitaire non trouvé ou aucune modification effectuée.'
}
}
return {
success: true,
message: 'Année Scolaire mis à jour avec succès.'
message: 'Année Univesitaire mis à jour avec succès.'
}
} catch (error) {
return { success: false, error: 'Erreur veullez réeseyer' + error }

4
database/Models/NoteSysrem.js

@ -33,13 +33,13 @@ async function updateSysteme(id, admis, redouble, renvoyer) {
if (result.affectedRows === 0) {
return {
success: false,
message: 'Année Scolaire non trouvé.'
message: 'Année Univesitaire non trouvé.'
}
}
return {
success: true,
message: 'Année Scolaire supprimé avec succès.'
message: 'Année Univesitaire supprimé avec succès.'
}
} catch (error) {
return error

8
database/Models/Parcours.js

@ -64,13 +64,13 @@ async function deletes(id) {
if (result.affectedRows === 0) {
return {
success: false,
message: 'Année Scolaire non trouvé.'
message: 'Année Univesitaire non trouvé.'
}
}
return {
success: true,
message: 'Année Scolaire supprimé avec succès.'
message: 'Année Univesitaire supprimé avec succès.'
}
} catch (error) {
return error
@ -86,13 +86,13 @@ async function updateparcour(id, nom, uniter, mention_id) {
if (result.affectedRows === 0) {
return {
success: false,
message: 'Année Scolaire non trouvé ou aucune modification effectuée.'
message: 'Année Univesitaire non trouvé ou aucune modification effectuée.'
}
}
return {
success: true,
message: 'Année Scolaire mis à jour avec succès.'
message: 'Année Univesitaire mis à jour avec succès.'
}
} catch (error) {
return error

4
database/database.backup.js

@ -2,9 +2,9 @@ const mysql = require('mysql2/promise')
const bcrypt = require('bcryptjs')
const pool = mysql.createPool({
host: '127.0.0.1',
host: '192.168.200.200',
user: 'root',
password: '',
password: 'stephane1313',
database: 'university',
waitForConnections: true,
connectionLimit: 10,

4
database/database.js

@ -2,9 +2,9 @@ const mysql = require('mysql2/promise')
const bcrypt = require('bcryptjs')
const pool = mysql.createPool({
host: '127.0.0.1',
host: '192.168.200.200',
user: 'root',
password: '',
password: 'stephane1313',
database: 'university',
waitForConnections: true,
connectionLimit: 10,

4
database/database2.js

@ -2,9 +2,9 @@ const mysql = require('mysql2/promise')
const bcrypt = require('bcryptjs')
const pool = mysql.createPool({
host: '127.0.0.1',
host: '192.168.200.200',
user: 'root',
password: '',
password: 'stephane1313',
database: 'university',
waitForConnections: true,
connectionLimit: 10,

4
database/function/System.js

@ -287,13 +287,13 @@ async function updateNessesaryTable(id, multiplicateur) {
if (result.affectedRows === 0) {
return {
success: false,
message: 'Année Scolaire non trouvé.'
message: 'Année universitaire non trouvé.'
}
}
return {
success: true,
message: 'Année Scolaire supprimé avec succès.'
message: 'Année universitaire supprimé avec succès.'
}
} catch (error) {
return error

8
src/renderer/src/components/AddAnneeScolaire.jsx

@ -98,7 +98,7 @@ const AddAnneeScolaire = () => {
{status === 200 ? (
<Typography style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
<img src={svgSuccess} alt="" width={50} height={50} />{' '}
<span>Année Scolaire insérer avec succes</span>
<span>Année Univesitaire insérer avec succes</span>
</Typography>
) : (
<Typography style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
@ -136,7 +136,7 @@ const AddAnneeScolaire = () => {
<div className={classe.h1style}>
<div className={classeHome.blockTitle}>
<h1 style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
<FaCalendarPlus /> Ajout Année Scolaire
<FaCalendarPlus /> Ajout Année Univesitaire
</h1>
<Link to={'#'} onClick={() => window.history.back()}>
<Button color="warning" variant="contained">
@ -170,12 +170,12 @@ const AddAnneeScolaire = () => {
}}
>
<h4 style={{ textAlign: 'center', padding: '0 0 3% 0' }}>
Creation de nouvelle Année Scolaire
Creation de nouvelle Année Univesitaire
</h4>
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<TextField
label={'Année Scolaire'}
label={'Année Univesitaire'}
name={'code'}
placeholder="2024-2025"
color="warning"

8
src/renderer/src/components/AddStudent.jsx

@ -409,7 +409,7 @@ const AddStudent = () => {
</Grid>
<Grid item xs={12} sm={6}>
<TextField
label="Prenom"
label="Prénom"
name="prenom"
fullWidth
size="small"
@ -503,13 +503,13 @@ const AddStudent = () => {
variant="outlined"
>
<InputLabel id="demo-select-small-label" color="warning">
Année Scolaire
Année Univesitaire
</InputLabel>
<Select
labelId="demo-select-small-label"
id="demo-select-small"
value={formData.annee_scolaire}
label="Année Scolaire"
label="Année Univesitaire"
color="warning"
size="small"
onChange={handleInputChange}
@ -521,7 +521,7 @@ const AddStudent = () => {
<FaCalendarAlt />
</InputAdornment>
}
label="Année Scolaire"
label="Année Univesitaire"
/>
}
sx={{

4
src/renderer/src/components/AnneeScolaire.jsx

@ -48,7 +48,7 @@ const AnneeScolaire = () => {
const [ids, setIds] = useState(0)
const column = [
{ field: 'code', headerName: 'Année Scolaire', width: 130 },
{ field: 'code', headerName: 'Année Univesitaire', width: 130 },
{ field: 'debut', headerName: 'Date de début', width: 130 },
{ field: 'fin', headerName: 'Date de fin', width: 130 },
{
@ -259,7 +259,7 @@ const AnneeScolaire = () => {
<div className={classe.h1style}>
<div className={classeHome.blockTitle}>
<h1 style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
<BsCalendar2Date /> Année Scolaire
<BsCalendar2Date /> Année Univesitaire
</h1>
<Link to={'/addanneescolaire'}>
<Button color="warning" variant="contained">

8
src/renderer/src/components/ExportEtudiants.jsx

@ -460,16 +460,16 @@ const ExportEtudiants = () => {
>
<MenuItem value={col.headerName}>{col.headerName}</MenuItem>
<MenuItem value={'nom'}>nom</MenuItem>
<MenuItem value={'prenom'}>prenom</MenuItem>
<MenuItem value={'prenom'}>prénom</MenuItem>
<MenuItem value={`niveau`}>niveau</MenuItem>
<MenuItem value={`date_naissance`}>date de naissance</MenuItem>
<MenuItem value={`annee_scolaire`}>année scolaire</MenuItem>
<MenuItem value={`annee_scolaire`}>Année Univesitaire</MenuItem>
<MenuItem value={`mention`}>mention</MenuItem>
<MenuItem value={`num_inscription`}>numéro d'inscription</MenuItem>
<MenuItem value={`nationalite`}>Nationaliter</MenuItem>
<MenuItem value={`nationalite`}>Nationalité</MenuItem>
<MenuItem value={`sexe`}>Sexe</MenuItem>
<MenuItem value={`cin`}>CIN</MenuItem>
<MenuItem value={`date_de_livraison`}>Date de livraison</MenuItem>
<MenuItem value={`date_de_livraison`}>Date de délivrance(CIN)</MenuItem>
<MenuItem value={`annee_baccalaureat`}>Année du baccalaureat</MenuItem>
<MenuItem value={`serie`}>Série</MenuItem>
<MenuItem value={`code_redoublement`}>Code redoublement</MenuItem>

4
src/renderer/src/components/Home.jsx

@ -151,12 +151,12 @@ const Home = () => {
sx={{ color: 'black', fontSize: '15px', textTransform: 'capitalize' }}
color="warning"
>
Année Scolaire
Année Univesitaire
</InputLabel>
<Select
labelId="demo-select-small-label"
id="demo-select-small"
label="Année Scolaire"
label="Année Univesitaire"
color="warning"
defaultValue={'general'}
onChange={FilterAnneeScolaire}

159
src/renderer/src/components/Login.jsx

@ -1,60 +1,113 @@
import { useRef, useState } from 'react'
// import { Container, Row, Col, Form, Button, Card, InputGroup } from 'react-bootstrap';
import { useRef, useState, useEffect } from 'react'
import { Container, Grid, Card, Typography, TextField, Button, InputAdornment } from '@mui/material'
import { FaUserCircle, FaLock, FaUser } from 'react-icons/fa'
import classe from '../assets/Login.module.css'
import { useAuthContext } from '../contexts/AuthContext'
import { Link } from 'react-router-dom'
import { Link, useNavigate } from 'react-router-dom'
import { ValidationLogin, invalidCredential } from './validation/Login'
const Login = () => {
/**
* token from the AuthContext in the context folder
*/
const { setToken } = useAuthContext()
/**
* hook to store our data from the input element
*/
const [username, setUsername] = useState()
const [password, setPassword] = useState()
/**
* ref for our username and password input and the error span
*/
const { token, setToken, setUser, isAuthenticated, isLoading } = useAuthContext()
const navigate = useNavigate()
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const [isSubmitting, setIsSubmitting] = useState(false)
const userNameRef = useRef()
const passwordRef = useRef()
const userNameError = useRef()
const passwordError = useRef()
/**
* function to send the data to the IPCRender
* and make login
*
* @param {any} e
*/
// Redirection si déjà authentifié
useEffect(() => {
if (!isLoading && isAuthenticated) {
console.log('Utilisateur déjà authentifié, redirection vers home')
navigate('/', { replace: true })
}
}, [isAuthenticated, isLoading, navigate])
const formLogin = async (e) => {
e.preventDefault()
if (isSubmitting) return
setIsSubmitting(true)
let validate = ValidationLogin(
userNameRef.current,
passwordRef.current,
userNameError.current,
passwordError.current
)
try {
const validate = ValidationLogin(
userNameRef.current,
passwordRef.current,
userNameError.current,
passwordError.current
)
if (validate) {
if (!validate) {
setIsSubmitting(false)
return
}
console.log('Tentative de connexion pour:', username)
const response = await window.allUser.login({ username, password })
console.log('Réponse login:', response)
if (response.success) {
// Redirect to main window
setToken(JSON.stringify(response.user))
// Extraire le token et les données utilisateur
const userData = response.user
// Essayer plusieurs sources pour le token
const userToken = response.user.token || response.token || response.user.access_token || response.access_token
console.log('Connexion réussie:', { userData, userToken })
console.log('Structure complète de response:', response)
if (!userToken) {
console.error('Aucun token trouvé dans la réponse!')
// Générer un token temporaire ou utiliser l'ID utilisateur
const tempToken = `temp_token_${userData.id}_${Date.now()}`
console.log('Utilisation d\'un token temporaire:', tempToken)
setUser(userData)
setToken(tempToken)
} else {
// Sauvegarder les données
setUser(userData)
setToken(userToken)
}
console.log('Redirection vers home...')
// Forcer la redirection avec un délai
setTimeout(() => {
navigate('/', { replace: true })
}, 100)
} else {
invalidCredential(userNameError.current, response.error)
console.error('Échec de la connexion:', response.error)
invalidCredential(userNameError.current, response.error || 'Erreur de connexion')
}
} catch (error) {
console.error('Erreur login :', error)
invalidCredential(userNameError.current, 'Erreur de connexion')
} finally {
setIsSubmitting(false)
}
}
// Afficher un loader pendant la vérification initiale
if (isLoading) {
return (
<Container
maxWidth={false}
sx={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}
>
<Typography>Chargement...</Typography>
</Container>
)
}
// Ne pas afficher le formulaire si déjà authentifié
if (isAuthenticated) {
return null
}
return (
<Container
maxWidth={false}
@ -63,7 +116,7 @@ const Login = () => {
>
<Grid container justifyContent="center">
<Grid item xs={12} md={6} lg={4}>
<Card className={`p-4 shadow ` + classe.cards} sx={{ padding: 4, boxShadow: 3 }}>
<Card className={`p-4 shadow ${classe.cards}`} sx={{ padding: 4, boxShadow: 3 }}>
<div style={{ textAlign: 'center', marginBottom: '1rem' }}>
<FaUserCircle size={60} color="dark" className="text-light" />
</div>
@ -78,6 +131,8 @@ const Login = () => {
fullWidth
placeholder="Nom d'utilisateur"
margin="normal"
value={username}
disabled={isSubmitting}
InputProps={{
startAdornment: (
<InputAdornment position="start">
@ -90,16 +145,13 @@ const Login = () => {
inputRef={userNameRef}
sx={{
'& .MuiOutlinedInput-root': {
'& fieldset': {
borderColor: 'white' // Set the border color when not focused
},
'&:hover fieldset': {
borderColor: 'rgb(156, 39, 176)' // Set the border color on hover
}
'& fieldset': { borderColor: 'white' },
'&:hover fieldset': { borderColor: 'rgb(156, 39, 176)' }
}
}}
/>
<span className="text-danger" ref={userNameError}></span>
<TextField
label="Mot de passe"
color="secondary"
@ -108,6 +160,8 @@ const Login = () => {
fullWidth
placeholder="Mot de passe"
margin="normal"
value={password}
disabled={isSubmitting}
className={classe.input}
InputProps={{
startAdornment: (
@ -120,25 +174,22 @@ const Login = () => {
inputRef={passwordRef}
sx={{
'& .MuiOutlinedInput-root': {
'& fieldset': {
borderColor: 'white' // Set the border color when not focused
},
'&:hover fieldset': {
borderColor: 'rgb(156, 39, 176)' // Set the border color on hover
}
'& fieldset': { borderColor: 'white' },
'&:hover fieldset': { borderColor: 'rgb(156, 39, 176)' }
}
}}
/>
<span ref={passwordError} className="text-danger"></span>
<Button
variant="contained"
color="secondary"
type="submit"
fullWidth
sx={{ marginTop: 2 }}
<Button
variant="contained"
color="secondary"
type="submit"
fullWidth
disabled={isSubmitting}
sx={{ mt: 2 }}
>
Se connecter
{isSubmitting ? 'Connexion...' : 'Se connecter'}
</Button>
<div style={{ display: 'flex', justifyContent: 'space-between', marginTop: '1rem' }}>
@ -154,4 +205,4 @@ const Login = () => {
)
}
export default Login
export default Login

6
src/renderer/src/components/ModalAddEtudiants.jsx

@ -154,7 +154,7 @@ const ModalAddEtudiants = ({ open, handleClose }) => {
</Grid>
<Grid item xs={12} sm={6}>
<TextField
label="Prenom"
label="Prénom"
name="prenom"
fullWidth
color="secondary"
@ -232,10 +232,10 @@ const ModalAddEtudiants = ({ open, handleClose }) => {
/>
</Grid>
{/* Année Scolaire and Numéro d'Inscription Fields */}
{/* Année Univesitaire and Numéro d'Inscription Fields */}
<Grid item xs={12} sm={6}>
<TextField
label="Année Scolaire"
label="Année Univesitaire"
name="annee_scolaire"
fullWidth
color="secondary"

4
src/renderer/src/components/ModalAddProf.jsx

@ -95,10 +95,10 @@ const ModalAddProf = ({ open, onClose, matiere_id, onSubmitSuccess }) => {
margin="normal"
required
name="prenom_enseignant"
label="Prenom du professeur"
label="Prénom du professeur"
type="text"
fullWidth
placeholder="Prenom du professeur"
placeholder="Prénom du professeur"
variant="outlined"
value={formData.prenom_enseignant}
color="warning"

6
src/renderer/src/components/ModalCertificate.jsx

@ -41,14 +41,14 @@ const ModalCertificate = ({ open, onClose, json }) => {
return (
<Dialog open={open} onClose={onClose}>
<form action="">
<DialogTitle>Informations sur l'élève</DialogTitle>
<DialogTitle>Informations sur l'étudiant</DialogTitle>
<DialogContent>
<TextField
autoFocus
margin="dense"
required
name="pere"
label="Père de l'élève"
label="Père de l'étudiant"
type="text"
fullWidth
variant="outlined"
@ -60,7 +60,7 @@ const ModalCertificate = ({ open, onClose, json }) => {
margin="dense"
name="mere"
required
label="Mère de l'élève"
label="Mère de l'étudiant"
type="text"
fullWidth
variant="outlined"

2
src/renderer/src/components/ModalExportFichr.jsx

@ -170,7 +170,7 @@ const ModalExportFichr = () => {
</tr>
<tr style={{ borderBottom: 'solid 1px gray' }}>
<th style={{ borderRight: 'solid 1px gray' }}>N°</th>
<th style={{ borderRight: 'solid 1px gray' }}>Nom et Prenom</th>
<th style={{ borderRight: 'solid 1px gray' }}>Nom et Prénom</th>
<th style={{ borderRight: 'solid 1px gray' }}>Mention</th>
<th>Emergement</th>
</tr>

2
src/renderer/src/components/ModalRecepice.jsx

@ -41,7 +41,7 @@ const ModalRecepice = ({ open, onClose, json }) => {
margin="dense"
required
name="nom"
label="Nom et prenom du chef de services"
label="Nom et prénom du chef de services"
type="text"
fullWidth
variant="outlined"

2
src/renderer/src/components/ModalStage.jsx

@ -57,7 +57,7 @@ const ModalStage = ({ open, onClose }) => {
margin="dense"
name="prenom"
required
label="Prenom du directeur"
label="Prénom du directeur"
type="text"
fullWidth
variant="outlined"

109
src/renderer/src/components/Noteclasse.jsx

@ -8,7 +8,7 @@ import { frFR } from '@mui/x-data-grid/locales'
import { createTheme, ThemeProvider } from '@mui/material/styles'
import { IoNewspaperOutline } from 'react-icons/io5'
import { IoMdReturnRight } from 'react-icons/io'
import { Button, Modal, Box } from '@mui/material'
import { Button, Modal, Box, Menu, MenuItem } from '@mui/material'
import { Tooltip } from 'react-tooltip'
import ReleverNotes from './ReleverNotes'
import { FaDownload } from 'react-icons/fa'
@ -50,12 +50,23 @@ const Noteclasse = () => {
}
function checkNull(params) {
console.log(params);
if (params == null || params == undefined) {
return null
}
return params
}
// MODIFICATION: Nouvelle fonction pour calculer la moyenne avec rattrapage
function compareSessionNotesForAverage(session1, session2) {
// Si il y a une session de rattrapage, utiliser la meilleure note
if (session2) {
return Math.max(session1, session2.note)
}
// Sinon utiliser la note normale
return session1
}
function compareSessionNotes(session1, session2) {
let notes
if (session2) {
@ -94,10 +105,10 @@ const Noteclasse = () => {
modelJson.mention = etudiants[index][j].mention_id
modelJson.anneescolaire = etudiants[index][j].annee_scolaire
// console.log(checkNull(session[index][j]));
// MODIFICATION: Utiliser la meilleure note (rattrapage si existe) pour la moyenne générale
if (session[index]) {
note +=
compareSessionNotes(etudiants[index][j].note, checkNull(session[index][j])) *
compareSessionNotesForAverage(etudiants[index][j].note, checkNull(session[index][j])) *
etudiants[index][j].credit
} else {
note += etudiants[index][j].note * etudiants[index][j].credit
@ -113,15 +124,15 @@ const Noteclasse = () => {
}
function checkNumberSession(id) {
let sessionNumber
let sessionNumber = 1
for (let index = 0; index < session.length; index++) {
for (let j = 0; j < session[index].length; j++) {
if (session[index][j].etudiant_id == id) {
sessionNumber = 2
} else {
sessionNumber = 1
break
}
}
if (sessionNumber === 2) break
}
return sessionNumber
}
@ -147,9 +158,29 @@ const Noteclasse = () => {
const paginationModel = { page: 0, pageSize: 5 }
// États pour le menu déroulant
const [anchorEl, setAnchorEl] = useState(null)
const [selectedStudentId, setSelectedStudentId] = useState(null)
const open = Boolean(anchorEl)
const handleMenuClick = (event, studentId) => {
setAnchorEl(event.currentTarget)
setSelectedStudentId(studentId)
}
const handleMenuClose = () => {
setAnchorEl(null)
setSelectedStudentId(null)
}
const handleSessionTypeSelect = (sessionType) => {
sendData(selectedStudentId, sessionType)
handleMenuClose()
}
const columns = [
{ field: 'nom', headerName: 'Nom', width: 170 },
{ field: 'prenom', headerName: 'Prenom', width: 160 },
{ field: 'prenom', headerName: 'Prénom', width: 160 },
{ field: 'session', headerName: 'Nombre de Session', width: 180 },
{ field: 'mention', headerName: 'Mention', width: 180 },
{ field: 'moyenne', headerName: 'Moyenne Général', width: 160 },
@ -171,19 +202,21 @@ const Noteclasse = () => {
flex: 1,
renderCell: (params) => (
<div style={{ display: 'flex', gap: '10px' }}>
<Link to={`#`} onClick={() => sendData(params.value)}>
{/* <IoEyeSharp style={{fontSize:"20px", color:"white"}} /> */}
<Button color="warning" variant="contained" className={`update${params.value}`}>
<IoNewspaperOutline style={{ fontSize: '20px', color: 'white' }} />
</Button>
<Tooltip
anchorSelect={`.update${params.value}`}
style={{ fontSize: '13px', zIndex: 22 }}
place="bottom-end"
>
Imprimer un relevé de notes
</Tooltip>
</Link>
<Button
color="warning"
variant="contained"
className={`update${params.value}`}
onClick={(event) => handleMenuClick(event, params.value)}
>
<IoNewspaperOutline style={{ fontSize: '20px', color: 'white' }} />
</Button>
<Tooltip
anchorSelect={`.update${params.value}`}
style={{ fontSize: '13px', zIndex: 22 }}
place="bottom-end"
>
Imprimer un relevé de notes
</Tooltip>
</div>
)
}
@ -205,15 +238,18 @@ const Noteclasse = () => {
const [form, setForm] = useState({
id: '',
niveau: '',
anneescolaire: ''
anneescolaire: '',
sessionType: 'ensemble' // Par défaut
})
const [selectedId, setSelectedId] = useState(null) // Store id dynamically
const sendData = (id) => {
const sendData = (id, sessionType = 'ensemble') => {
setSelectedId(id)
// if (selectedId !== null) {
setOpenCart(true)
// }
setForm(prevForm => ({
...prevForm,
sessionType: sessionType
}))
setOpenCart(true)
}
useEffect(() => {
@ -229,7 +265,9 @@ const Noteclasse = () => {
}
}
}, [openCard, selectedId])
console.log(form)
const downloadButton = () => {
setBolll(true)
}
@ -265,6 +303,7 @@ const Noteclasse = () => {
id={form.id}
anneescolaire={scolaire}
niveau={form.niveau}
sessionType={form.sessionType}
refs={bolll}
/>
<Button
@ -298,6 +337,24 @@ const Noteclasse = () => {
return (
<div className={classe.mainHome}>
{modalReleverNotes()}
{/* Menu pour sélectionner le type de session */}
<Menu
anchorEl={anchorEl}
open={open}
onClose={handleMenuClose}
MenuListProps={{
'aria-labelledby': 'session-button',
}}
>
<MenuItem onClick={() => handleSessionTypeSelect('normale')}>
Session Normale
</MenuItem>
<MenuItem onClick={() => handleSessionTypeSelect('ensemble')}>
Session Rattrapage
</MenuItem>
</Menu>
<div className={classeHome.header}>
<div className={classe.h1style}>
<div className={classeHome.blockTitle}>
@ -369,4 +426,4 @@ const Noteclasse = () => {
)
}
export default Noteclasse
export default Noteclasse

2
src/renderer/src/components/Notes.jsx

@ -34,7 +34,7 @@ const Notes = () => {
const columns = [
{ field: 'niveau', headerName: 'Niveau', width: 170 },
{ field: 'annee_scolaire', headerName: 'Année scolaire', width: 160 },
{ field: 'annee_scolaire', headerName: 'Année Univesitaire', width: 160 },
// { field:'moyenne', headerName:'Moyenne de classe', width:160},
{
field: 'action',

208
src/renderer/src/components/Param.jsx

@ -1,33 +1,35 @@
import { useState } from 'react'
import { Box, Button, InputAdornment, TextField, Grid, Modal, Typography } from '@mui/material'
import { FaEnvelope, FaLock, FaUser } from 'react-icons/fa'
import { GrConfigure } from 'react-icons/gr'
import { Link } from 'react-router-dom'
import { useAuthContext } from '../contexts/AuthContext'
import IpConfig from './IpConfig'
import classe from '../assets/AllStyleComponents.module.css'
import img from '../assets/para.png'
import classeHome from '../assets/Home.module.css'
import { Box, Button, InputAdornment, TextField, Grid, Modal, Typography } from '@mui/material'
import classeAdd from '../assets/AddStudent.module.css'
import { useAuthContext } from '../contexts/AuthContext'
import { FaEnvelope, FaLock, FaUser } from 'react-icons/fa'
import img from '../assets/para.png'
import svgSuccess from '../assets/success.svg'
import svgError from '../assets/error.svg'
import { Link } from 'react-router-dom'
import { GrConfigure } from 'react-icons/gr'
import IpConfig from './IpConfig'
import { useNavigate} from 'react-router-dom'
const Setting = () => {
const { token, setToken } = useAuthContext()
const userInfo = JSON.parse(token)
const { user, setUser, token, setToken } = useAuthContext()
const navigate = useNavigate()
if (!user) {
navigate('/login');
return <div>Chargement...</div>
}
// Initialisation du formulaire avec les infos de l'utilisateur
const [formData, setFormData] = useState({
username: userInfo.username,
email: userInfo.email,
username: user.username,
email: user.email,
password: '',
id: userInfo.id
id: user.id
})
/**
* function to set the data in state
* @param {*} e
*/
// Gestion des inputs
const handleInputChange = (e) => {
const { name, value } = e.target
setFormData((prevData) => ({
@ -36,49 +38,40 @@ const Setting = () => {
}))
}
// Gestion de l'envoi du formulaire
const handleSubmit = async (e) => {
e.preventDefault()
// Handle form submission logic
const response = await window.allUser.updateUsers(formData)
console.log(response)
if (response.success) {
setOpen(true)
setCode(200)
setToken(JSON.stringify(response.users))
setFormData({
username: response.username,
email: response.email,
password: '',
id: userInfo.id
})
} else {
setCode(422)
try {
const response = await window.allUser.updateUsers(formData)
if (response.success) {
setOpen(true)
setCode(200)
setUser(response.user) // Mettre à jour user
setToken(response.user.token) // Mettre à jour token si besoin
setFormData({
username: response.user.username,
email: response.user.email,
password: '',
id: response.user.id
})
} else {
setCode(422)
setOpen(true)
}
} catch (error) {
console.error('Erreur lors de la mise à jour:', error)
setCode(500)
setOpen(true)
}
}
/**
* hook to open modal
*/
// Modal
const [open, setOpen] = useState(false)
const [code, setCode] = useState(200)
/**
* function to close modal
*/
const handleClose = () => setOpen(false)
/**
* function to return the view Modal
*
* @returns {JSX}
*/
const modals = () => (
<Modal
open={open}
onClose={handleClose}
aria-labelledby="modal-title"
aria-describedby="modal-description"
>
<Modal open={open} onClose={handleClose} aria-labelledby="modal-title">
<Box
sx={{
position: 'absolute',
@ -91,30 +84,22 @@ const Setting = () => {
p: 4
}}
>
{code == 422 ? (
<Typography
style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '10px' }}
>
<img src={svgError} alt="" width={50} height={50} />{' '}
<span style={{ marginLeft: '10px' }}>Email déjà pris</span>
{code === 422 ? (
<Typography sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '10px' }}>
<img src={svgError} alt="Erreur" width={50} height={50} />
<span>Email déjà pris</span>
</Typography>
) : code === 500 ? (
<Typography sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '10px' }}>
<span>Une erreur est survenue</span>
</Typography>
) : (
<Typography
style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '10px' }}
>
<img src={svgSuccess} alt="" width={100} height={100} />{' '}
<span>Modification a été effectuée avec succès</span>
<Typography sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '10px' }}>
<img src={svgSuccess} alt="Succès" width={100} height={100} />
<span>Modification effectuée avec succès</span>
</Typography>
)}
<Box
sx={{
marginTop: '2%',
display: 'flex',
gap: '20px',
alignItems: 'end',
justifyContent: 'flex-end'
}}
>
<Box sx={{ mt: 2, display: 'flex', justifyContent: 'flex-end' }}>
<Button onClick={handleClose} color="warning" variant="contained">
OK
</Button>
@ -123,10 +108,10 @@ const Setting = () => {
</Modal>
)
const [openConfig, setOpenCOnfig] = useState(false)
const onCloseConfig = () => setOpenCOnfig(false)
const openCOnfigFunction = () => setOpenCOnfig(true)
// IP Config
const [openConfig, setOpenConfig] = useState(false)
const onCloseConfig = () => setOpenConfig(false)
const openConfigFunction = () => setOpenConfig(true)
return (
<div className={classe.mainHome}>
@ -135,8 +120,8 @@ const Setting = () => {
<div className={classeHome.header}>
<div className={classe.h1style}>
<div className={classeHome.blockTitle}>
<h1>setting</h1>
<Link to={'#'} onClick={openCOnfigFunction}>
<h1>Settings</h1>
<Link to="#" onClick={openConfigFunction}>
<Button color="warning" variant="contained">
<GrConfigure style={{ fontSize: '20px' }} /> IP configuration
</Button>
@ -144,7 +129,7 @@ const Setting = () => {
</div>
</div>
</div>
{/* contenu */}
<div className={classeHome.contenaire}>
<div className={classeAdd.boxEtudiantsCard}>
<Box
@ -162,22 +147,15 @@ const Setting = () => {
>
<Box
sx={{
marginTop: '5%',
mt: '5%',
display: 'flex',
gap: '10px',
alignItems: 'start',
flexDirection: 'column',
fontSize: 16,
fontFamily: 'sans-serif',
justifyContent: 'flex-end'
alignItems: 'center',
gap: '10px'
}}
>
<span style={{ display: 'flex', marginLeft: '40%' }}>
<img src={img} alt="" height={150} width={150} />
</span>
<form onSubmit={handleSubmit} style={{ marginTop: '5%' }}>
{/* */}
<img src={img} alt="avatar" width={150} height={150} />
<form onSubmit={handleSubmit} style={{ width: '100%', marginTop: '5%' }}>
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<TextField
@ -189,18 +167,7 @@ const Setting = () => {
onChange={handleInputChange}
required
InputProps={{
startAdornment: (
<InputAdornment position="start">
<FaUser />
</InputAdornment>
)
}}
sx={{
'& .MuiOutlinedInput-root': {
'&:hover fieldset': {
borderColor: '#ff9800' // Set the border color on hover
}
}
startAdornment: <InputAdornment position="start"><FaUser /></InputAdornment>
}}
/>
</Grid>
@ -214,23 +181,11 @@ const Setting = () => {
value={formData.email}
onChange={handleInputChange}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<FaEnvelope />
</InputAdornment>
)
}}
sx={{
'& .MuiOutlinedInput-root': {
'&:hover fieldset': {
borderColor: '#ff9800' // Set the border color on hover
}
}
startAdornment: <InputAdornment position="start"><FaEnvelope /></InputAdornment>
}}
/>
</Grid>
{/* matieres Mecanique general */}
<Grid item xs={12} sm={12}>
<Grid item xs={12}>
<TextField
label="Mot de passe"
name="password"
@ -240,30 +195,13 @@ const Setting = () => {
value={formData.password}
onChange={handleInputChange}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<FaLock />
</InputAdornment>
)
}}
sx={{
'& .MuiOutlinedInput-root': {
'&:hover fieldset': {
borderColor: '#ff9800' // Set the border color on hover
}
}
startAdornment: <InputAdornment position="start"><FaLock /></InputAdornment>
}}
/>
</Grid>
{/* Matieres Resistance Materiaux */}
{/* Submit Button */}
<Grid
item
xs={12}
style={{ display: 'flex', gap: '30px', justifyContent: 'flex-end' }}
>
<Grid item xs={12} sx={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button type="submit" color="warning" variant="contained">
Enregister
Enregistrer
</Button>
</Grid>
</Grid>

263
src/renderer/src/components/ReleverNotes.jsx

@ -10,11 +10,16 @@ import dayjs from 'dayjs'
import getSemestre from './function/GetSemestre'
import { descisionJury, getmentionAfterNotes } from './function/FonctionRelever'
const ReleverNotes = ({ id, anneescolaire, niveau, refs }) => {
const ReleverNotes = ({ id, anneescolaire, niveau, sessionType = 'ensemble', refs }) => {
const [etudiant, setEtudiant] = useState([])
const [matieres, setMatieres] = useState([])
const [notes, setNotes] = useState([])
// Fonction pour vérifier si les crédits doivent être affichés
const shouldShowCredits = () => {
return niveau !== 'L1' && niveau !== 'L2'
}
const handleDownloadPDF = async () => {
const input = Telever.current
@ -166,9 +171,19 @@ const ReleverNotes = ({ id, anneescolaire, niveau, refs }) => {
return acc
}, {})
const compareMoyenne = (normal, rattrapage) => {
const note = Math.max(Number(normal), Number(rattrapage))
return note >= 10 ? 'Admis' : 'Ajourné'
// MODIFICATION: Fonction compareMoyenne mise à jour
const compareMoyenne = (normal, rattrapage, sessionType) => {
if (sessionType === 'normale') {
// Pour session normale: toujours évaluer selon la note normale uniquement
return Number(normal) >= 10 ? 'Admis' : 'Ajourné'
} else if (sessionType === 'rattrapage') {
// Pour session rattrapage: évaluer selon la note de rattrapage
return Number(rattrapage) >= 10 ? 'Admis' : 'Ajourné'
} else {
// Pour session ensemble: prendre la meilleure des deux notes
const bestNote = Math.max(Number(normal), Number(rattrapage))
return bestNote >= 10 ? 'Admis' : 'Ajourné'
}
}
const TbodyContent = () => {
@ -219,7 +234,6 @@ const ReleverNotes = ({ id, anneescolaire, niveau, refs }) => {
fontWeight: 'bold',
textAlign: 'center',
borderRight: 'solid 1px black',
// borderBottom: 'solid 1px black',
borderTop: 'solid 1px black'
}}
>
@ -231,18 +245,29 @@ const ReleverNotes = ({ id, anneescolaire, niveau, refs }) => {
<td style={{ borderRight: 'solid 1px black', borderTop: 'solid 1px black' }}>
{matiere.nom}
</td>
<td style={{ borderRight: 'solid 1px black', borderTop: 'solid 1px black' }}>
{matiere.credit}
</td>
<td style={{ borderRight: 'solid 1px black', borderTop: 'solid 1px black' }}>
{matiere.note}
</td>
<td style={{ borderRight: 'solid 1px black', borderTop: 'solid 1px black' }}>
{matiere.credit}
</td>
<td style={{ borderRight: 'solid 1px black', borderTop: 'solid 1px black' }}>
{matiere.noterepech}
</td>
{/* Affichage conditionnel des colonnes selon le type de session */}
{sessionType !== 'rattrapage' && (
<>
<td style={{ borderRight: 'solid 1px black', borderTop: 'solid 1px black' }}>
{matiere.credit}
</td>
<td style={{ borderRight: 'solid 1px black', borderTop: 'solid 1px black' }}>
{matiere.note}
</td>
</>
)}
{sessionType !== 'normale' && (
<>
<td style={{ borderRight: 'solid 1px black', borderTop: 'solid 1px black' }}>
{matiere.credit}
</td>
<td style={{ borderRight: 'solid 1px black', borderTop: 'solid 1px black' }}>
{matiere.noterepech}
</td>
</>
)}
{/* Display the comparison value only once */}
{matiereIndex === 0 && (
@ -255,7 +280,6 @@ const ReleverNotes = ({ id, anneescolaire, niveau, refs }) => {
borderTop: 'solid 1px black'
}}
>
{/* Replace 'hgh' with your logic for displaying the comparison */}
{compareMoyenne(
(
matieres.reduce((total, matiere) => total + matiere.note, 0) /
@ -264,7 +288,8 @@ const ReleverNotes = ({ id, anneescolaire, niveau, refs }) => {
(
matieres.reduce((total, matiere) => total + matiere.noterepech, 0) /
matieres.length
).toFixed(2)
).toFixed(2),
sessionType // MODIFICATION: Passer le sessionType
)}
</td>
)}
@ -288,57 +313,65 @@ const ReleverNotes = ({ id, anneescolaire, niveau, refs }) => {
>
Total de Credit et Moyenne des Notes
</td>
<td
style={{
textAlign: 'center',
fontWeight: 'bold',
borderRight: 'solid 1px black',
borderTop: 'solid 1px black'
}}
>
{/* Calculate Total de Credit */}
{matieres.reduce((total, matiere) => total + matiere.credit, 0)}
</td>
<td
style={{
textAlign: 'center',
fontWeight: 'bold',
borderRight: 'solid 1px black',
borderTop: 'solid 1px black'
}}
className="moyenneNotes"
>
{/* Calculate Moyenne des Notes */}
{(
matieres.reduce((total, matiere) => total + matiere.note, 0) /
matieres.length
).toFixed(2)}{' '}
{/* Format to 2 decimal places */}
</td>
<td
style={{
textAlign: 'center',
fontWeight: 'bold',
borderTop: 'solid 1px black',
borderRight: 'solid 1px black'
}}
>
{matieres.reduce((total, matiere) => total + matiere.credit, 0)}
</td>
<td
style={{
textAlign: 'center',
fontWeight: 'bold',
borderRight: 'solid 1px black',
borderTop: 'solid 1px black'
}}
className="moyenneNotesRattrapage"
>
{(
matieres.reduce((total, matiere) => total + matiere.noterepech, 0) /
matieres.length
).toFixed(2)}
</td>
{sessionType !== 'rattrapage' && (
<>
<td
style={{
textAlign: 'center',
fontWeight: 'bold',
borderRight: 'solid 1px black',
borderTop: 'solid 1px black'
}}
>
{matieres.reduce((total, matiere) => total + matiere.credit, 0)}
</td>
<td
style={{
textAlign: 'center',
fontWeight: 'bold',
borderRight: 'solid 1px black',
borderTop: 'solid 1px black'
}}
className="moyenneNotes"
>
{(
matieres.reduce((total, matiere) => total + matiere.note, 0) /
matieres.length
).toFixed(2)}
</td>
</>
)}
{sessionType !== 'normale' && (
<>
<td
style={{
textAlign: 'center',
fontWeight: 'bold',
borderTop: 'solid 1px black',
borderRight: 'solid 1px black'
}}
>
{matieres.reduce((total, matiere) => total + matiere.credit, 0)}
</td>
<td
style={{
textAlign: 'center',
fontWeight: 'bold',
borderRight: 'solid 1px black',
borderTop: 'solid 1px black'
}}
className="moyenneNotesRattrapage"
>
{(
matieres.reduce((total, matiere) => total + matiere.noterepech, 0) /
matieres.length
).toFixed(2)}
</td>
</>
)}
<td
style={{
textAlign: 'center',
@ -357,6 +390,7 @@ const ReleverNotes = ({ id, anneescolaire, niveau, refs }) => {
)
}
// MODIFICATION: Fonction totalNotes mise à jour pour tenir compte du sessionType
const totalNotes = () => {
let totalNotes = document.querySelectorAll('.moyenneNotes')
let totalNotesRepech = document.querySelectorAll('.moyenneNotesRattrapage')
@ -365,25 +399,29 @@ const ReleverNotes = ({ id, anneescolaire, niveau, refs }) => {
let TotalNoteNumberRepech = 0
totalNotes.forEach((notes) => {
TotalNoteNumber += Number(notes.textContent / totalNotes.length)
// console.log(notes.textContent);
TotalNoteNumber += Number(notes.textContent) / totalNotes.length
})
totalNotesRepech.forEach((notes) => {
TotalNoteNumberRepech += Number(notes.textContent / totalNotes.length)
// console.log(notes.textContent);
TotalNoteNumberRepech += Number(notes.textContent) / totalNotesRepech.length
})
let note = Math.max(TotalNoteNumber, TotalNoteNumberRepech)
return note
// Retourner la note selon le type de session
if (sessionType === 'normale') {
return TotalNoteNumber
} else if (sessionType === 'rattrapage') {
return TotalNoteNumberRepech
} else {
// Pour 'ensemble', prendre la meilleure note
return Math.max(TotalNoteNumber, TotalNoteNumberRepech)
}
}
const [note, setNote] = useState(0)
useEffect(() => {
setNote(totalNotes())
}, [TbodyContent])
}, [TbodyContent, sessionType])
return (
<div className={classe.mainHome}>
@ -391,9 +429,8 @@ const ReleverNotes = ({ id, anneescolaire, niveau, refs }) => {
<div style={{ display: 'flex', justifyContent: 'center' }}>
<Paper
sx={{
// width: "100%",
height: 'auto', // Auto height to make the grid responsive
minHeight: 500, // Ensures a minimum height
height: 'auto',
minHeight: 500,
display: 'flex',
padding: '1%',
width: '70%',
@ -425,7 +462,7 @@ const ReleverNotes = ({ id, anneescolaire, niveau, refs }) => {
</span>
<br />
<span>
<b>Prenom</b>
<b>Prénom</b>
</span>
<br />
<span>
@ -480,7 +517,7 @@ const ReleverNotes = ({ id, anneescolaire, niveau, refs }) => {
<tr style={{ borderTop: 'solid 1px black', textAlign: 'center' }}>
<th colSpan={3}></th>
<th
colSpan={4}
colSpan={sessionType === 'ensemble' ? 4 : 2}
style={{
background: '#bdbcbc',
borderLeft: 'solid 1px black',
@ -495,18 +532,25 @@ const ReleverNotes = ({ id, anneescolaire, niveau, refs }) => {
<th style={{ borderLeft: 'solid 1px black' }}></th>
<th style={{ borderLeft: 'solid 1px black' }}></th>
<th style={{ borderLeft: 'solid 1px black' }}></th>
<th
colSpan={2}
style={{ background: '#bdbcbc', borderLeft: 'solid 1px black' }}
>
Normale
</th>
<th
colSpan={2}
style={{ background: '#bdbcbc', borderLeft: 'solid 1px black' }}
>
Rattrapage
</th>
{sessionType !== 'rattrapage' && (
<th
colSpan={shouldShowCredits() ? 2 : 1}
style={{ background: '#bdbcbc', borderLeft: 'solid 1px black' }}
>
Normale
</th>
)}
{sessionType !== 'normale' && (
<th
colSpan={shouldShowCredits() ? 2 : 1}
style={{ background: '#bdbcbc', borderLeft: 'solid 1px black' }}
>
Rattrapage
</th>
)}
<th
style={{ borderLeft: 'solid 1px black', borderRight: 'solid 1px black' }}
></th>
@ -514,7 +558,6 @@ const ReleverNotes = ({ id, anneescolaire, niveau, refs }) => {
<tr
style={{
borderTop: 'solid 1px black',
// borderBottom: 'solid 1px black',
background: '#bdbcbc',
textAlign: 'center'
}}
@ -524,10 +567,21 @@ const ReleverNotes = ({ id, anneescolaire, niveau, refs }) => {
</th>
<th style={{ borderLeft: 'solid 1px black' }}>UE</th>
<th style={{ borderLeft: 'solid 1px black' }}>EC</th>
<th style={{ borderLeft: 'solid 1px black', padding: '0 5px' }}>crédit</th>
<th style={{ borderLeft: 'solid 1px black', padding: '0 5px' }}>Notes</th>
<th style={{ borderLeft: 'solid 1px black', padding: '0 5px' }}>crédit</th>
<th style={{ borderLeft: 'solid 1px black', padding: '0 5px' }}>Notes</th>
{sessionType !== 'rattrapage' && (
<>
<th style={{ borderLeft: 'solid 1px black', padding: '0 5px' }}>crédit</th>
<th style={{ borderLeft: 'solid 1px black', padding: '0 5px' }}>Notes</th>
</>
)}
{sessionType !== 'normale' && (
<>
<th style={{ borderLeft: 'solid 1px black', padding: '0 5px' }}>crédit</th>
<th style={{ borderLeft: 'solid 1px black', padding: '0 5px' }}>Notes</th>
</>
)}
<th style={{ borderLeft: 'solid 1px black', borderRight: 'solid 1px black' }}>
Observation
</th>
@ -548,7 +602,7 @@ const ReleverNotes = ({ id, anneescolaire, niveau, refs }) => {
</td>
<td style={{ borderRight: 'solid 1px black' }}>{note.toFixed(2)}</td>
<td style={{ borderRight: 'solid 1px black' }}>/20</td>
<td colSpan={4}></td>
<td colSpan={sessionType === 'ensemble' ? 3 : 2}></td>
</tr>
<tr style={{ border: 'solid 1px black' }}>
<td
@ -562,11 +616,8 @@ const ReleverNotes = ({ id, anneescolaire, niveau, refs }) => {
Mention:{' '}
<span style={{ marginLeft: '3%' }}>{getmentionAfterNotes(note)}</span>
</td>
<td colSpan={5} style={{ textAlign: 'left', paddingLeft: '1%' }}>
<td colSpan={sessionType === 'ensemble' ? 4 : 3} style={{ textAlign: 'left', paddingLeft: '1%' }}>
Décision du Jury:{' '}
<span style={{ marginLeft: '3%' }}>
{descisionJury(note, etudiant.niveau)}
</span>
</td>
</tr>
</tbody>
@ -591,4 +642,4 @@ const ReleverNotes = ({ id, anneescolaire, niveau, refs }) => {
)
}
export default ReleverNotes
export default ReleverNotes

562
src/renderer/src/components/Resultat.jsx

@ -3,7 +3,7 @@ import { useParams, Link } from 'react-router-dom'
import classe from '../assets/AllStyleComponents.module.css'
import classeHome from '../assets/Home.module.css'
import Paper from '@mui/material/Paper'
import { Button, Modal, Box } from '@mui/material'
import { Button, Modal, Box, Tabs, Tab, Select, MenuItem, FormControl, InputLabel } from '@mui/material'
import { IoMdReturnRight } from 'react-icons/io'
import jsPDF from 'jspdf'
import autoTable from 'jspdf-autotable'
@ -20,10 +20,18 @@ const Resultat = () => {
const [etudiants, setEtudiants] = useState([])
const [mention, setMention] = useState([])
const [session, setSession] = useState([])
const [tabValue, setTabValue] = useState(0)
// États pour les sélections
const [selectedMatiere, setSelectedMatiere] = useState('')
const [selectedUE, setSelectedUE] = useState('')
const [availableMatieres, setAvailableMatieres] = useState([])
const [availableUEs, setAvailableUEs] = useState([])
useEffect(() => {
window.notes.getMoyenne(formData).then((response) => {
setEtudiants(response)
extractMatieresAndUEs(response)
})
window.noteRepech.getMoyenneRepech(formData).then((response) => {
setSession(response)
@ -33,6 +41,28 @@ const Resultat = () => {
})
}, [])
// Fonction pour extraire les matières et UEs disponibles
const extractMatieresAndUEs = (data) => {
const matieres = new Set()
const ues = new Set()
for (let index = 0; index < data.length; index++) {
for (let j = 0; j < data[index].length; j++) {
const matiere = data[index][j].matiere || `Matière ${j + 1}`
const ue = data[index][j].ue || `UE${Math.floor(j / 2) + 1}`
matieres.add(matiere)
ues.add(ue)
}
}
setAvailableMatieres(Array.from(matieres))
setAvailableUEs(Array.from(ues))
// Sélectionner la première matière et UE par défaut
if (matieres.size > 0) setSelectedMatiere(Array.from(matieres)[0])
if (ues.size > 0) setSelectedUE(Array.from(ues)[0])
}
let dataToMap = []
function returnmention(id) {
@ -45,6 +75,18 @@ const Resultat = () => {
return mentions
}
// Fonction pour déterminer la mention selon la moyenne
function getMentionFromMoyenne(moyenne) {
const moy = parseFloat(moyenne)
if (moy >= 18) return 'Excellent'
if (moy >= 16) return 'Très Bien'
if (moy >= 14) return 'Bien'
if (moy >= 12) return 'Assez Bien'
if (moy >= 10) return 'Passable'
if (moy >= 7) return 'Autorisé à redoubler'
return 'Remise à la famille'
}
function checkNull(params) {
if (params == null || params == undefined) {
return null
@ -52,51 +94,6 @@ const Resultat = () => {
return params
}
const print = () => {
const generatePDF = () => {
try {
const pdf = new jsPDF({
orientation: 'portrait',
unit: 'mm',
format: 'a4'
})
pdf.addImage(logoRelerev1, 'PNG', 10, 5, 40, 20)
pdf.addImage(logoRelerev2, 'PNG', 175, 5, 30, 30)
// Ajouter le texte entre les logos
pdf.setFontSize(10)
pdf.text('REPOBLIKAN\'I MADAGASIKARA', 105, 10, { align: 'center' })
pdf.text('Fitiavana-Tanindrazana-Fandrosoana', 105, 14, { align: 'center' })
pdf.text('********************', 105, 18, { align: 'center' })
pdf.text('MINISTÈRE DE L\'ENSEIGNEMENT SUPÉRIEUR', 105, 22, { align: 'center' })
pdf.text('ET DE LA RECHERCHE SCIENTIFIQUE', 105, 26, { align: 'center' })
pdf.text('********************', 105, 30, { align: 'center' })
pdf.text('UNIVERSITÉ DE TOAMASINA', 105, 34, { align: 'center' })
pdf.text('ÉCOLE SUPÉRIEURE POLYTECHNIQUE', 105, 38, { align: 'center' })
// Select the table
autoTable(pdf, {
html: '#myTable2',
startY: 50, // décalé vers le bas pour laisser la place aux logos et texte
theme: 'grid',
headStyles: {
fillColor: 'gray',
halign: 'center',
fontStyle: 'bold',
textColor: 'black'
},
styles: { fontSize: 8, cellPadding: 2, halign: 'center' }
})
pdf.save(`Resultat-${niveau}-${scolaire}.pdf`)
} catch (error) {
console.error('Error generating PDF:', error)
}
}
generatePDF()
}
function compareSessionNotes(session1, session2) {
let notes
if (session2) {
@ -111,12 +108,13 @@ const Resultat = () => {
return notes
}
// Traitement des données pour résultat définitif - INCLUANT TOUS LES ÉTUDIANTS
for (let index = 0; index < etudiants.length; index++) {
let total = 0
let note = 0
let totalCredit = 0
let hasValidNotes = false
// Create a new object for each student
let modelJson = {
id: '',
nom: '',
@ -135,29 +133,389 @@ const Resultat = () => {
modelJson.mention = etudiants[index][j].mention_id
modelJson.anneescolaire = etudiants[index][j].annee_scolaire
// console.log(checkNull(session[index][j]));
let currentNote = etudiants[index][j].note
if (session[index]) {
note +=
compareSessionNotes(etudiants[index][j].note, checkNull(session[index][j])) *
etudiants[index][j].credit
} else {
note += etudiants[index][j].note * etudiants[index][j].credit
currentNote = compareSessionNotes(etudiants[index][j].note, checkNull(session[index][j]))
}
totalCredit += etudiants[index][j].credit
}
total = note / totalCredit
modelJson.moyenne = total.toFixed(2)
// Vérifier si l'étudiant a des notes valides
if (currentNote != null && currentNote != undefined && !isNaN(currentNote)) {
note += currentNote * etudiants[index][j].credit
totalCredit += etudiants[index][j].credit
hasValidNotes = true
}
}
// Add the new object to the array
// Calculer la moyenne même si certaines notes manquent
if (hasValidNotes && totalCredit > 0) {
total = note / totalCredit
modelJson.moyenne = total.toFixed(2)
} else {
modelJson.moyenne = 'N/A'
}
dataToMap.push(modelJson)
}
const sortedStudents = dataToMap
.filter((student) => parseFloat(student.moyenne) >= 10)
.sort((a, b) => parseFloat(b.moyenne) - parseFloat(a.moyenne))
// Fonction pour obtenir les résultats par matière sélectionnée
const getResultsByMatiere = () => {
const results = []
for (let index = 0; index < etudiants.length; index++) {
for (let j = 0; j < etudiants[index].length; j++) {
const matiere = etudiants[index][j].matiere || `Matière ${j + 1}`
if (matiere === selectedMatiere) {
let finalNote = etudiants[index][j].note
if (session[index] && session[index][j]) {
finalNote = compareSessionNotes(etudiants[index][j].note, session[index][j])
}
console.log(sortedStudents)
results.push({
id: etudiants[index][j].etudiant_id,
nom: etudiants[index][j].nom,
prenom: etudiants[index][j].prenom,
note: finalNote != null ? finalNote.toFixed(2) : 'N/A',
credit: etudiants[index][j].credit,
mention: returnmention(etudiants[index][j].mention_id)
})
}
}
}
return results.sort((a, b) => {
const noteA = a.note === 'N/A' ? -1 : parseFloat(a.note)
const noteB = b.note === 'N/A' ? -1 : parseFloat(b.note)
return noteB - noteA
})
}
// Fonction pour obtenir les résultats par UE sélectionnée
const getResultsByUE = () => {
const groupedStudents = {}
const matieresInUE = new Set()
// Grouper les étudiants et collecter les matières de l'UE
for (let index = 0; index < etudiants.length; index++) {
for (let j = 0; j < etudiants[index].length; j++) {
const ue = etudiants[index][j].ue || `UE${Math.floor(j / 2) + 1}`
const matiere = etudiants[index][j].matiere || `Matière ${j + 1}`
if (ue === selectedUE) {
matieresInUE.add(matiere)
const etudiantId = etudiants[index][j].etudiant_id
if (!groupedStudents[etudiantId]) {
groupedStudents[etudiantId] = {
id: etudiantId,
nom: etudiants[index][j].nom,
prenom: etudiants[index][j].prenom,
matieres: {},
totalNote: 0,
totalCredit: 0,
hasValidNotes: false
}
}
let finalNote = etudiants[index][j].note
if (session[index] && session[index][j]) {
finalNote = compareSessionNotes(etudiants[index][j].note, session[index][j])
}
if (finalNote != null && finalNote != undefined && !isNaN(finalNote)) {
groupedStudents[etudiantId].matieres[matiere] = finalNote.toFixed(2)
groupedStudents[etudiantId].totalNote += finalNote * etudiants[index][j].credit
groupedStudents[etudiantId].totalCredit += etudiants[index][j].credit
groupedStudents[etudiantId].hasValidNotes = true
} else {
groupedStudents[etudiantId].matieres[matiere] = 'N/A'
}
}
}
}
const results = Object.values(groupedStudents).map(student => ({
...student,
moyenneUE: student.hasValidNotes && student.totalCredit > 0
? (student.totalNote / student.totalCredit).toFixed(2)
: 'N/A'
}))
return {
students: results.sort((a, b) => {
const moyA = a.moyenneUE === 'N/A' ? -1 : parseFloat(a.moyenneUE)
const moyB = b.moyenneUE === 'N/A' ? -1 : parseFloat(b.moyenneUE)
return moyB - moyA
}),
matieres: Array.from(matieresInUE)
}
}
const sortedStudents = dataToMap.sort((a, b) => {
const moyA = a.moyenne === 'N/A' ? -1 : parseFloat(a.moyenne)
const moyB = b.moyenne === 'N/A' ? -1 : parseFloat(b.moyenne)
return moyB - moyA
})
const handleTabChange = (event, newValue) => {
setTabValue(newValue)
}
const print = () => {
const generatePDF = () => {
try {
const pdf = new jsPDF({
orientation: 'portrait',
unit: 'mm',
format: 'a4'
})
pdf.addImage(logoRelerev1, 'PNG', 175, 5, 32, 30)
pdf.addImage(logoRelerev2, 'PNG', 10, 5, 40, 30)
pdf.setFontSize(10)
pdf.text('REPOBLIKAN\'I MADAGASIKARA', 105, 10, { align: 'center' })
pdf.text('Fitiavana-Tanindrazana-Fandrosoana', 105, 14, { align: 'center' })
pdf.text('********************', 105, 18, { align: 'center' })
pdf.text('MINISTÈRE DE L\'ENSEIGNEMENT SUPÉRIEUR', 105, 22, { align: 'center' })
pdf.text('ET DE LA RECHERCHE SCIENTIFIQUE', 105, 26, { align: 'center' })
pdf.text('********************', 105, 30, { align: 'center' })
pdf.text('UNIVERSITÉ DE TOAMASINA', 105, 34, { align: 'center' })
pdf.text('ÉCOLE SUPÉRIEURE POLYTECHNIQUE', 105, 38, { align: 'center' })
const tableId = tabValue === 0 ? '#resultTable' : tabValue === 1 ? '#subjectTable' : '#ueTable'
autoTable(pdf, {
html: tableId,
startY: 50,
theme: 'grid',
headStyles: {
fillColor: [255, 255, 255], // Fond blanc
halign: 'center',
fontStyle: 'bold',
textColor: [0, 0, 0], // Texte noir
lineColor: [0, 0, 0], // Bordure noire
lineWidth: 0.5
},
styles: {
fontSize: 8,
cellPadding: 2,
halign: 'center',
lineColor: [0, 0, 0], // Bordure noire pour toutes les cellules
lineWidth: 0.5
},
bodyStyles: {
lineColor: [0, 0, 0], // Bordure noire pour le corps du tableau
lineWidth: 0.5
}
})
const suffix = tabValue === 0 ? 'definitif' :
tabValue === 1 ? `par-matiere-${selectedMatiere}` :
`par-ue-${selectedUE}`
pdf.save(`Resultat-${suffix}-${niveau}-${scolaire}.pdf`)
} catch (error) {
console.error('Error generating PDF:', error)
}
}
generatePDF()
}
const renderHeader = () => (
<div
style={{
display: 'flex',
alignItems: 'flex-start',
justifyContent: 'space-between',
marginBottom: '20px',
position: 'relative'
}}
>
<img src={logoRelerev2} alt="Logo gauche" width={90} height={90} />
<div
style={{
position: 'absolute',
left: '50%',
transform: 'translateX(-50%)',
textAlign: 'center',
fontSize: '10px',
lineHeight: '1.2'
}}
>
<div style={{ fontWeight: 'bold' }}>REPOBLIKAN'I MADAGASIKARA</div>
<div style={{ fontStyle: 'italic' }}>Fitiavana-Tanindrazana-Fandrosoana</div>
<div>********************</div>
<div style={{ fontWeight: 'bold' }}>MINISTÈRE DE L'ENSEIGNEMENT SUPÉRIEUR</div>
<div style={{ fontWeight: 'bold' }}>ET DE LA RECHERCHE SCIENTIFIQUE</div>
<div>********************</div>
<div style={{ fontWeight: 'bold' }}>UNIVERSITÉ DE TOAMASINA</div>
<div style={{ fontWeight: 'bold' }}>ÉCOLE SUPÉRIEURE POLYTECHNIQUE</div>
</div>
<img src={logoRelerev1} alt="Logo droite" width={110} height={90} />
</div>
)
const renderResultDefinitif = () => (
<table
className="table table-bordered table-striped text-center shadow-sm"
id="resultTable"
style={{ fontSize: '12px' }}
>
<thead className="table-secondary">
<tr>
<td colSpan={5} className="py-3" style={{ backgroundColor: '#f8f9fa' }}>
<h6 style={{ margin: 0, fontWeight: 'bold' }}>
Résultat Définitif : {niveau} admis en {niveau === 'L1' ? 'L2' : niveau === 'L2' ? 'L3' : 'Master'} par ordre de mérite
</h6>
</td>
</tr>
<tr style={{ backgroundColor: '#e9ecef' }}>
<th style={{ width: '10%', fontWeight: 'bold' }}>RANG</th>
<th style={{ width: '25%', fontWeight: 'bold' }}>NOMS</th>
<th style={{ width: '30%', fontWeight: 'bold' }}>PRÉNOMS</th>
<th style={{ width: '15%', fontWeight: 'bold' }}>Moyenne</th>
<th style={{ width: '20%', fontWeight: 'bold' }}>Mention</th>
</tr>
</thead>
<tbody>
{sortedStudents.map((sorted, index) => (
<tr key={sorted.id}>
<td style={{ fontWeight: 'bold' }}>{index + 1}.</td>
<td style={{ textAlign: 'left', paddingLeft: '10px', fontWeight: 'bold' }}>{sorted.nom}</td>
<td style={{ textAlign: 'left', paddingLeft: '10px' }}>{sorted.prenom}</td>
<td style={{ fontWeight: 'bold' }}>{sorted.moyenne}</td>
<td style={{ fontWeight: 'bold' }}>
{sorted.moyenne !== 'N/A' ? getMentionFromMoyenne(sorted.moyenne) : 'N/A'}
</td>
</tr>
))}
</tbody>
</table>
)
const renderResultParMatiere = () => {
const results = getResultsByMatiere()
return (
<>
<div style={{ marginBottom: '20px' }}>
<FormControl fullWidth>
<InputLabel>Sélectionner une matière</InputLabel>
<Select
value={selectedMatiere}
onChange={(e) => setSelectedMatiere(e.target.value)}
label="Sélectionner une matière"
>
{availableMatieres.map((matiere) => (
<MenuItem key={matiere} value={matiere}>
{matiere}
</MenuItem>
))}
</Select>
</FormControl>
</div>
<table
className="table table-bordered table-striped text-center shadow-sm"
id="subjectTable"
style={{ fontSize: '12px' }}
>
<thead className="table-secondary">
<tr>
<td colSpan={4} className="py-3" style={{ backgroundColor: '#f8f9fa' }}>
<h6 style={{ margin: 0, fontWeight: 'bold' }}>
Résultat pour la matière : {selectedMatiere}
</h6>
</td>
</tr>
<tr style={{ backgroundColor: '#e9ecef' }}>
<th style={{ width: '10%', fontWeight: 'bold' }}>RANG</th>
<th style={{ width: '30%', fontWeight: 'bold' }}>NOMS</th>
<th style={{ width: '40%', fontWeight: 'bold' }}>PRÉNOMS</th>
<th style={{ width: '20%', fontWeight: 'bold' }}>NOTE</th>
</tr>
</thead>
<tbody>
{results.map((item, index) => (
<tr key={item.id}>
<td style={{ fontWeight: 'bold' }}>{index + 1}.</td>
<td style={{ textAlign: 'left', paddingLeft: '10px', fontWeight: 'bold' }}>{item.nom}</td>
<td style={{ textAlign: 'left', paddingLeft: '10px' }}>{item.prenom}</td>
<td style={{ fontWeight: 'bold' }}>{item.note}</td>
</tr>
))}
</tbody>
</table>
</>
)
}
const renderResultParUE = () => {
const { students, matieres } = getResultsByUE()
return (
<>
<div style={{ marginBottom: '20px' }}>
<FormControl fullWidth>
<InputLabel>Sélectionner une UE</InputLabel>
<Select
value={selectedUE}
onChange={(e) => setSelectedUE(e.target.value)}
label="Sélectionner une UE"
>
{availableUEs.map((ue) => (
<MenuItem key={ue} value={ue}>
{ue}
</MenuItem>
))}
</Select>
</FormControl>
</div>
<table
className="table table-bordered table-striped text-center shadow-sm"
id="ueTable"
style={{ fontSize: '12px' }}
>
<thead className="table-secondary">
<tr>
<td colSpan={3 + matieres.length} className="py-3" style={{ backgroundColor: '#f8f9fa' }}>
<h6 style={{ margin: 0, fontWeight: 'bold' }}>
Résultat pour l'UE : {selectedUE}
</h6>
</td>
</tr>
<tr style={{ backgroundColor: '#e9ecef' }}>
<th style={{ fontWeight: 'bold' }}>RANG</th>
<th style={{ fontWeight: 'bold' }}>NOMS</th>
<th style={{ fontWeight: 'bold' }}>PRÉNOMS</th>
{matieres.map((matiere) => (
<th key={matiere} style={{ fontWeight: 'bold' }}>{matiere}</th>
))}
<th style={{ fontWeight: 'bold' }}>MOYENNE UE</th>
</tr>
</thead>
<tbody>
{students.map((student, index) => (
<tr key={student.id}>
<td style={{ fontWeight: 'bold' }}>{index + 1}.</td>
<td style={{ textAlign: 'left', paddingLeft: '10px', fontWeight: 'bold' }}>{student.nom}</td>
<td style={{ textAlign: 'left', paddingLeft: '10px' }}>{student.prenom}</td>
{matieres.map((matiere) => (
<td key={matiere} style={{ fontWeight: 'bold' }}>
{student.matieres[matiere] || 'N/A'}
</td>
))}
<td style={{ fontWeight: 'bold', backgroundColor: '#fff3cd' }}>{student.moyenneUE}</td>
</tr>
))}
</tbody>
</table>
</>
)
}
return (
<div className={classe.mainHome}>
@ -194,80 +552,28 @@ const Resultat = () => {
padding: '2%'
}}
>
{/* En-tête avec logos et texte */}
<div
style={{
display: 'flex',
alignItems: 'flex-start',
justifyContent: 'space-between',
marginBottom: '20px',
position: 'relative'
}}
>
<img src={logoRelerev1} alt="Logo gauche" width={70} />
{/* Texte centré entre les logos */}
<div
style={{
position: 'absolute',
left: '50%',
transform: 'translateX(-50%)',
textAlign: 'center',
fontSize: '10px',
lineHeight: '1.2'
}}
>
<div style={{ fontWeight: 'bold' }}>REPOBLIKAN'I MADAGASIKARA</div>
<div style={{ fontStyle: 'italic' }}>Fitiavana-Tanindrazana-Fandrosoana</div>
<div>********************</div>
<div style={{ fontWeight: 'bold' }}>MINISTÈRE DE L'ENSEIGNEMENT SUPÉRIEUR</div>
<div style={{ fontWeight: 'bold' }}>ET DE LA RECHERCHE SCIENTIFIQUE</div>
<div>********************</div>
<div style={{ fontWeight: 'bold' }}>UNIVERSITÉ DE TOAMASINA</div>
<div style={{ fontWeight: 'bold' }}>ÉCOLE SUPÉRIEURE POLYTECHNIQUE</div>
</div>
<img src={logoRelerev2} alt="Logo droite" width={90} height={90} />
</div>
{renderHeader()}
{/* Informations du parcours */}
<div style={{ marginBottom: '15px', fontSize: '12px' }}>
<div><strong>Parcours :</strong> GC</div>
<div><strong>Niveau :</strong> {niveau}</div>
<div><strong>Année Universitaire :</strong> {scolaire}</div>
</div>
<table
className="table table-bordered table-striped text-center shadow-sm"
id="myTable2"
style={{ fontSize: '12px' }}
<Tabs
value={tabValue}
onChange={handleTabChange}
centered
sx={{ marginBottom: '20px' }}
>
<thead className="table-secondary">
<tr>
<td colSpan={4} className="py-3" style={{ backgroundColor: '#f8f9fa' }}>
<h6 style={{ margin: 0, fontWeight: 'bold' }}>
Résultat de la Deuxième Session : {niveau} admis en L3 par ordre de mérite
</h6>
</td>
</tr>
<tr style={{ backgroundColor: '#e9ecef' }}>
<th style={{ width: '10%', fontWeight: 'bold' }}>RANG</th>
<th style={{ width: '30%', fontWeight: 'bold' }}>NOMS</th>
<th style={{ width: '40%', fontWeight: 'bold' }}>PRÉNOMS</th>
<th style={{ width: '20%', fontWeight: 'bold' }}>Moyenne</th>
</tr>
</thead>
<tbody>
{sortedStudents.map((sorted, index) => (
<tr key={sorted.id}>
<td style={{ fontWeight: 'bold' }}>{index + 1}.</td>
<td style={{ textAlign: 'left', paddingLeft: '10px', fontWeight: 'bold' }}>{sorted.nom}</td>
<td style={{ textAlign: 'left', paddingLeft: '10px' }}>{sorted.prenom}</td>
<td style={{ fontWeight: 'bold' }}>{sorted.moyenne}</td>
</tr>
))}
</tbody>
</table>
<Tab label="Résultat Définitif" />
<Tab label="Par Matière" />
<Tab label="Par UE" />
</Tabs>
{tabValue === 0 && renderResultDefinitif()}
{tabValue === 1 && renderResultParMatiere()}
{tabValue === 2 && renderResultParUE()}
</Paper>
</div>
</div>

84
src/renderer/src/components/Sidenav.jsx

@ -1,4 +1,4 @@
import React, { useState } from 'react'
import React, { useState, useEffect } from 'react'
import classe from '../assets/Sidenav.module.css'
import { RiDashboardHorizontalFill } from 'react-icons/ri'
import { PiStudentFill } from 'react-icons/pi'
@ -21,8 +21,27 @@ import { FaClipboardList } from 'react-icons/fa6'
const Sidenav = () => {
const [anchorEl, setAnchorEl] = useState(null)
const [userRole, setUserRole] = useState(null)
const open = Boolean(anchorEl)
const { setToken } = useAuthContext()
const { user } = useAuthContext()
// // Récupération du rôle utilisateur au montage du composant
// useEffect(() => {
// const fetchUserRole = async () => {
// try {
// // Supposant que vous avez une méthode getUser dans votre contexte ou API
// const user = await window.allUser?.users(); // ou votre méthode d'API
// console.log('Résultat de getAllUsers:', user)
// setUserRole(user?.roles?.toLowerCase()) // Normaliser en minuscule
// } catch (error) {
// console.error('Erreur lors de la récupération du rôle utilisateur:', error)
// setUserRole(null)
// }
// }
// fetchUserRole()
// }, [])
const handleClick = (event) => {
setAnchorEl(event.currentTarget)
@ -40,6 +59,11 @@ const Sidenav = () => {
setToken(null)
}
// Fonction pour vérifier si l'utilisateur est admin
const isAdmin = () => {
console.log('Rôle de l’utilisateur:', user?.roles)
return user?.roles?.toLowerCase() === 'admin'
}
return (
<nav className={classe.navbar}>
<style>
@ -82,21 +106,26 @@ const Sidenav = () => {
</Tooltip>
</Link>
</li>
<li>
<Link
to={'/notes'}
className={classe.nav_link}
style={{
outline: 'none',
borderBottom: window.location.hash == '#/notes' ? '2px solid white' : 'none'
}}
>
<CgNotes className="notes" style={{ outline: 'none' }} />
<Tooltip anchorSelect=".notes" className="custom-tooltip" place="top">
Notes
</Tooltip>
</Link>
</li>
{/* Navigation Notes - Visible uniquement pour les admins */}
{isAdmin() && (
<li>
<Link
to={'/notes'}
className={classe.nav_link}
style={{
outline: 'none',
borderBottom: window.location.hash == '#/notes' ? '2px solid white' : 'none'
}}
>
<CgNotes className="notes" style={{ outline: 'none' }} />
<Tooltip anchorSelect=".notes" className="custom-tooltip" place="top">
Notes
</Tooltip>
</Link>
</li>
)}
<li>
<Link
to={'/mention'}
@ -153,7 +182,7 @@ const Sidenav = () => {
>
<BsCalendar2Date className="anneescolaire" style={{ outline: 'none' }} />
<Tooltip anchorSelect=".anneescolaire" className="custom-tooltip" place="top">
Année Scolaire
Année Univesitaire
</Tooltip>
</Link>
</li>
@ -187,17 +216,6 @@ const Sidenav = () => {
</Tooltip>
</Link>
</li>
{/* <li>
<Link to={'/manual'} className={classe.nav_link} style={{
outline: 'none',
borderBottom: window.location.hash == '#/manual' ? '2px solid white' : 'none'
}}>
<GrManual className='manual' style={{ outline: 'none' }} />
<Tooltip anchorSelect=".manual" className='custom-tooltip' place="top">
Manuel d'utilisation
</Tooltip>
</Link>
</li> */}
</ul>
<ul className={classe.liste2}>
<li>
@ -261,14 +279,6 @@ const Sidenav = () => {
</MenuItem>
</Menu>
</li>
{/* <li>
<Link to={'/teste'}>
<SiVitest className='test' style={{outline:'none'}} />
<Tooltip anchorSelect=".test" className='custom-tooltip' place="top">
Teste
</Tooltip>
</Link>
</li> */}
<li>
<LuLogOut className="logout" style={{ outline: 'none' }} onClick={logout} />
<Tooltip anchorSelect=".logout" className="custom-tooltip" place="top">
@ -280,4 +290,4 @@ const Sidenav = () => {
)
}
export default Sidenav
export default Sidenav

6
src/renderer/src/components/SingleAnneeScolaire.jsx

@ -121,7 +121,7 @@ const SingleAnneeScolaire = () => {
<div className={classeHome.blockTitle}>
<h1 style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
<BsCalendar2Date />
Mise a jour Année Scolaire
Mise a jour Année Univesitaire
</h1>
<Link to={'#'} onClick={() => window.history.back()}>
<Button color="warning" variant="contained">
@ -155,12 +155,12 @@ const SingleAnneeScolaire = () => {
onSubmit={formSubmit}
>
<h4 style={{ textAlign: 'center', padding: '0 0 3% 0' }}>
mise a jour Année Scolaire
mise a jour Année Univesitaire
</h4>
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<TextField
label={'Année Scolaire'}
label={'Année Univesitaire'}
name={'code'}
placeholder="2024-2025"
color="warning"

8
src/renderer/src/components/SingleEtudiant.jsx

@ -535,12 +535,12 @@ const SingleEtudiant = () => {
</Grid>
</Grid>
{/* Group Année Scolaire and Numero d'Inscription */}
{/* Group Année Univesitaire and Numero d'Inscription */}
<Grid container spacing={2}>
<Grid item xs={6}>
<TextField
fullWidth
label="Année Scolaire"
label="Année Univesitaire"
name="annee_scolaire"
color="warning"
defaultValue={etudiant.annee_scolaire} // Controlled component value
@ -813,7 +813,7 @@ const SingleEtudiant = () => {
</Grid>
</Grid>
{/* Group Année Scolaire and Numero d'Inscription */}
{/* Group Année Univesitaire and Numero d'Inscription */}
<Grid container spacing={2}>
<Grid item xs={6}>
<TextField
@ -1111,7 +1111,7 @@ const SingleEtudiant = () => {
variant="h6"
style={{ display: 'flex', justifyContent: 'space-between' }}
>
<span>Année Scolaire:</span> {etudiant.annee_scolaire}
<span>Année Univesitaire:</span> {etudiant.annee_scolaire}
</Typography>
</Grid>
<Grid item xs={12}>

21
src/renderer/src/components/Student.jsx

@ -26,8 +26,18 @@ import { processPdf } from './function/PDFEditorV2'
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
const Student = () => {
// Récupération de l'utilisateur connecté
const { user } = useAuthContext()
// Fonction pour vérifier si l'utilisateur est admin
const isAdmin = () => {
console.log('Rôle de l\'utilisateur dans Student:', user?.roles)
return user?.roles?.toLowerCase() === 'admin'
}
const theme = createTheme({
components: {
MuiIconButton: {
@ -251,7 +261,7 @@ const Student = () => {
*/
const columns = [
{ field: 'nom', headerName: 'Nom', width: 180 },
{ field: 'prenom', headerName: 'Prenom', width: 180 },
{ field: 'prenom', headerName: 'Prénom', width: 180 },
{ field: 'sexe', headerName: 'Sexe', width: 80 },
{ field: 'cin', headerName: 'CIN', width: 180 },
{ field: 'date_deli', headerName: 'Date de delivrance', width: 80 },
@ -337,7 +347,9 @@ const Student = () => {
>
{/* Groupe 1 : Certificat */}
<Link style={{ display: 'flex', gap: '10px' }}>
<SeeNote params={params} />
{/* Affichage conditionnel de SeeNote - uniquement pour les admins */}
{isAdmin() && <SeeNote params={params} />}
<Link>
<Button
onClick={() => handleOpen(params.value)}
@ -435,8 +447,8 @@ const Student = () => {
if (etudiant) {
let data = {
f1: `${etudiant.nom} ${etudiant.prenom}`,
f2: `Naissances: ${dayjs(etudiant.date_de_naissances).format('DD-MM-YYYY')}`,
f3: `Niveau: ${etudiant.niveau}`,
f2: `Naissance: ${dayjs(etudiant.date_de_naissances).format('DD-MM-YYYY')}`,
f3: `Niveau: ${etudiant.niveau} ${etudiant.mentionUnite}`,
f4: `Année: ${etudiant.annee_scolaire}`,
f5: `Inscription: ${etudiant.num_inscription}`,
f8: etudiant.photos
@ -488,6 +500,7 @@ const Student = () => {
domaine: etudiant.domaine,
contact: etudiant.contact,
mention_id: etudiant.mention_id,
mentionUnite: etudiant.mentionUnite,
action: etudiant.id // Ensure this is a valid URL for the image
}))

8
src/renderer/src/components/SystemeNote.jsx

@ -221,8 +221,8 @@ const SystemeNote = () => {
<tr style={{ fontWeight: 'bold' }}>
<td style={{ color: 'gray' }}>Status :</td>
<td style={{ color: 'gray' }}>Admis</td>
<td style={{ color: 'gray' }}>Redouble</td>
<td style={{ color: 'gray' }}>Renvoyer</td>
<td style={{ color: 'gray' }}>Autorisé à redoubler</td>
<td style={{ color: 'gray' }}>Remis à la famille</td>
</tr>
</thead>
<tbody>
@ -271,7 +271,7 @@ const SystemeNote = () => {
{/* <Grid container spacing={2}> */}
<Grid item xs={12} sm={3}>
<TextField
label={'Notes pour redoubler'}
label={'Notes pour autorisé à redoubler'}
name={'redouble'}
color="warning"
fullWidth
@ -310,7 +310,7 @@ const SystemeNote = () => {
{/* <Grid container spacing={2}> */}
<Grid item xs={12} sm={3}>
<TextField
label={'Notes pour etre renvoyer'}
label={'Notes pour etre remis à la famille'}
name={'renvoyer'}
color="warning"
fullWidth

4
src/renderer/src/components/TesteDatagrid.jsx

@ -248,11 +248,11 @@ const TesteDatagrid = ({ id, niveau, annee_scolaire, nomPrenom, inscription, ref
</div>
</div>
<div style={{ fontSize: '13px', margin: '1%' }}>
<span>Nom & Prenoms: </span>
<span>Nom & Prénoms: </span>
<span>{nomPrenom}</span>
<br />
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<span>Année scolaire: </span>
<span>Année Univesitaire: </span>
<span>{annee_scolaire}</span>
<span>Niveau: </span>
<span>{niveau}</span>

4
src/renderer/src/components/UpdateModalProf.jsx

@ -96,10 +96,10 @@ const UpdateModalProf = ({ open, onClose, matiere_id, onSubmitSuccess }) => {
margin="normal"
required
name="prenom_enseignant"
label="Prenom du professeur"
label="Prénom du professeur"
type="text"
fullWidth
placeholder="Prenom du professeur"
placeholder="Prénom du professeur"
variant="outlined"
value={formData.prenom_enseignant}
color="warning"

6
src/renderer/src/components/function/PDFEditor.js

@ -21,7 +21,7 @@ const PDFEditor = async (data) => {
form.getTextField('name').setText(data.f1)
form.getTextField('birthday').setText('Date de naissance: ' + data.f2)
form.getTextField('niveau').setText('Niveau: ' + data.f3)
form.getTextField('annee').setText('Année scolaire: ' + data.f4)
form.getTextField('annee').setText('Année Univesitaire: ' + data.f4)
form.getTextField('num_inscription').setText("Numéro d'inscription: " + data.f5)
form.flatten()
@ -73,10 +73,10 @@ const PDFEditor = async (data) => {
// ----------------------------------------------- carte arriere -------------------------------------------
const paperContent = `
CUniversity
Nom et prenom: ${data.f1}
Nom et prénom: ${data.f1}
Date de naissance: ${data.f2}
Niveau: ${data.f3}
Année scolaire: ${data.f4}
Année Univesitaire: ${data.f4}
Numéro d'inscription: ${data.f5}
`

69
src/renderer/src/components/function/PDFEditorV2.js

@ -14,28 +14,49 @@ async function fillPdfFields(jsonData) {
// Get the first page to draw text on
const page = pdfDoc.getPage(0)
const form = pdfDoc.getForm()
const nameField = form.getTextField('name')
nameField.setText(jsonData.f1 || '')
const birthdayField = form.getTextField('birthday')
birthdayField.setText(jsonData.f2 || '')
const niveauField = form.getTextField('niveau')
niveauField.setText(jsonData.f3 || '')
const anneeField = form.getTextField('annee')
anneeField.setText(jsonData.f4 || '')
const num_inscriptionField = form.getTextField('num_inscription')
num_inscriptionField.setText(jsonData.f5 || '')
console.log('namefield:', nameField.getText())
console.log('namefield:', birthdayField.getText())
console.log('namefield:', niveauField.getText())
console.log('namefield:', anneeField.getText())
console.log('namefield:', num_inscriptionField.getText())
// Define positions for text (adjust these coordinates based on your red dots)
const textPositions = [
{ x: 45, y: 92, text: `${jsonData.f1 || ''}`, fontSize: 10 }, // Nom et prénom
{ x: 45, y: 75, text: `${jsonData.f2 || ''}`, fontSize: 10 }, // Date de naissance
{ x: 45, y: 58, text: `${jsonData.f3 || ''}`, fontSize: 10 }, // Niveau
{ x: 45, y: 38, text: `${jsonData.f4 || ''}`, fontSize: 10 }, // Année scolaire
{ x: 60, y: 23, text: `${jsonData.f5 || ''}`, fontSize: 10 } // Numéro d'inscription
]
// const textPositions = [
// { x: 45, y: 92, text: `${jsonData.f1 || ''}`, fontSize: 10 }, // Nom et prénom
// { x: 45, y: 75, text: `${jsonData.f2 || ''}`, fontSize: 10 }, // Date de naissance
// { x: 45, y: 58, text: `${jsonData.f3 || ''}`, fontSize: 10 }, // Niveau
// { x: 45, y: 38, text: `${jsonData.f4 || ''}`, fontSize: 10 }, // Année Univesitaire
// { x: 60, y: 23, text: `${jsonData.f5 || ''}`, fontSize: 10 } // Numéro d'inscription
// ]
// Draw text at specified positions
textPositions.forEach((item, index) => {
if (item.text.trim()) {
page.drawText(item.text, {
x: item.x,
y: item.y,
size: item.fontSize - 2,
color: rgb(1, 1, 1), // Black text
})
console.log(`Drawing text at position ${index + 1}: ${item.text} at (${item.x}, ${item.y})`)
}
})
// textPositions.forEach((item, index) => {
// if (item.text.trim()) {
// page.drawText(item.text, {
// x: item.x,
// y: item.y,
// size: item.fontSize - 2,
// color: rgb(1, 1, 1), // Black text
// })
// console.log(`Drawing text at position ${index + 1}: ${item.text} at (${item.x}, ${item.y})`)
// }
// })
// ---------------------------------calculate and paste the image in pdf--------------------------------------
if (jsonData.f8) {
@ -79,12 +100,12 @@ async function fillPdfFields(jsonData) {
// -------------------------------------------paste the qrCode in the pdf--------------------------------------
const paperContent = `
ECOLE POLYTECHNIQUE DE TOAMASINA
Nom et prenom: ${jsonData.f1}
Date de naissance: ${jsonData.f2}
Niveau: ${jsonData.f3}
Année scolaire: ${jsonData.f4}
Numéro d'inscription: ${jsonData.f5}
ECOLE SUPERIEURE POLYTECHNIQUE DE TOAMASINA
${jsonData.f1}
${jsonData.f2}
${jsonData.f3}
${jsonData.f4}
${jsonData.f5}
`
const qrCanvas = document.createElement('canvas')

2
src/renderer/src/components/validation/ValidationAddAnneeScolaire.js

@ -1,5 +1,5 @@
/**
* function validation année scolaire form
* function validation Année Univesitaire form
* @param {*} code
* @param {*} debut
* @param {*} fin

80
src/renderer/src/contexts/AuthContext.jsx

@ -1,38 +1,84 @@
import { createContext, useContext, useState } from 'react'
import { createContext, useContext, useState, useEffect } from 'react'
const AuthContext = createContext({
user: null,
token: null,
setUser: () => {},
setToken: () => {}
setToken: () => {},
isAuthenticated: false
})
export const AuthContextProvider = ({ children }) => {
const [user, setUser] = useState()
const [token, _setToken] = useState(localStorage.getItem('ACCESS_TOKEN'))
// Initialiser avec null explicitement
const [user, setUser] = useState(null)
const [token, _setToken] = useState(null)
const [isLoading, setIsLoading] = useState(true)
const setToken = (token) => {
_setToken(token)
// Initialiser depuis localStorage au montage
useEffect(() => {
const storedToken = localStorage.getItem('ACCESS_TOKEN')
const storedUser = localStorage.getItem('USER_DATA')
if (storedToken) {
_setToken(storedToken)
}
if (storedUser) {
try {
setUser(JSON.parse(storedUser))
} catch (error) {
console.error('Erreur parsing user data:', error)
localStorage.removeItem('USER_DATA')
}
}
setIsLoading(false)
}, [])
if (token) {
localStorage.setItem('ACCESS_TOKEN', token)
const setToken = (newToken) => {
_setToken(newToken)
if (newToken) {
localStorage.setItem('ACCESS_TOKEN', newToken)
} else {
localStorage.removeItem('ACCESS_TOKEN')
localStorage.removeItem('USER_DATA') // Nettoyer aussi les données utilisateur
setUser(null) // Reset user state
}
}
const setUserData = (userData) => {
setUser(userData)
if (userData) {
localStorage.setItem('USER_DATA', JSON.stringify(userData))
} else {
localStorage.removeItem('USER_DATA')
}
}
const logout = () => {
setToken(null)
setUserData(null)
}
const isAuthenticated = !!(token && user)
const contextValue = {
user,
token,
setUser: setUserData,
setToken,
logout,
isAuthenticated,
isLoading
}
return (
<AuthContext.Provider
value={{
user,
token,
setUser,
setToken
}}
>
<AuthContext.Provider value={contextValue}>
{children}
</AuthContext.Provider>
)
}
export const useAuthContext = () => useContext(AuthContext)
export const useAuthContext = () => useContext(AuthContext)

2
src/renderer/src/test/qr.html

@ -26,7 +26,7 @@
<p><b>Prenom</b> : Joseph Fabrice</p>
<p><b>Date de naissance</b> : 11-12-2001</p>
<p><b>Niveau</b> : L3</p>
<p><b>Année scolaire</b> : 2023-2024</p>
<p><b>Année Univesitaire</b> : 2023-2024</p>
<p><b>Num inscription</b> : 12345678900</p>
</div>
</div>

2
src/renderer/src/test/relever.html

@ -21,7 +21,7 @@
<h3>RELEVÉE DE NOTE</h3>
<p><strong>Nom & Prenoms :</strong> F3</p>
<p>
<strong>Niveau :</strong> L1 <span><strong>Année scolaire :</strong> 2022-2023</span>
<strong>Niveau :</strong> L1 <span><strong>Année Univesitaire :</strong> 2022-2023</span>
</p>
<p><strong>N° inscription :</strong> F42</p>

2
text.txt

@ -248,7 +248,7 @@ const FileUploader = () => {
<th>Photos</th>
<th>Date de Naissances</th>
<th>Niveau</th>
<th>Année Scolaire</th>
<th>Année Univesitaire</th>
<th>Num Inscription</th>
</tr>
</thead>

Loading…
Cancel
Save