resolved
This commit is contained in:
commit
9e9bc98548
27
electron.vite.config.1754936034364.mjs
Normal file
27
electron.vite.config.1754936034364.mjs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// electron.vite.config.mjs
|
||||||
|
import { resolve } from "path";
|
||||||
|
import { defineConfig, externalizeDepsPlugin } from "electron-vite";
|
||||||
|
import react from "@vitejs/plugin-react";
|
||||||
|
var electron_vite_config_default = defineConfig({
|
||||||
|
main: {
|
||||||
|
plugins: [externalizeDepsPlugin()]
|
||||||
|
},
|
||||||
|
preload: {
|
||||||
|
plugins: [externalizeDepsPlugin()]
|
||||||
|
},
|
||||||
|
renderer: {
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
"@renderer": resolve("src/renderer/src")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: [react()]
|
||||||
|
},
|
||||||
|
worker: {
|
||||||
|
format: "es"
|
||||||
|
// Use ES module for worker (you can also use 'iife')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
export {
|
||||||
|
electron_vite_config_default as default
|
||||||
|
};
|
||||||
922
src/main/backup.js
Normal file
922
src/main/backup.js
Normal file
@ -0,0 +1,922 @@
|
|||||||
|
import { app, shell, BrowserWindow, ipcMain, Tray, Menu } from 'electron'
|
||||||
|
import { join } from 'path'
|
||||||
|
const path = require('path')
|
||||||
|
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
|
||||||
|
import icon from '../../resources/logo.ico?asset' // Your tray icon file
|
||||||
|
const database = require('../../database/database2')
|
||||||
|
|
||||||
|
database
|
||||||
|
.createTables()
|
||||||
|
.then(() => database.insertDefaultAdmin())
|
||||||
|
.then(() => database.insertStatusesIfNotExist())
|
||||||
|
.catch(console.error)
|
||||||
|
|
||||||
|
const { createConfigIp, updateIPConfig } = require('../../database/Models/IpConfig')
|
||||||
|
const { importFileToDatabase } = require('../../database/import/Etudiants')
|
||||||
|
const { loginUser, forgotPassword, insertUser, updateUser } = require('../../database/Models/Users')
|
||||||
|
const {
|
||||||
|
insertEtudiant,
|
||||||
|
getSingleEtudiant,
|
||||||
|
FilterDataByNiveau,
|
||||||
|
updateEtudiant,
|
||||||
|
changePDP,
|
||||||
|
updateParcours,
|
||||||
|
createTranche,
|
||||||
|
getTranche,
|
||||||
|
updateTranche,
|
||||||
|
deleteTranche,
|
||||||
|
deleteEtudiant,
|
||||||
|
getSingleTranche
|
||||||
|
} = require('../../database/Models/Etudiants')
|
||||||
|
const {
|
||||||
|
insertNiveau,
|
||||||
|
updateNiveau,
|
||||||
|
getSingleNiveau,
|
||||||
|
deleteNiveau
|
||||||
|
} = require('../../database/Models/Niveau')
|
||||||
|
const {
|
||||||
|
insertNote,
|
||||||
|
getNote,
|
||||||
|
updateNote,
|
||||||
|
showMoyen,
|
||||||
|
getMatiereAndNote,
|
||||||
|
getNotesWithRepechToDisplay
|
||||||
|
} = require('../../database/Models/Notes')
|
||||||
|
const {
|
||||||
|
createMatiere,
|
||||||
|
getSingleMatiere,
|
||||||
|
updateMatiere,
|
||||||
|
updateMatiereNiveau,
|
||||||
|
displayMatiereFromForm,
|
||||||
|
deleteMatiere,
|
||||||
|
asygnationToMention,
|
||||||
|
getMentionMatiere,
|
||||||
|
getMentionMatiereChecked,
|
||||||
|
getSemestreMatiere,
|
||||||
|
insertUpdateMentionSemestre,
|
||||||
|
insertNewProf,
|
||||||
|
getSIngleProf,
|
||||||
|
updateProf
|
||||||
|
} = require('../../database/Models/Matieres')
|
||||||
|
const { importFileToDatabaseMatiere } = require('../../database/import/Matieres')
|
||||||
|
const { importNiveau } = require('../../database/import/Niveau')
|
||||||
|
const { updateSysteme } = require('../../database/Models/NoteSysrem')
|
||||||
|
const {
|
||||||
|
createAnneeScolaire,
|
||||||
|
deleteAnneeScolaire,
|
||||||
|
getSingleAnneScolaire,
|
||||||
|
updateAnneeScolaire,
|
||||||
|
setCurrent
|
||||||
|
} = require('../../database/Models/AnneeScolaire')
|
||||||
|
const {
|
||||||
|
createMention,
|
||||||
|
deleteMention,
|
||||||
|
getSingleMention,
|
||||||
|
updateMention
|
||||||
|
} = require('../../database/Models/Mentions')
|
||||||
|
const {
|
||||||
|
getNoteRepech,
|
||||||
|
updateNoteRepech,
|
||||||
|
showMoyenRepech
|
||||||
|
} = require('../../database/Models/NoteRepechage')
|
||||||
|
const {
|
||||||
|
updateCurrentYears,
|
||||||
|
updateStudents,
|
||||||
|
updateNessesaryTable
|
||||||
|
} = require('../../database/function/System')
|
||||||
|
const { autoUpdater } = require('electron-updater')
|
||||||
|
const { URL } = require('../../database/api/Config')
|
||||||
|
const {
|
||||||
|
insertParcour,
|
||||||
|
getSingleParcours,
|
||||||
|
deletes,
|
||||||
|
updateparcour,
|
||||||
|
parcourMatiere,
|
||||||
|
extractFiche,
|
||||||
|
getParcourMatiere
|
||||||
|
} = require('../../database/Models/Parcours')
|
||||||
|
|
||||||
|
// Declare mainWindow and tray in the global scope
|
||||||
|
let mainWindow
|
||||||
|
let tray = null
|
||||||
|
updateCurrentYears()
|
||||||
|
updateStudents()
|
||||||
|
|
||||||
|
autoUpdater.setFeedURL({
|
||||||
|
provider: 'generic',
|
||||||
|
url: `${URL}/latest` // Ensure this points to the folder containing latest.yml
|
||||||
|
})
|
||||||
|
|
||||||
|
function createWindow() {
|
||||||
|
// Create the browser window.
|
||||||
|
mainWindow = new BrowserWindow({
|
||||||
|
width: 1375,
|
||||||
|
minWidth: 1375,
|
||||||
|
height: 740,
|
||||||
|
minHeight: 740,
|
||||||
|
show: false,
|
||||||
|
autoHideMenuBar: true,
|
||||||
|
fullscreen: false,
|
||||||
|
icon: path.join(__dirname, 'resources', 'logo.ico'), // Path to your icon,
|
||||||
|
...(process.platform === 'linux' ? { icon } : {}),
|
||||||
|
webPreferences: {
|
||||||
|
preload: join(__dirname, '../preload/index.js'),
|
||||||
|
nodeIntegration: true,
|
||||||
|
contextIsolation: true,
|
||||||
|
sandbox: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Désactiver les raccourcis clavier
|
||||||
|
mainWindow.webContents.on('before-input-event', (event, input) => {
|
||||||
|
if (input.control || input.meta || input.alt || input.key === 'F11') {
|
||||||
|
event.preventDefault()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
mainWindow.on('ready-to-show', () => {
|
||||||
|
mainWindow.maximize() // Maximiser la fenêtre
|
||||||
|
mainWindow.show()
|
||||||
|
})
|
||||||
|
|
||||||
|
mainWindow.webContents.setWindowOpenHandler((details) => {
|
||||||
|
shell.openExternal(details.url)
|
||||||
|
return { action: 'deny' }
|
||||||
|
})
|
||||||
|
|
||||||
|
// Load the appropriate URL based on environment
|
||||||
|
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
|
||||||
|
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
|
||||||
|
} else {
|
||||||
|
mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle window close (hide instead of closing)
|
||||||
|
mainWindow.on('close', (event) => {
|
||||||
|
if (!app.isQuiting) {
|
||||||
|
event.preventDefault()
|
||||||
|
mainWindow.hide() // Minimize to tray instead of closing
|
||||||
|
} else {
|
||||||
|
// Destroy the tray when quitting
|
||||||
|
if (tray) tray.destroy()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to create the system tray
|
||||||
|
function createTray() {
|
||||||
|
const iconPath = icon // Use your icon path here
|
||||||
|
tray = new Tray(iconPath)
|
||||||
|
|
||||||
|
// Create a context menu for the tray
|
||||||
|
const contextMenu = Menu.buildFromTemplate([
|
||||||
|
{
|
||||||
|
label: 'Ouvrir',
|
||||||
|
click: () => {
|
||||||
|
mainWindow.show()
|
||||||
|
mainWindow.webContents.send('navigateToRoute', '#/') // Send the route as a string
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'A Propos',
|
||||||
|
click: () => {
|
||||||
|
mainWindow.show()
|
||||||
|
mainWindow.webContents.send('navigateToRoute', '#/apropos') // Send the route as a string
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Quit',
|
||||||
|
click: () => {
|
||||||
|
// Clear localStorage in the renderer process
|
||||||
|
mainWindow.webContents
|
||||||
|
.executeJavaScript('localStorage.removeItem("ACCESS_TOKEN");')
|
||||||
|
.then(() => {
|
||||||
|
console.log('localStorage cleared.')
|
||||||
|
// Ensure the app quits entirely
|
||||||
|
if (tray) {
|
||||||
|
app.quit()
|
||||||
|
tray.destroy()
|
||||||
|
// if (app.quit()) {
|
||||||
|
// tray.destroy()
|
||||||
|
// }
|
||||||
|
} // Quit the app
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error('Error clearing localStorage:', err)
|
||||||
|
// Quit the app even if clearing fails
|
||||||
|
if (tray) {
|
||||||
|
app.quit()
|
||||||
|
tray.destroy()
|
||||||
|
// if (app.quit()) {
|
||||||
|
// tray.destroy()
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
tray.setToolTip('My Electron App')
|
||||||
|
tray.setContextMenu(contextMenu)
|
||||||
|
|
||||||
|
// Show the app when the tray icon is clicked
|
||||||
|
tray.on('click', () => {
|
||||||
|
mainWindow.show()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
electronApp.setAppUserModelId('com.electron')
|
||||||
|
autoUpdater.checkForUpdatesAndNotify()
|
||||||
|
|
||||||
|
app.on('browser-window-created', (_, window) => {
|
||||||
|
optimizer.watchWindowShortcuts(window)
|
||||||
|
})
|
||||||
|
|
||||||
|
createWindow()
|
||||||
|
createTray() // Create the tray icon
|
||||||
|
|
||||||
|
app.on('activate', function () {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// When an update is available
|
||||||
|
autoUpdater.on('update-available', () => {
|
||||||
|
dialog.showMessageBox({
|
||||||
|
type: 'info',
|
||||||
|
title: 'Mise à jour disponible',
|
||||||
|
message: 'Une nouvelle version est disponible. Téléchargement en cours...'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// When the update is downloaded
|
||||||
|
autoUpdater.on('update-downloaded', (info) => {
|
||||||
|
dialog
|
||||||
|
.showMessageBox({
|
||||||
|
type: 'info',
|
||||||
|
title: 'Mise à jour prête',
|
||||||
|
message: `La version ${info.version} a été téléchargée. Redémarrer maintenant ?`,
|
||||||
|
buttons: ['Redémarrer', 'Plus tard']
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
if (result.response === 0) {
|
||||||
|
autoUpdater.quitAndInstall()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// If an error occurs
|
||||||
|
autoUpdater.on('error', (error) => {
|
||||||
|
dialog.showErrorBox('Update Error', error == null ? 'Unknown' : error.message)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Quit the app when all windows are closed, except on macOS
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// In this file you can include the rest of your app"s specific main process
|
||||||
|
// code. You can also put them in separate files and require them here.
|
||||||
|
|
||||||
|
// Event for handling login
|
||||||
|
ipcMain.handle('login', async (event, credentials) => {
|
||||||
|
const { username, password } = credentials
|
||||||
|
|
||||||
|
const users = await loginUser(username, password)
|
||||||
|
|
||||||
|
if (users) {
|
||||||
|
return { success: true, user: users }
|
||||||
|
} else {
|
||||||
|
return { success: false }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Event for handling insert other user
|
||||||
|
ipcMain.handle('insertUser', async (event, credentials) => {
|
||||||
|
const { username, email, password, roles } = credentials
|
||||||
|
|
||||||
|
const users = await insertUser(username, email, password, roles)
|
||||||
|
|
||||||
|
return users
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for handlign forgot password
|
||||||
|
ipcMain.handle('forgotPassword', async (event, credentials) => {
|
||||||
|
const { email, password, passwordConfirmation } = credentials
|
||||||
|
|
||||||
|
const updated = await forgotPassword(email, password, passwordConfirmation)
|
||||||
|
|
||||||
|
if (updated) {
|
||||||
|
return updated
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for updating users
|
||||||
|
ipcMain.handle('updateUsers', async (event, credentials) => {
|
||||||
|
const { username, newUsername, email, newEmail, passwordVerif, password, id } = credentials
|
||||||
|
|
||||||
|
const update = await updateUser(newUsername, newEmail, password, id)
|
||||||
|
|
||||||
|
return update
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for quit app
|
||||||
|
ipcMain.handle('quit', async () => {
|
||||||
|
app.quit()
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for minimizing the app
|
||||||
|
ipcMain.handle('minimize', async () => {
|
||||||
|
if (mainWindow) {
|
||||||
|
mainWindow.minimize()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for insert etudiants
|
||||||
|
ipcMain.handle('insertEtudiant', async (event, credentials) => {
|
||||||
|
const {
|
||||||
|
nom,
|
||||||
|
prenom,
|
||||||
|
photos,
|
||||||
|
date_de_naissances,
|
||||||
|
niveau,
|
||||||
|
annee_scolaire,
|
||||||
|
status,
|
||||||
|
num_inscription,
|
||||||
|
mention_id,
|
||||||
|
sexe,
|
||||||
|
nationaliter,
|
||||||
|
cin,
|
||||||
|
date_delivrence,
|
||||||
|
annee_bacc,
|
||||||
|
serie,
|
||||||
|
boursier,
|
||||||
|
domaine,
|
||||||
|
contact,
|
||||||
|
parcours
|
||||||
|
} = credentials
|
||||||
|
|
||||||
|
const insert = await insertEtudiant(
|
||||||
|
nom,
|
||||||
|
prenom,
|
||||||
|
photos,
|
||||||
|
date_de_naissances,
|
||||||
|
niveau,
|
||||||
|
annee_scolaire,
|
||||||
|
status,
|
||||||
|
num_inscription,
|
||||||
|
mention_id,
|
||||||
|
sexe,
|
||||||
|
nationaliter,
|
||||||
|
cin,
|
||||||
|
date_delivrence,
|
||||||
|
annee_bacc,
|
||||||
|
serie,
|
||||||
|
boursier,
|
||||||
|
domaine,
|
||||||
|
contact,
|
||||||
|
parcours
|
||||||
|
)
|
||||||
|
|
||||||
|
return insert
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for fetching single
|
||||||
|
ipcMain.handle('getByNiveau', async (event, credentials) => {
|
||||||
|
const { niveau } = credentials
|
||||||
|
|
||||||
|
const getSingle = await FilterDataByNiveau(niveau)
|
||||||
|
|
||||||
|
return getSingle
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for fetching single
|
||||||
|
ipcMain.handle('single', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
|
||||||
|
const getSingle = await getSingleEtudiant(id)
|
||||||
|
|
||||||
|
return getSingle
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for inserting niveau
|
||||||
|
ipcMain.handle('insertNiveau', async (event, credentials) => {
|
||||||
|
const { nom } = credentials
|
||||||
|
|
||||||
|
const insert = await insertNiveau(nom)
|
||||||
|
|
||||||
|
return insert
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for updating etudiants
|
||||||
|
ipcMain.handle('updateETudiants', async (event, credentials) => {
|
||||||
|
const {
|
||||||
|
nom,
|
||||||
|
prenom,
|
||||||
|
photos,
|
||||||
|
date_de_naissances,
|
||||||
|
niveau,
|
||||||
|
annee_scolaire,
|
||||||
|
status,
|
||||||
|
mention_id,
|
||||||
|
num_inscription,
|
||||||
|
id,
|
||||||
|
sexe,
|
||||||
|
nationalite,
|
||||||
|
cin,
|
||||||
|
date_delivrance,
|
||||||
|
annee_bacc,
|
||||||
|
serie,
|
||||||
|
boursier,
|
||||||
|
domaine,
|
||||||
|
contact,
|
||||||
|
parcours
|
||||||
|
} = credentials
|
||||||
|
|
||||||
|
const updating = await updateEtudiant(
|
||||||
|
nom,
|
||||||
|
prenom,
|
||||||
|
photos,
|
||||||
|
date_de_naissances,
|
||||||
|
niveau,
|
||||||
|
annee_scolaire,
|
||||||
|
status,
|
||||||
|
mention_id,
|
||||||
|
num_inscription,
|
||||||
|
id,
|
||||||
|
sexe,
|
||||||
|
nationalite,
|
||||||
|
cin,
|
||||||
|
date_delivrance,
|
||||||
|
annee_bacc,
|
||||||
|
serie,
|
||||||
|
boursier,
|
||||||
|
domaine,
|
||||||
|
contact,
|
||||||
|
parcours
|
||||||
|
)
|
||||||
|
|
||||||
|
return updating
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for updating etudiants pdp
|
||||||
|
ipcMain.handle('updateETudiantsPDP', async (event, credentials) => {
|
||||||
|
const { pdp, id } = credentials
|
||||||
|
|
||||||
|
const updating = await changePDP(pdp, id)
|
||||||
|
|
||||||
|
return updating
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for adding notes
|
||||||
|
ipcMain.handle('insertNote', async (event, credentials) => {
|
||||||
|
const { etudiant_id, etudiant_niveau, mention_id, formData, annee_scolaire } = credentials
|
||||||
|
|
||||||
|
const insert = await insertNote(
|
||||||
|
etudiant_id,
|
||||||
|
etudiant_niveau,
|
||||||
|
mention_id,
|
||||||
|
formData,
|
||||||
|
annee_scolaire
|
||||||
|
)
|
||||||
|
|
||||||
|
return insert
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for get single note
|
||||||
|
ipcMain.handle('getSingleNote', async (event, credentials) => {
|
||||||
|
const { id, niveau, mention_id } = credentials
|
||||||
|
|
||||||
|
const get = await getNote(id, niveau, mention_id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for get single note repech
|
||||||
|
ipcMain.handle('getNotesRepech', async (event, credentials) => {
|
||||||
|
const { id, niveau, mention_id } = credentials
|
||||||
|
|
||||||
|
const get = await getNoteRepech(id, niveau, mention_id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for updating note
|
||||||
|
ipcMain.handle('updatetNote', async (event, credentials) => {
|
||||||
|
const { formData, niveau, id, mention_id, annee_scolaire } = credentials
|
||||||
|
|
||||||
|
const update = await updateNote(formData, niveau, id, mention_id, annee_scolaire)
|
||||||
|
|
||||||
|
return update
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for updating note repech
|
||||||
|
ipcMain.handle('updatetNoteRepech', async (event, credentials) => {
|
||||||
|
const { formData2, niveau, id } = credentials
|
||||||
|
|
||||||
|
const update = await updateNoteRepech(formData2, niveau, id)
|
||||||
|
|
||||||
|
return update
|
||||||
|
})
|
||||||
|
|
||||||
|
// event to get single matiere
|
||||||
|
ipcMain.handle('getMatiereByID', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
|
||||||
|
const matiere = await getSingleMatiere(id)
|
||||||
|
|
||||||
|
return matiere
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for updating matiere
|
||||||
|
ipcMain.handle('updateMatiere', async (event, credentials) => {
|
||||||
|
const { nom, credit, uniter, ue, id } = credentials
|
||||||
|
|
||||||
|
const update = await updateMatiere(nom, id, credit, uniter, ue)
|
||||||
|
|
||||||
|
return update
|
||||||
|
})
|
||||||
|
ipcMain.handle('updateMatiereNiveau', async (event, credentials) => {
|
||||||
|
// credentials = { niveau_id, id }
|
||||||
|
const update = await updateMatiereNiveau(credentials) // ✅ on passe id + niveau_id
|
||||||
|
return update
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for importExcel
|
||||||
|
ipcMain.handle('importexcel', async (event, credentials) => {
|
||||||
|
const files = credentials
|
||||||
|
console.log(files)
|
||||||
|
const insert = await importFileToDatabase(files)
|
||||||
|
|
||||||
|
return insert
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for udatign a single niveau
|
||||||
|
ipcMain.handle('updateSingleNiveau', async (event, credentials) => {
|
||||||
|
const { nom, id } = credentials
|
||||||
|
|
||||||
|
const update = updateNiveau(nom, id)
|
||||||
|
|
||||||
|
return update
|
||||||
|
})
|
||||||
|
|
||||||
|
// event to get single niveau
|
||||||
|
ipcMain.handle('singleNiveau', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
|
||||||
|
const update = getSingleNiveau(id)
|
||||||
|
|
||||||
|
return update
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for creating matiere
|
||||||
|
ipcMain.handle('createMatiere', async (event, credentials) => {
|
||||||
|
const { nom, credit, uniter, ue } = credentials
|
||||||
|
|
||||||
|
const create = createMatiere(nom, credit, uniter, ue)
|
||||||
|
|
||||||
|
return create
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for import excel matiere
|
||||||
|
ipcMain.handle('importExcelMatiere', async (event, credentials) => {
|
||||||
|
const files = credentials
|
||||||
|
console.log(files)
|
||||||
|
const insert = await importFileToDatabaseMatiere(files)
|
||||||
|
|
||||||
|
return insert
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for import excel niveau
|
||||||
|
ipcMain.handle('importNiveau', async (event, credentials) => {
|
||||||
|
const files = credentials
|
||||||
|
console.log(files)
|
||||||
|
const insert = await importNiveau(files)
|
||||||
|
|
||||||
|
return insert
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for updating note systeme
|
||||||
|
ipcMain.handle('updateNoteSysteme', async (event, credentials) => {
|
||||||
|
const { id, admis, redouble, renvoyer } = credentials
|
||||||
|
|
||||||
|
const update = updateSysteme(id, admis, redouble, renvoyer)
|
||||||
|
return update
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for updating note systeme
|
||||||
|
ipcMain.handle('createAnneeScolaire', async (event, credentials) => {
|
||||||
|
const { code, debut, fin } = credentials
|
||||||
|
|
||||||
|
const create = createAnneeScolaire(code, debut, fin)
|
||||||
|
return create
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getMoyene', async (event, credentials) => {
|
||||||
|
const { niveau, scolaire } = credentials
|
||||||
|
console.log('index.js', niveau, scolaire)
|
||||||
|
|
||||||
|
const create = showMoyen(niveau, scolaire)
|
||||||
|
return create
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getMoyenneRepech', async (event, credentials) => {
|
||||||
|
const { niveau, scolaire } = credentials
|
||||||
|
console.log('index.js', niveau, scolaire)
|
||||||
|
|
||||||
|
const create = showMoyenRepech(niveau, scolaire)
|
||||||
|
return create
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('noteMatiere', async (event, credentials) => {
|
||||||
|
const { id, niveau, annee_scolaire } = credentials
|
||||||
|
|
||||||
|
const get = getMatiereAndNote(id, niveau, annee_scolaire)
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('displayMatiereFromForm', async (event, credentials) => {
|
||||||
|
const { niveau, mention_id, parcours } = credentials
|
||||||
|
|
||||||
|
const get = displayMatiereFromForm(niveau, mention_id, parcours)
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('createMention', async (event, credentials) => {
|
||||||
|
const { nom, uniter } = credentials
|
||||||
|
|
||||||
|
const get = createMention(nom, uniter)
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getSingleMention', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
|
||||||
|
const get = getSingleMention(id)
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('updateMention', async (event, credentials) => {
|
||||||
|
const { nom, uniter, id } = credentials
|
||||||
|
|
||||||
|
const get = updateMention(nom, uniter, id)
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('deleteMention', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
|
||||||
|
const get = deleteMention(id)
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('deleteNiveaus', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
|
||||||
|
const get = deleteNiveau(id)
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('deleteMatiere', async (event, id) => {
|
||||||
|
return await deleteMatiere(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
ipcMain.handle('asign', async (event, credentials) => {
|
||||||
|
const { formData, id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = asygnationToMention(formData, id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('asignSemestre', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
|
||||||
|
const get = getMentionMatiereChecked(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getAsign', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = getMentionMatiere(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('deleteAnneeScolaire', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = deleteAnneeScolaire(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getSemestreMatiere', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = getSemestreMatiere(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('insertUpdateMentionSemestre', async (event, credentials) => {
|
||||||
|
const { id, selectedSemestres } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = insertUpdateMentionSemestre(id, selectedSemestres)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getSingleAnneeScolaire', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = getSingleAnneScolaire(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('updateAnneeScolaire', async (event, credentials) => {
|
||||||
|
const { code, debut, fin, id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = updateAnneeScolaire(id, code, debut, fin)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('setCurrent', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = setCurrent(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('noteRelerer', async (event, credentials) => {
|
||||||
|
const { id, anneescolaire, niveau } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = getNotesWithRepechToDisplay(id, anneescolaire, niveau)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('updateNessesary', async (event, credentials) => {
|
||||||
|
const { id, multiplicateur } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = updateNessesaryTable(id, multiplicateur)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('insertProf', async (event, credentials) => {
|
||||||
|
const { nom_enseignant, prenom_enseignant, contact, date, matiere_id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = insertNewProf(matiere_id, nom_enseignant, prenom_enseignant, contact, date)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('insertParcours', async (event, credentials) => {
|
||||||
|
const { nom, uniter, mention_id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = insertParcour(nom, uniter, mention_id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getSingleParcours', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = getSingleParcours(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('deleteParcours', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = deletes(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('updateParcours', async (event, credentials) => {
|
||||||
|
const { nom, uniter, mention_id, id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = updateparcour(id, nom, uniter, mention_id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('parcourMatiere', async (event, credentials) => {
|
||||||
|
const { matiere_id, parcour_id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = parcourMatiere(matiere_id, parcour_id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getSingleProf', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = getSIngleProf(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('updateProf', async (event, credentials) => {
|
||||||
|
const { nom_enseignant, prenom_enseignant, contact, date, matiere_id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = updateProf(matiere_id, nom_enseignant, prenom_enseignant, contact, date)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('extractFiches', async (event, credentials) => {
|
||||||
|
const { matiere_id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = extractFiche(matiere_id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getParcourMatiere', async (event, credentials) => {
|
||||||
|
const { matiere_id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = getParcourMatiere(matiere_id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('changeParcours', async (event, credentials) => {
|
||||||
|
const { parcours, user_id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = updateParcours(parcours, user_id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('createTranche', async (event, credentials) => {
|
||||||
|
const { etudiant_id, tranchename, montant } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = createTranche(etudiant_id, tranchename, montant)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getTranche', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = getTranche(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('updateTranche', async (event, credentials) => {
|
||||||
|
const { id, tranchename, montant } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = updateTranche(id, tranchename, montant)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('deleteTranche', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
console.log(id)
|
||||||
|
const get = deleteTranche(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('deleteEtudiant', async (event, id) => {
|
||||||
|
return await deleteEtudiant(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('getSingleTranche', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = getSingleTranche(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('createIPConfig', async (event, credentials) => {
|
||||||
|
const { ipname } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = createConfigIp(ipname)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('updateIPConfig', async (event, credentials) => {
|
||||||
|
const { id, ipname } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = updateIPConfig(id, ipname)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
903
src/main/index.js
Normal file
903
src/main/index.js
Normal file
@ -0,0 +1,903 @@
|
|||||||
|
import { app, shell, BrowserWindow, ipcMain, Tray, Menu } from 'electron'
|
||||||
|
import { join } from 'path'
|
||||||
|
const path = require('path')
|
||||||
|
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
|
||||||
|
import icon from '../../resources/logo.ico?asset' // Your tray icon file
|
||||||
|
const database = require('../../database/database')
|
||||||
|
|
||||||
|
database
|
||||||
|
.createTables()
|
||||||
|
.then(() => database.insertDefaultAdmin())
|
||||||
|
.then(() => database.insertStatusesIfNotExist())
|
||||||
|
.catch(console.error)
|
||||||
|
|
||||||
|
const { loginUsers, insertUser, updateUser } = require('../../database/Models/Users')
|
||||||
|
const { createConfigIp, updateIPConfig } = require('../../database/Models/IpConfig')
|
||||||
|
const { importFileToDatabase } = require('../../database/import/Etudiants')
|
||||||
|
const {
|
||||||
|
insertEtudiant,
|
||||||
|
getSingleEtudiant,
|
||||||
|
FilterDataByNiveau,
|
||||||
|
updateEtudiant,
|
||||||
|
changePDP,
|
||||||
|
updateParcours,
|
||||||
|
createTranche,
|
||||||
|
getTranche,
|
||||||
|
updateTranche,
|
||||||
|
deleteTranche,
|
||||||
|
getSingleTranche
|
||||||
|
} = require('../../database/Models/Etudiants')
|
||||||
|
const {
|
||||||
|
insertNiveau,
|
||||||
|
updateNiveau,
|
||||||
|
getSingleNiveau,
|
||||||
|
deleteNiveau
|
||||||
|
} = require('../../database/Models/Niveau')
|
||||||
|
const {
|
||||||
|
insertNote,
|
||||||
|
getNote,
|
||||||
|
updateNote,
|
||||||
|
showMoyen,
|
||||||
|
getMatiereAndNote,
|
||||||
|
getNotesWithRepechToDisplay
|
||||||
|
} = require('../../database/Models/Notes')
|
||||||
|
const {
|
||||||
|
createMatiere,
|
||||||
|
getSingleMatiere,
|
||||||
|
updateMatiere,
|
||||||
|
updateMatiereNiveau,
|
||||||
|
displayMatiereFromForm,
|
||||||
|
deleteMatiere,
|
||||||
|
deleteEtudiant,
|
||||||
|
asygnationToMention,
|
||||||
|
getMentionMatiere,
|
||||||
|
getMentionMatiereChecked,
|
||||||
|
getSemestreMatiere,
|
||||||
|
insertUpdateMentionSemestre,
|
||||||
|
insertNewProf,
|
||||||
|
getSIngleProf,
|
||||||
|
updateProf
|
||||||
|
} = require('../../database/Models/Matieres')
|
||||||
|
const { importFileToDatabaseMatiere } = require('../../database/import/Matieres')
|
||||||
|
const { importNiveau } = require('../../database/import/Niveau')
|
||||||
|
const { updateSysteme } = require('../../database/Models/NoteSysrem')
|
||||||
|
const {
|
||||||
|
createAnneeScolaire,
|
||||||
|
deleteAnneeScolaire,
|
||||||
|
getSingleAnneScolaire,
|
||||||
|
updateAnneeScolaire,
|
||||||
|
setCurrent
|
||||||
|
} = require('../../database/Models/AnneeScolaire')
|
||||||
|
const {
|
||||||
|
createMention,
|
||||||
|
deleteMention,
|
||||||
|
getSingleMention,
|
||||||
|
updateMention
|
||||||
|
} = require('../../database/Models/Mentions')
|
||||||
|
const {
|
||||||
|
getNoteRepech,
|
||||||
|
updateNoteRepech,
|
||||||
|
showMoyenRepech
|
||||||
|
} = require('../../database/Models/NoteRepechage')
|
||||||
|
const {
|
||||||
|
updateCurrentYears,
|
||||||
|
updateStudents,
|
||||||
|
updateNessesaryTable
|
||||||
|
} = require('../../database/function/System')
|
||||||
|
const { autoUpdater } = require('electron-updater')
|
||||||
|
const { URL } = require('../../database/api/Config')
|
||||||
|
const {
|
||||||
|
insertParcour,
|
||||||
|
getSingleParcours,
|
||||||
|
deletes,
|
||||||
|
updateparcour,
|
||||||
|
parcourMatiere,
|
||||||
|
extractFiche,
|
||||||
|
getParcourMatiere
|
||||||
|
} = require('../../database/Models/Parcours')
|
||||||
|
|
||||||
|
// Declare mainWindow and tray in the global scope
|
||||||
|
let mainWindow
|
||||||
|
let tray = null
|
||||||
|
updateCurrentYears()
|
||||||
|
updateStudents()
|
||||||
|
|
||||||
|
autoUpdater.setFeedURL({
|
||||||
|
provider: 'generic',
|
||||||
|
url: `${URL}/latest` // Ensure this points to the folder containing latest.yml
|
||||||
|
})
|
||||||
|
|
||||||
|
function createWindow() {
|
||||||
|
// Create the browser window.
|
||||||
|
mainWindow = new BrowserWindow({
|
||||||
|
width: 1375,
|
||||||
|
minWidth: 1375,
|
||||||
|
height: 740,
|
||||||
|
minHeight: 740,
|
||||||
|
show: false,
|
||||||
|
autoHideMenuBar: true,
|
||||||
|
fullscreen: false,
|
||||||
|
icon: path.join(__dirname, 'resources', 'logo.ico'), // Path to your icon,
|
||||||
|
...(process.platform === 'linux' ? { icon } : {}),
|
||||||
|
webPreferences: {
|
||||||
|
preload: join(__dirname, '../preload/index.js'),
|
||||||
|
nodeIntegration: true,
|
||||||
|
contextIsolation: true,
|
||||||
|
sandbox: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Désactiver les raccourcis clavier
|
||||||
|
mainWindow.webContents.on('before-input-event', (event, input) => {
|
||||||
|
if (input.control || input.meta || input.alt || input.key === 'F11') {
|
||||||
|
event.preventDefault()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
mainWindow.on('ready-to-show', () => {
|
||||||
|
mainWindow.maximize() // Maximiser la fenêtre
|
||||||
|
mainWindow.show()
|
||||||
|
})
|
||||||
|
|
||||||
|
mainWindow.webContents.setWindowOpenHandler((details) => {
|
||||||
|
shell.openExternal(details.url)
|
||||||
|
return { action: 'deny' }
|
||||||
|
})
|
||||||
|
|
||||||
|
// Load the appropriate URL based on environment
|
||||||
|
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
|
||||||
|
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
|
||||||
|
} else {
|
||||||
|
mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle window close (hide instead of closing)
|
||||||
|
mainWindow.on('close', (event) => {
|
||||||
|
if (!app.isQuiting) {
|
||||||
|
event.preventDefault()
|
||||||
|
mainWindow.hide() // Minimize to tray instead of closing
|
||||||
|
} else {
|
||||||
|
// Destroy the tray when quitting
|
||||||
|
if (tray) tray.destroy()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to create the system tray
|
||||||
|
function createTray() {
|
||||||
|
const iconPath = icon // Use your icon path here
|
||||||
|
tray = new Tray(iconPath)
|
||||||
|
|
||||||
|
// Create a context menu for the tray
|
||||||
|
const contextMenu = Menu.buildFromTemplate([
|
||||||
|
{
|
||||||
|
label: 'Ouvrir',
|
||||||
|
click: () => {
|
||||||
|
mainWindow.show()
|
||||||
|
mainWindow.webContents.send('navigateToRoute', '#/') // Send the route as a string
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'A Propos',
|
||||||
|
click: () => {
|
||||||
|
mainWindow.show()
|
||||||
|
mainWindow.webContents.send('navigateToRoute', '#/apropos') // Send the route as a string
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Quit',
|
||||||
|
click: () => {
|
||||||
|
// Clear localStorage in the renderer process
|
||||||
|
mainWindow.webContents
|
||||||
|
.executeJavaScript('localStorage.removeItem("ACCESS_TOKEN");')
|
||||||
|
.then(() => {
|
||||||
|
console.log('localStorage cleared.')
|
||||||
|
// Ensure the app quits entirely
|
||||||
|
if (tray) {
|
||||||
|
app.quit()
|
||||||
|
tray.destroy()
|
||||||
|
// if (app.quit()) {
|
||||||
|
// tray.destroy()
|
||||||
|
// }
|
||||||
|
} // Quit the app
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error('Error clearing localStorage:', err)
|
||||||
|
// Quit the app even if clearing fails
|
||||||
|
if (tray) {
|
||||||
|
app.quit()
|
||||||
|
tray.destroy()
|
||||||
|
// if (app.quit()) {
|
||||||
|
// tray.destroy()
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
tray.setToolTip('My Electron App')
|
||||||
|
tray.setContextMenu(contextMenu)
|
||||||
|
|
||||||
|
// Show the app when the tray icon is clicked
|
||||||
|
tray.on('click', () => {
|
||||||
|
mainWindow.show()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
electronApp.setAppUserModelId('com.electron')
|
||||||
|
autoUpdater.checkForUpdatesAndNotify()
|
||||||
|
|
||||||
|
app.on('browser-window-created', (_, window) => {
|
||||||
|
optimizer.watchWindowShortcuts(window)
|
||||||
|
})
|
||||||
|
|
||||||
|
createWindow()
|
||||||
|
createTray() // Create the tray icon
|
||||||
|
|
||||||
|
app.on('activate', function () {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// When an update is available
|
||||||
|
autoUpdater.on('update-available', () => {
|
||||||
|
dialog.showMessageBox({
|
||||||
|
type: 'info',
|
||||||
|
title: 'Mise à jour disponible',
|
||||||
|
message: 'Une nouvelle version est disponible. Téléchargement en cours...'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// When the update is downloaded
|
||||||
|
autoUpdater.on('update-downloaded', (info) => {
|
||||||
|
dialog
|
||||||
|
.showMessageBox({
|
||||||
|
type: 'info',
|
||||||
|
title: 'Mise à jour prête',
|
||||||
|
message: `La version ${info.version} a été téléchargée. Redémarrer maintenant ?`,
|
||||||
|
buttons: ['Redémarrer', 'Plus tard']
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
if (result.response === 0) {
|
||||||
|
autoUpdater.quitAndInstall()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// If an error occurs
|
||||||
|
autoUpdater.on('error', (error) => {
|
||||||
|
dialog.showErrorBox('Update Error', error == null ? 'Unknown' : error.message)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Quit the app when all windows are closed, except on macOS
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// In this file you can include the rest of your app"s specific main process
|
||||||
|
// code. You can also put them in separate files and require them here.
|
||||||
|
|
||||||
|
// event for quit app
|
||||||
|
ipcMain.handle('quit', async () => {
|
||||||
|
app.quit()
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for minimizing the app
|
||||||
|
ipcMain.handle('minimize', async () => {
|
||||||
|
if (mainWindow) {
|
||||||
|
mainWindow.minimize()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('login', async (event, credentials) => {
|
||||||
|
const { username, password } = credentials
|
||||||
|
|
||||||
|
// Pass username and password to loginUsers
|
||||||
|
let response = await loginUsers(username, password)
|
||||||
|
|
||||||
|
return response
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('insertUser', async (event, credentials) => {
|
||||||
|
const { username, email, password, roles } = credentials
|
||||||
|
|
||||||
|
const users = await insertUser(username, email, password, roles)
|
||||||
|
|
||||||
|
return users
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('updateUsers', async (event, credentials) => {
|
||||||
|
const { username, email, password, id } = credentials
|
||||||
|
|
||||||
|
const update = await updateUser(username, email, password, id)
|
||||||
|
|
||||||
|
return update
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for insert etudiants
|
||||||
|
ipcMain.handle('insertEtudiant', async (event, credentials) => {
|
||||||
|
const {
|
||||||
|
nom,
|
||||||
|
prenom,
|
||||||
|
photos,
|
||||||
|
date_de_naissances,
|
||||||
|
niveau,
|
||||||
|
annee_scolaire,
|
||||||
|
status,
|
||||||
|
num_inscription,
|
||||||
|
mention_id,
|
||||||
|
sexe,
|
||||||
|
nationaliter,
|
||||||
|
cin,
|
||||||
|
date_delivrence,
|
||||||
|
annee_bacc,
|
||||||
|
serie,
|
||||||
|
boursier,
|
||||||
|
domaine,
|
||||||
|
contact,
|
||||||
|
parcours
|
||||||
|
} = credentials
|
||||||
|
|
||||||
|
const insert = await insertEtudiant(
|
||||||
|
nom,
|
||||||
|
prenom,
|
||||||
|
photos,
|
||||||
|
date_de_naissances,
|
||||||
|
niveau,
|
||||||
|
annee_scolaire,
|
||||||
|
status,
|
||||||
|
num_inscription,
|
||||||
|
mention_id,
|
||||||
|
sexe,
|
||||||
|
nationaliter,
|
||||||
|
cin,
|
||||||
|
date_delivrence,
|
||||||
|
annee_bacc,
|
||||||
|
serie,
|
||||||
|
boursier,
|
||||||
|
domaine,
|
||||||
|
contact,
|
||||||
|
parcours
|
||||||
|
)
|
||||||
|
|
||||||
|
return insert
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for fetching single
|
||||||
|
ipcMain.handle('getByNiveau', async (event, credentials) => {
|
||||||
|
const { niveau } = credentials
|
||||||
|
|
||||||
|
const getSingle = await FilterDataByNiveau(niveau)
|
||||||
|
|
||||||
|
return getSingle
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for fetching single
|
||||||
|
ipcMain.handle('single', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
|
||||||
|
const getSingle = await getSingleEtudiant(id)
|
||||||
|
|
||||||
|
return getSingle
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for inserting niveau
|
||||||
|
ipcMain.handle('insertNiveau', async (event, credentials) => {
|
||||||
|
const { nom } = credentials
|
||||||
|
|
||||||
|
const insert = await insertNiveau(nom)
|
||||||
|
|
||||||
|
return insert
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for updating etudiants
|
||||||
|
ipcMain.handle('updateETudiants', async (event, credentials) => {
|
||||||
|
const {
|
||||||
|
nom,
|
||||||
|
prenom,
|
||||||
|
photos,
|
||||||
|
date_de_naissances,
|
||||||
|
niveau,
|
||||||
|
annee_scolaire,
|
||||||
|
status,
|
||||||
|
mention_id,
|
||||||
|
num_inscription,
|
||||||
|
id,
|
||||||
|
sexe,
|
||||||
|
nationalite,
|
||||||
|
cin,
|
||||||
|
date_delivrance,
|
||||||
|
annee_bacc,
|
||||||
|
serie,
|
||||||
|
boursier,
|
||||||
|
domaine,
|
||||||
|
contact,
|
||||||
|
parcours
|
||||||
|
} = credentials
|
||||||
|
|
||||||
|
const updating = await updateEtudiant(
|
||||||
|
nom,
|
||||||
|
prenom,
|
||||||
|
photos,
|
||||||
|
date_de_naissances,
|
||||||
|
niveau,
|
||||||
|
annee_scolaire,
|
||||||
|
status,
|
||||||
|
mention_id,
|
||||||
|
num_inscription,
|
||||||
|
id,
|
||||||
|
sexe,
|
||||||
|
nationalite,
|
||||||
|
cin,
|
||||||
|
date_delivrance,
|
||||||
|
annee_bacc,
|
||||||
|
serie,
|
||||||
|
boursier,
|
||||||
|
domaine,
|
||||||
|
contact,
|
||||||
|
parcours
|
||||||
|
)
|
||||||
|
|
||||||
|
return updating
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for updating etudiants pdp
|
||||||
|
ipcMain.handle('updateETudiantsPDP', async (event, credentials) => {
|
||||||
|
const { pdp, id } = credentials
|
||||||
|
|
||||||
|
const updating = await changePDP(pdp, id)
|
||||||
|
|
||||||
|
return updating
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for adding notes
|
||||||
|
ipcMain.handle('insertNote', async (event, credentials) => {
|
||||||
|
const { etudiant_id, etudiant_niveau, mention_id, formData, annee_scolaire } = credentials
|
||||||
|
|
||||||
|
const insert = await insertNote(
|
||||||
|
etudiant_id,
|
||||||
|
etudiant_niveau,
|
||||||
|
mention_id,
|
||||||
|
formData,
|
||||||
|
annee_scolaire
|
||||||
|
)
|
||||||
|
|
||||||
|
return insert
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for get single note
|
||||||
|
ipcMain.handle('getSingleNote', async (event, credentials) => {
|
||||||
|
const { id, niveau, mention_id } = credentials
|
||||||
|
|
||||||
|
const get = await getNote(id, niveau, mention_id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for get single note repech
|
||||||
|
ipcMain.handle('getNotesRepech', async (event, credentials) => {
|
||||||
|
const { id, niveau, mention_id } = credentials
|
||||||
|
|
||||||
|
const get = await getNoteRepech(id, niveau, mention_id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for updating note
|
||||||
|
ipcMain.handle('updatetNote', async (event, credentials) => {
|
||||||
|
const { formData, niveau, id, mention_id, annee_scolaire } = credentials
|
||||||
|
|
||||||
|
const update = await updateNote(formData, niveau, id, mention_id, annee_scolaire)
|
||||||
|
|
||||||
|
return update
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for updating note repech
|
||||||
|
ipcMain.handle('updatetNoteRepech', async (event, credentials) => {
|
||||||
|
const { formData2, niveau, id } = credentials
|
||||||
|
|
||||||
|
const update = await updateNoteRepech(formData2, niveau, id)
|
||||||
|
|
||||||
|
return update
|
||||||
|
})
|
||||||
|
|
||||||
|
// event to get single matiere
|
||||||
|
ipcMain.handle('getMatiereByID', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
|
||||||
|
const matiere = await getSingleMatiere(id)
|
||||||
|
|
||||||
|
return matiere
|
||||||
|
})
|
||||||
|
|
||||||
|
// // event for updating matiere
|
||||||
|
ipcMain.handle('updateMatiere', async (event, credentials) => {
|
||||||
|
const { nom, credit, uniter, ue, id } = credentials
|
||||||
|
|
||||||
|
const update = await updateMatiere(nom, id, credit, uniter, ue)
|
||||||
|
|
||||||
|
return update
|
||||||
|
})
|
||||||
|
ipcMain.handle('updateMatiereNiveau', async (event, credentials) => {
|
||||||
|
// credentials = { niveau_id, id }
|
||||||
|
const update = await updateMatiereNiveau(credentials) // ✅ on passe id + niveau_id
|
||||||
|
return update
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for importExcel
|
||||||
|
ipcMain.handle('importexcel', async (event, credentials) => {
|
||||||
|
const files = credentials
|
||||||
|
console.log(files)
|
||||||
|
const insert = await importFileToDatabase(files)
|
||||||
|
|
||||||
|
return insert
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for udatign a single niveau
|
||||||
|
ipcMain.handle('updateSingleNiveau', async (event, credentials) => {
|
||||||
|
const { nom, id } = credentials
|
||||||
|
|
||||||
|
const update = updateNiveau(nom, id)
|
||||||
|
|
||||||
|
return update
|
||||||
|
})
|
||||||
|
|
||||||
|
// event to get single niveau
|
||||||
|
ipcMain.handle('singleNiveau', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
|
||||||
|
const update = getSingleNiveau(id)
|
||||||
|
|
||||||
|
return update
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for creating matiere
|
||||||
|
ipcMain.handle('createMatiere', async (event, credentials) => {
|
||||||
|
const { nom, credit, uniter, ue } = credentials
|
||||||
|
|
||||||
|
const create = createMatiere(nom, credit, uniter, ue)
|
||||||
|
|
||||||
|
return create
|
||||||
|
})
|
||||||
|
|
||||||
|
// // event for import excel matiere
|
||||||
|
ipcMain.handle('importExcelMatiere', async (event, credentials) => {
|
||||||
|
const files = credentials
|
||||||
|
console.log(files)
|
||||||
|
const insert = await importFileToDatabaseMatiere(files)
|
||||||
|
|
||||||
|
return insert
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for import excel niveau
|
||||||
|
ipcMain.handle('importNiveau', async (event, credentials) => {
|
||||||
|
const files = credentials
|
||||||
|
console.log(files)
|
||||||
|
const insert = await importNiveau(files)
|
||||||
|
|
||||||
|
return insert
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for updating note systeme
|
||||||
|
ipcMain.handle('updateNoteSysteme', async (event, credentials) => {
|
||||||
|
const { id, admis, redouble, renvoyer } = credentials
|
||||||
|
|
||||||
|
const update = updateSysteme(id, admis, redouble, renvoyer)
|
||||||
|
return update
|
||||||
|
})
|
||||||
|
|
||||||
|
// event for updating note systeme
|
||||||
|
ipcMain.handle('createAnneeScolaire', async (event, credentials) => {
|
||||||
|
const { code, debut, fin } = credentials
|
||||||
|
|
||||||
|
const create = createAnneeScolaire(code, debut, fin)
|
||||||
|
return create
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getMoyene', async (event, credentials) => {
|
||||||
|
const { niveau, scolaire } = credentials
|
||||||
|
console.log('index.js', niveau, scolaire)
|
||||||
|
|
||||||
|
const create = showMoyen(niveau, scolaire)
|
||||||
|
return create
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getMoyenneRepech', async (event, credentials) => {
|
||||||
|
const { niveau, scolaire } = credentials
|
||||||
|
console.log('index.js', niveau, scolaire)
|
||||||
|
|
||||||
|
const create = showMoyenRepech(niveau, scolaire)
|
||||||
|
return create
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('noteMatiere', async (event, credentials) => {
|
||||||
|
const { id, niveau, annee_scolaire } = credentials
|
||||||
|
|
||||||
|
const get = getMatiereAndNote(id, niveau, annee_scolaire)
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('displayMatiereFromForm', async (event, credentials) => {
|
||||||
|
const { niveau, mention_id, parcours } = credentials
|
||||||
|
|
||||||
|
const get = displayMatiereFromForm(niveau, mention_id, parcours)
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('createMention', async (event, credentials) => {
|
||||||
|
const { nom, uniter } = credentials
|
||||||
|
|
||||||
|
const get = createMention(nom, uniter)
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getSingleMention', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
|
||||||
|
const get = getSingleMention(id)
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('updateMention', async (event, credentials) => {
|
||||||
|
const { nom, uniter, id } = credentials
|
||||||
|
|
||||||
|
const get = updateMention(nom, uniter, id)
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('deleteMention', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
|
||||||
|
const get = deleteMention(id)
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('deleteNiveaus', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
|
||||||
|
const get = deleteNiveau(id)
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
ipcMain.handle('deleteMatiere', async (event, id) => {
|
||||||
|
return await deleteMatiere(id);
|
||||||
|
});
|
||||||
|
ipcMain.handle('deleteEtudiant', async (event, id) => {
|
||||||
|
return await deleteEtudiant(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
ipcMain.handle('asign', async (event, credentials) => {
|
||||||
|
const { formData, id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = asygnationToMention(formData, id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('asignSemestre', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
|
||||||
|
const get = getMentionMatiereChecked(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getAsign', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = getMentionMatiere(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('deleteAnneeScolaire', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = deleteAnneeScolaire(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getSemestreMatiere', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = getSemestreMatiere(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('insertUpdateMentionSemestre', async (event, credentials) => {
|
||||||
|
const { id, selectedSemestres } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = insertUpdateMentionSemestre(id, selectedSemestres)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getSingleAnneeScolaire', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = getSingleAnneScolaire(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('updateAnneeScolaire', async (event, credentials) => {
|
||||||
|
const { code, debut, fin, id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = updateAnneeScolaire(id, code, debut, fin)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('setCurrent', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = setCurrent(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('noteRelerer', async (event, credentials) => {
|
||||||
|
const { id, anneescolaire, niveau } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = getNotesWithRepechToDisplay(id, anneescolaire, niveau)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('updateNessesary', async (event, credentials) => {
|
||||||
|
const { id, multiplicateur } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = updateNessesaryTable(id, multiplicateur)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('insertProf', async (event, credentials) => {
|
||||||
|
const { nom_enseignant, prenom_enseignant, contact, date, matiere_id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = insertNewProf(matiere_id, nom_enseignant, prenom_enseignant, contact, date)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('insertParcours', async (event, credentials) => {
|
||||||
|
const { nom, uniter, mention_id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = insertParcour(nom, uniter, mention_id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getSingleParcours', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = getSingleParcours(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('deleteParcours', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = deletes(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('updateParcours', async (event, credentials) => {
|
||||||
|
const { nom, uniter, mention_id, id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = updateparcour(id, nom, uniter, mention_id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('parcourMatiere', async (event, credentials) => {
|
||||||
|
const { matiere_id, parcour_id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = parcourMatiere(matiere_id, parcour_id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getSingleProf', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = getSIngleProf(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('updateProf', async (event, credentials) => {
|
||||||
|
const { nom_enseignant, prenom_enseignant, contact, date, matiere_id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = updateProf(matiere_id, nom_enseignant, prenom_enseignant, contact, date)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('extractFiches', async (event, credentials) => {
|
||||||
|
const { matiere_id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = extractFiche(matiere_id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getParcourMatiere', async (event, credentials) => {
|
||||||
|
const { matiere_id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = getParcourMatiere(matiere_id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('changeParcours', async (event, credentials) => {
|
||||||
|
const { parcours, user_id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = updateParcours(parcours, user_id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('createTranche', async (event, credentials) => {
|
||||||
|
const { etudiant_id, tranchename, montant } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = createTranche(etudiant_id, tranchename, montant)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getTranche', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = getTranche(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('updateTranche', async (event, credentials) => {
|
||||||
|
const { id, tranchename, montant } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = updateTranche(id, tranchename, montant)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('deleteTranche', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
console.log(id)
|
||||||
|
const get = deleteTranche(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('getSingleTranche', async (event, credentials) => {
|
||||||
|
const { id } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = getSingleTranche(id)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('createIPConfig', async (event, credentials) => {
|
||||||
|
const { ipname } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = createConfigIp(ipname)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcMain.handle('updateIPConfig', async (event, credentials) => {
|
||||||
|
const { id, ipname } = credentials
|
||||||
|
// console.log(formData, id);
|
||||||
|
const get = updateIPConfig(id, ipname)
|
||||||
|
|
||||||
|
return get
|
||||||
|
})
|
||||||
212
src/preload/index.backup.js
Normal file
212
src/preload/index.backup.js
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
import { contextBridge, ipcRenderer } from 'electron'
|
||||||
|
import { electronAPI } from '@electron-toolkit/preload'
|
||||||
|
const { getNessesarytable } = require('../../database/function/System')
|
||||||
|
const { getNiveau } = require('../../database/Models/Niveau')
|
||||||
|
const { getAllUsers } = require('../../database/Models/Users')
|
||||||
|
const { getAllEtudiants, getDataToDashboard } = require('../../database/Models/Etudiants')
|
||||||
|
const { verifyEtudiantIfHeHasNotes, blockShowMoyene } = require('../../database/Models/Notes')
|
||||||
|
|
||||||
|
const { synchronizeData } = require('../../database/api/SyncronisationDataUsers')
|
||||||
|
const { synchronizeDataEtudiants } = require('../../database/api/SyncronisationDataEtudiants')
|
||||||
|
const { synchronizeDataNotes } = require('../../database/api/CheckUpdateNote')
|
||||||
|
const { getMatiere, getSemestre, getEnseignants } = require('../../database/Models/Matieres')
|
||||||
|
const { getSysteme } = require('../../database/Models/NoteSysrem')
|
||||||
|
const { getStatus } = require('../../database/Models/Status')
|
||||||
|
const { getAnneeScolaire, getInterval } = require('../../database/Models/AnneeScolaire')
|
||||||
|
const { getMentions } = require('../../database/Models/Mentions')
|
||||||
|
const { getAll } = require('../../database/api/Get')
|
||||||
|
const { getParcours } = require('../../database/Models/Parcours')
|
||||||
|
const { getIPConfig } = require('../../database/Models/IpConfig')
|
||||||
|
|
||||||
|
// Custom APIs for renderer
|
||||||
|
const api = {}
|
||||||
|
|
||||||
|
// Use `contextBridge` APIs to expose Electron APIs to
|
||||||
|
// renderer only if context isolation is enabled, otherwise
|
||||||
|
// just add to the DOM global.
|
||||||
|
if (process.contextIsolated) {
|
||||||
|
try {
|
||||||
|
contextBridge.exposeInMainWorld('electron', electronAPI)
|
||||||
|
contextBridge.exposeInMainWorld('api', api)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextBridge for Tray
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('Tray', {
|
||||||
|
onNavigate: (callback) => {
|
||||||
|
ipcRenderer.on('navigateToRoute', (event, route) => {
|
||||||
|
callback(route) // Pass the route to the renderer callback
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextBridge for users
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('allUser', {
|
||||||
|
users: () => getAllUsers(),
|
||||||
|
login: (credentials) => ipcRenderer.invoke('login', credentials),
|
||||||
|
insertUsers: (credentials) => ipcRenderer.invoke('insertUser', credentials),
|
||||||
|
forgotPassword: (credentials) => ipcRenderer.invoke('forgotPassword', credentials),
|
||||||
|
quit: () => ipcRenderer.invoke('quit'),
|
||||||
|
minimize: () => ipcRenderer.invoke('minimize'),
|
||||||
|
updateUsers: (credentials) => ipcRenderer.invoke('updateUsers', credentials)
|
||||||
|
})
|
||||||
|
|
||||||
|
contextBridge.exposeInMainWorld('syncro', {
|
||||||
|
getall: () => getAll()
|
||||||
|
})
|
||||||
|
|
||||||
|
// syncronisation des donner
|
||||||
|
window.addEventListener('online', async () => {
|
||||||
|
if (navigator.onLine) {
|
||||||
|
// synchronizeData()
|
||||||
|
// synchronizeDataEtudiants()
|
||||||
|
// synchronizeDataNotes()
|
||||||
|
await getAll()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// send data
|
||||||
|
getAll()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextBridge for etudiants
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('etudiants', {
|
||||||
|
insertEtudiant: (credentials) => ipcRenderer.invoke('insertEtudiant', credentials),
|
||||||
|
getEtudiants: () => getAllEtudiants(),
|
||||||
|
FilterDataByNiveau: (credential) => ipcRenderer.invoke('getByNiveau', credential),
|
||||||
|
getSingle: (credential) => ipcRenderer.invoke('single', credential),
|
||||||
|
updateEtudiants: (credentials) => ipcRenderer.invoke('updateETudiants', credentials),
|
||||||
|
getDataToDashboards: () => getDataToDashboard(),
|
||||||
|
updateEtudiantsPDP: (credentials) => ipcRenderer.invoke('updateETudiantsPDP', credentials),
|
||||||
|
importExcel: (credentials) => ipcRenderer.invoke('importexcel', credentials),
|
||||||
|
changeParcours: (credentials) => ipcRenderer.invoke('changeParcours', credentials),
|
||||||
|
createTranche: (credentials) => ipcRenderer.invoke('createTranche', credentials),
|
||||||
|
getTranche: (credentials) => ipcRenderer.invoke('getTranche', credentials),
|
||||||
|
updateTranche: (credentials) => ipcRenderer.invoke('updateTranche', credentials),
|
||||||
|
deleteTranche: (credentials) => ipcRenderer.invoke('deleteTranche', credentials),
|
||||||
|
getSingleTranche: (credentials) => ipcRenderer.invoke('getSingleTranche', credentials)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cobtextBridge for niveaus
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('niveaus', {
|
||||||
|
getNiveau: () => getNiveau(),
|
||||||
|
getSingleNiveau: (credential) => ipcRenderer.invoke('singleNiveau', credential),
|
||||||
|
insertNiveau: (credentials) => ipcRenderer.invoke('insertNiveau', credentials),
|
||||||
|
updateSingleNiveau: (credentials) => ipcRenderer.invoke('updateSingleNiveau', credentials),
|
||||||
|
importNiveau: (credentials) => ipcRenderer.invoke('importNiveau', credentials),
|
||||||
|
deleteNiveaus: (credentials) => ipcRenderer.invoke('deleteNiveaus', credentials)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextBridge for notes
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('notes', {
|
||||||
|
getNotes: (credentials) => ipcRenderer.invoke('getSingleNote', credentials),
|
||||||
|
insertNote: (credentials) => ipcRenderer.invoke('insertNote', credentials),
|
||||||
|
updateNote: (credentials) => ipcRenderer.invoke('updatetNote', credentials),
|
||||||
|
getMoyenne: (credentials) => ipcRenderer.invoke('getMoyene', credentials),
|
||||||
|
noteMatiere: (credentials) => ipcRenderer.invoke('noteMatiere', credentials),
|
||||||
|
noteRelerer: (credentials) => ipcRenderer.invoke('noteRelerer', credentials),
|
||||||
|
getMoyenneVerify: () => verifyEtudiantIfHeHasNotes(),
|
||||||
|
getblockNote: () => blockShowMoyene()
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextbridge for note repechage
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('noteRepech', {
|
||||||
|
getNotesRepech: (credentials) => ipcRenderer.invoke('getNotesRepech', credentials),
|
||||||
|
updateNoteRepech: (credentials) => ipcRenderer.invoke('updatetNoteRepech', credentials),
|
||||||
|
getMoyenneRepech: (credentials) => ipcRenderer.invoke('getMoyenneRepech', credentials)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextBridge for matieres
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('matieres', {
|
||||||
|
getMatiere: () => getMatiere(),
|
||||||
|
createMatiere: (credentials) => ipcRenderer.invoke('createMatiere', credentials),
|
||||||
|
getMatiereByID: (credentials) => ipcRenderer.invoke('getMatiereByID', credentials),
|
||||||
|
updateMatiere: (credentials) => ipcRenderer.invoke('updateMatiere', credentials),
|
||||||
|
updateMatiereNiveau: (credentials) => ipcRenderer.invoke('updateMatiereNiveau', credentials),
|
||||||
|
importExcel: (credentials) => ipcRenderer.invoke('importExcelMatiere', credentials),
|
||||||
|
displayMatiereFromForm: (credentials) =>
|
||||||
|
ipcRenderer.invoke('displayMatiereFromForm', credentials),
|
||||||
|
deleteMatiere: (credentials) => ipcRenderer.invoke('deleteMatiere', credentials),
|
||||||
|
deleteEtudiant: (credentials) => ipcRenderer.invoke('deleteEtudiant', credentials),
|
||||||
|
asign: (credentials) => ipcRenderer.invoke('asign', credentials),
|
||||||
|
getAsign: (credentials) => ipcRenderer.invoke('getAsign', credentials),
|
||||||
|
asignSemestre: (credentials) => ipcRenderer.invoke('asignSemestre', credentials),
|
||||||
|
getSemestreMatiere: (credentials) => ipcRenderer.invoke('getSemestreMatiere', credentials),
|
||||||
|
getSemestre: () => getSemestre(),
|
||||||
|
getNessesary: () => getNessesarytable(),
|
||||||
|
getENseignant: () => getEnseignants(),
|
||||||
|
insertUpdateMentionSemestre: (credentials) =>
|
||||||
|
ipcRenderer.invoke('insertUpdateMentionSemestre', credentials),
|
||||||
|
updateNessesary: (credentials) => ipcRenderer.invoke('updateNessesary', credentials),
|
||||||
|
insertProf: (credentials) => ipcRenderer.invoke('insertProf', credentials),
|
||||||
|
getSingleProf: (credentials) => ipcRenderer.invoke('getSingleProf', credentials),
|
||||||
|
updateProf: (credentials) => ipcRenderer.invoke('updateProf', credentials)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextBridge for note systeme
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('notesysteme', {
|
||||||
|
getSyteme: () => getSysteme(),
|
||||||
|
updateNoteSysteme: (credentials) => ipcRenderer.invoke('updateNoteSysteme', credentials),
|
||||||
|
insertParcours: (credentials) => ipcRenderer.invoke('insertParcours', credentials),
|
||||||
|
getSingleParcours: (credentials) => ipcRenderer.invoke('getSingleParcours', credentials),
|
||||||
|
deleteParcours: (credentials) => ipcRenderer.invoke('deleteParcours', credentials),
|
||||||
|
updateParcours: (credentials) => ipcRenderer.invoke('updateParcours', credentials),
|
||||||
|
parcourMatiere: (credentials) => ipcRenderer.invoke('parcourMatiere', credentials),
|
||||||
|
getParcours: () => getParcours(),
|
||||||
|
extractFiches: (credentials) => ipcRenderer.invoke('extractFiches', credentials),
|
||||||
|
getParcourMatiere: (credentials) => ipcRenderer.invoke('getParcourMatiere', credentials),
|
||||||
|
createIPConfig: (credentials) => ipcRenderer.invoke('createIPConfig', credentials),
|
||||||
|
getIPConfig: () => getIPConfig(),
|
||||||
|
updateIPConfig: (credentials) => ipcRenderer.invoke('updateIPConfig', credentials)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextbridge for status
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('statuss', {
|
||||||
|
getStatus: () => getStatus()
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextbridge for annee scolaire
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('anneescolaire', {
|
||||||
|
getAnneeScolaire: () => getAnneeScolaire(),
|
||||||
|
getInterval: () => getInterval(),
|
||||||
|
createAnneeScolaire: (credentials) => ipcRenderer.invoke('createAnneeScolaire', credentials),
|
||||||
|
deleteAnneeScolaire: (credentials) => ipcRenderer.invoke('deleteAnneeScolaire', credentials),
|
||||||
|
getSingleAnneeScolaire: (credentials) =>
|
||||||
|
ipcRenderer.invoke('getSingleAnneeScolaire', credentials),
|
||||||
|
updateAnneeScolaire: (credentials) => ipcRenderer.invoke('updateAnneeScolaire', credentials),
|
||||||
|
setCurrent: (credentials) => ipcRenderer.invoke('setCurrent', credentials)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextbridge for mention
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('mention', {
|
||||||
|
createMention: (credentials) => ipcRenderer.invoke('createMention', credentials),
|
||||||
|
getMention: () => getMentions(),
|
||||||
|
getSingleMention: (credentials) => ipcRenderer.invoke('getSingleMention', credentials),
|
||||||
|
updateMention: (credentials) => ipcRenderer.invoke('updateMention', credentials),
|
||||||
|
deleteMention: (credentials) => ipcRenderer.invoke('deleteMention', credentials)
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
window.electron = electronAPI
|
||||||
|
window.api = api
|
||||||
|
}
|
||||||
208
src/preload/index.js
Normal file
208
src/preload/index.js
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
import { contextBridge, ipcRenderer } from 'electron'
|
||||||
|
import { electronAPI } from '@electron-toolkit/preload'
|
||||||
|
const { getNessesarytable } = require('../../database/function/System')
|
||||||
|
const { getAllUsers } = require('../../database/Models/Users')
|
||||||
|
const { getAllEtudiants, getDataToDashboard } = require('../../database/Models/Etudiants')
|
||||||
|
const { verifyEtudiantIfHeHasNotes, blockShowMoyene } = require('../../database/Models/Notes')
|
||||||
|
const { getMatiere, getSemestre, getEnseignants } = require('../../database/Models/Matieres')
|
||||||
|
const { getSysteme } = require('../../database/Models/NoteSysrem')
|
||||||
|
const { getStatus } = require('../../database/Models/Status')
|
||||||
|
const { getAnneeScolaire, getInterval } = require('../../database/Models/AnneeScolaire')
|
||||||
|
const { getMentions } = require('../../database/Models/Mentions')
|
||||||
|
const { getAll } = require('../../database/api/Get')
|
||||||
|
const { getParcours } = require('../../database/Models/Parcours')
|
||||||
|
const { getNiveau } = require('../../database/Models/Niveau')
|
||||||
|
const { getIPConfig } = require('../../database/Models/IpConfig')
|
||||||
|
|
||||||
|
// Custom APIs for renderer
|
||||||
|
const api = {}
|
||||||
|
|
||||||
|
// Use `contextBridge` APIs to expose Electron APIs to
|
||||||
|
// renderer only if context isolation is enabled, otherwise
|
||||||
|
// just add to the DOM global.
|
||||||
|
if (process.contextIsolated) {
|
||||||
|
try {
|
||||||
|
contextBridge.exposeInMainWorld('electron', electronAPI)
|
||||||
|
contextBridge.exposeInMainWorld('api', api)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextBridge for Tray
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('Tray', {
|
||||||
|
onNavigate: (callback) => {
|
||||||
|
ipcRenderer.on('navigateToRoute', (event, route) => {
|
||||||
|
callback(route) // Pass the route to the renderer callback
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextBridge for users
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('allUser', {
|
||||||
|
users: () => getAllUsers(),
|
||||||
|
login: (credentials) => ipcRenderer.invoke('login', credentials),
|
||||||
|
insertUsers: (credentials) => ipcRenderer.invoke('insertUser', credentials),
|
||||||
|
forgotPassword: (credentials) => ipcRenderer.invoke('forgotPassword', credentials),
|
||||||
|
quit: () => ipcRenderer.invoke('quit'),
|
||||||
|
minimize: () => ipcRenderer.invoke('minimize'),
|
||||||
|
updateUsers: (credentials) => ipcRenderer.invoke('updateUsers', credentials)
|
||||||
|
})
|
||||||
|
|
||||||
|
contextBridge.exposeInMainWorld('syncro', {
|
||||||
|
getall: () => getAll()
|
||||||
|
})
|
||||||
|
|
||||||
|
// syncronisation des donner
|
||||||
|
window.addEventListener('online', async () => {
|
||||||
|
if (navigator.onLine) {
|
||||||
|
// synchronizeData()
|
||||||
|
// synchronizeDataEtudiants()
|
||||||
|
// synchronizeDataNotes()
|
||||||
|
await getAll()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// send data
|
||||||
|
getAll()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextBridge for etudiants
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('etudiants', {
|
||||||
|
insertEtudiant: (credentials) => ipcRenderer.invoke('insertEtudiant', credentials),
|
||||||
|
getEtudiants: () => getAllEtudiants(),
|
||||||
|
FilterDataByNiveau: (credential) => ipcRenderer.invoke('getByNiveau', credential),
|
||||||
|
getSingle: (credential) => ipcRenderer.invoke('single', credential),
|
||||||
|
updateEtudiants: (credentials) => ipcRenderer.invoke('updateETudiants', credentials),
|
||||||
|
getDataToDashboards: () => getDataToDashboard(),
|
||||||
|
updateEtudiantsPDP: (credentials) => ipcRenderer.invoke('updateETudiantsPDP', credentials),
|
||||||
|
importExcel: (credentials) => ipcRenderer.invoke('importexcel', credentials),
|
||||||
|
changeParcours: (credentials) => ipcRenderer.invoke('changeParcours', credentials),
|
||||||
|
createTranche: (credentials) => ipcRenderer.invoke('createTranche', credentials),
|
||||||
|
getTranche: (credentials) => ipcRenderer.invoke('getTranche', credentials),
|
||||||
|
updateTranche: (credentials) => ipcRenderer.invoke('updateTranche', credentials),
|
||||||
|
deleteTranche: (credentials) => ipcRenderer.invoke('deleteTranche', credentials),
|
||||||
|
getSingleTranche: (credentials) => ipcRenderer.invoke('getSingleTranche', credentials)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cobtextBridge for niveaus
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('niveaus', {
|
||||||
|
getNiveau: () => getNiveau(),
|
||||||
|
getSingleNiveau: (credential) => ipcRenderer.invoke('singleNiveau', credential),
|
||||||
|
insertNiveau: (credentials) => ipcRenderer.invoke('insertNiveau', credentials),
|
||||||
|
updateSingleNiveau: (credentials) => ipcRenderer.invoke('updateSingleNiveau', credentials),
|
||||||
|
importNiveau: (credentials) => ipcRenderer.invoke('importNiveau', credentials),
|
||||||
|
deleteNiveaus: (credentials) => ipcRenderer.invoke('deleteNiveaus', credentials)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextBridge for notes
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('notes', {
|
||||||
|
getNotes: (credentials) => ipcRenderer.invoke('getSingleNote', credentials),
|
||||||
|
insertNote: (credentials) => ipcRenderer.invoke('insertNote', credentials),
|
||||||
|
updateNote: (credentials) => ipcRenderer.invoke('updatetNote', credentials),
|
||||||
|
getMoyenne: (credentials) => ipcRenderer.invoke('getMoyene', credentials),
|
||||||
|
noteMatiere: (credentials) => ipcRenderer.invoke('noteMatiere', credentials),
|
||||||
|
noteRelerer: (credentials) => ipcRenderer.invoke('noteRelerer', credentials),
|
||||||
|
getMoyenneVerify: () => verifyEtudiantIfHeHasNotes(),
|
||||||
|
getblockNote: () => blockShowMoyene()
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextbridge for note repechage
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('noteRepech', {
|
||||||
|
getNotesRepech: (credentials) => ipcRenderer.invoke('getNotesRepech', credentials),
|
||||||
|
updateNoteRepech: (credentials) => ipcRenderer.invoke('updatetNoteRepech', credentials),
|
||||||
|
getMoyenneRepech: (credentials) => ipcRenderer.invoke('getMoyenneRepech', credentials)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextBridge for matieres
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('matieres', {
|
||||||
|
getMatiere: () => getMatiere(),
|
||||||
|
createMatiere: (credentials) => ipcRenderer.invoke('createMatiere', credentials),
|
||||||
|
getMatiereByID: (credentials) => ipcRenderer.invoke('getMatiereByID', credentials),
|
||||||
|
updateMatiere: (credentials) => ipcRenderer.invoke('updateMatiere', credentials),
|
||||||
|
updateMatiereNiveau: (credentials) => ipcRenderer.invoke('updateMatiereNiveau', credentials),
|
||||||
|
importExcel: (credentials) => ipcRenderer.invoke('importExcelMatiere', credentials),
|
||||||
|
displayMatiereFromForm: (credentials) =>
|
||||||
|
ipcRenderer.invoke('displayMatiereFromForm', credentials),
|
||||||
|
deleteMatiere: (id) => ipcRenderer.invoke('deleteMatiere', id),
|
||||||
|
deleteEtudiant: (id) => ipcRenderer.invoke('deleteEtudiant', id),
|
||||||
|
asign: (credentials) => ipcRenderer.invoke('asign', credentials),
|
||||||
|
getAsign: (credentials) => ipcRenderer.invoke('getAsign', credentials),
|
||||||
|
asignSemestre: (credentials) => ipcRenderer.invoke('asignSemestre', credentials),
|
||||||
|
getSemestreMatiere: (credentials) => ipcRenderer.invoke('getSemestreMatiere', credentials),
|
||||||
|
getSemestre: () => getSemestre(),
|
||||||
|
getNessesary: () => getNessesarytable(),
|
||||||
|
getENseignant: () => getEnseignants(),
|
||||||
|
insertUpdateMentionSemestre: (credentials) =>
|
||||||
|
ipcRenderer.invoke('insertUpdateMentionSemestre', credentials),
|
||||||
|
updateNessesary: (credentials) => ipcRenderer.invoke('updateNessesary', credentials),
|
||||||
|
insertProf: (credentials) => ipcRenderer.invoke('insertProf', credentials),
|
||||||
|
getSingleProf: (credentials) => ipcRenderer.invoke('getSingleProf', credentials),
|
||||||
|
updateProf: (credentials) => ipcRenderer.invoke('updateProf', credentials)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextBridge for note systeme
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('notesysteme', {
|
||||||
|
getSyteme: () => getSysteme(),
|
||||||
|
updateNoteSysteme: (credentials) => ipcRenderer.invoke('updateNoteSysteme', credentials),
|
||||||
|
insertParcours: (credentials) => ipcRenderer.invoke('insertParcours', credentials),
|
||||||
|
getSingleParcours: (credentials) => ipcRenderer.invoke('getSingleParcours', credentials),
|
||||||
|
deleteParcours: (credentials) => ipcRenderer.invoke('deleteParcours', credentials),
|
||||||
|
updateParcours: (credentials) => ipcRenderer.invoke('updateParcours', credentials),
|
||||||
|
parcourMatiere: (credentials) => ipcRenderer.invoke('parcourMatiere', credentials),
|
||||||
|
getParcours: () => getParcours(),
|
||||||
|
extractFiches: (credentials) => ipcRenderer.invoke('extractFiches', credentials),
|
||||||
|
getParcourMatiere: (credentials) => ipcRenderer.invoke('getParcourMatiere', credentials),
|
||||||
|
createIPConfig: (credentials) => ipcRenderer.invoke('createIPConfig', credentials),
|
||||||
|
getIPConfig: () => getIPConfig(),
|
||||||
|
updateIPConfig: (credentials) => ipcRenderer.invoke('updateIPConfig', credentials)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextbridge for status
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('statuss', {
|
||||||
|
getStatus: () => getStatus()
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextbridge for annee scolaire
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('anneescolaire', {
|
||||||
|
getAnneeScolaire: () => getAnneeScolaire(),
|
||||||
|
getInterval: () => getInterval(),
|
||||||
|
createAnneeScolaire: (credentials) => ipcRenderer.invoke('createAnneeScolaire', credentials),
|
||||||
|
deleteAnneeScolaire: (credentials) => ipcRenderer.invoke('deleteAnneeScolaire', credentials),
|
||||||
|
getSingleAnneeScolaire: (credentials) =>
|
||||||
|
ipcRenderer.invoke('getSingleAnneeScolaire', credentials),
|
||||||
|
updateAnneeScolaire: (credentials) => ipcRenderer.invoke('updateAnneeScolaire', credentials),
|
||||||
|
setCurrent: (credentials) => ipcRenderer.invoke('setCurrent', credentials)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* contextbridge for mention
|
||||||
|
*/
|
||||||
|
contextBridge.exposeInMainWorld('mention', {
|
||||||
|
createMention: (credentials) => ipcRenderer.invoke('createMention', credentials),
|
||||||
|
getMention: () => getMentions(),
|
||||||
|
getSingleMention: (credentials) => ipcRenderer.invoke('getSingleMention', credentials),
|
||||||
|
updateMention: (credentials) => ipcRenderer.invoke('updateMention', credentials),
|
||||||
|
deleteMention: (credentials) => ipcRenderer.invoke('deleteMention', credentials)
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
window.electron = electronAPI
|
||||||
|
window.api = api
|
||||||
|
}
|
||||||
17
src/renderer/src/assets/AllStyleComponents.module.css
Normal file
17
src/renderer/src/assets/AllStyleComponents.module.css
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
.h1style {
|
||||||
|
/* text-transform: uppercase; */
|
||||||
|
font-weight: 900;
|
||||||
|
/* 6636af4a 6636af ffae01 */
|
||||||
|
border-left: 10px solid #ffff;
|
||||||
|
padding-left: 10px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
background: linear-gradient(to right, #ffaf01b4, transparent);
|
||||||
|
color: white;
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 45px;
|
||||||
|
font-size: 25px;
|
||||||
|
}
|
||||||
|
.mainHome {
|
||||||
|
padding: 1% 0 0 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
283
src/renderer/src/components/AddAnneeScolaire.jsx
Normal file
283
src/renderer/src/components/AddAnneeScolaire.jsx
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
import React, { useRef, useState } from 'react'
|
||||||
|
import classe from '../assets/AllStyleComponents.module.css'
|
||||||
|
import classeHome from '../assets/Home.module.css'
|
||||||
|
import Paper from '@mui/material/Paper'
|
||||||
|
import { Link, useNavigate } from 'react-router-dom'
|
||||||
|
import { IoMdReturnRight } from 'react-icons/io'
|
||||||
|
import { Modal, Box, Typography, Button, InputAdornment, TextField, Grid } from '@mui/material'
|
||||||
|
import { FaCalendarAlt, FaCalendarPlus } from 'react-icons/fa'
|
||||||
|
import validationAnneeScolaire from './validation/ValidationAddAnneeScolaire'
|
||||||
|
import svgError from '../assets/error.svg'
|
||||||
|
import svgSuccess from '../assets/success.svg'
|
||||||
|
|
||||||
|
const AddAnneeScolaire = () => {
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
code: '',
|
||||||
|
debut: '',
|
||||||
|
fin: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const debutRef = useRef()
|
||||||
|
const codeRef = useRef()
|
||||||
|
const finRef = useRef()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function to set the data in state
|
||||||
|
* @param {*} e
|
||||||
|
*/
|
||||||
|
const handleInputChange = (e) => {
|
||||||
|
const { name, value } = e.target
|
||||||
|
setFormData((prevData) => ({
|
||||||
|
...prevData,
|
||||||
|
[name]: value
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
const formSubmit = async (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
let isValid = validationAnneeScolaire(codeRef.current, debutRef.current, finRef.current)
|
||||||
|
|
||||||
|
if (isValid) {
|
||||||
|
let response = await window.anneescolaire.createAnneeScolaire(formData)
|
||||||
|
console.log(response)
|
||||||
|
if (response.success) {
|
||||||
|
setStatus(200)
|
||||||
|
setOpen(true)
|
||||||
|
} else {
|
||||||
|
setStatus(400)
|
||||||
|
setOpen(true)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setStatus(400)
|
||||||
|
setOpen(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const [status, setStatus] = useState(200)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hook to open modal
|
||||||
|
*/
|
||||||
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function to close modal
|
||||||
|
*/
|
||||||
|
const handleClose = () => {
|
||||||
|
setOpen(false)
|
||||||
|
window.history.back()
|
||||||
|
}
|
||||||
|
const handleClose2 = () => {
|
||||||
|
setOpen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function to return the view Modal
|
||||||
|
*
|
||||||
|
* @returns {JSX}
|
||||||
|
*/
|
||||||
|
const modals = () => (
|
||||||
|
<Modal
|
||||||
|
open={open}
|
||||||
|
onClose={status === 200 ? handleClose : handleClose}
|
||||||
|
aria-labelledby="modal-title"
|
||||||
|
aria-describedby="modal-description"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
width: 450,
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
boxShadow: 24,
|
||||||
|
p: 4
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{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>
|
||||||
|
</Typography>
|
||||||
|
) : (
|
||||||
|
<Typography style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
||||||
|
<img src={svgError} alt="" width={50} height={50} />{' '}
|
||||||
|
<span>Erreur, veuillez réessayer</span>
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginTop: '2%',
|
||||||
|
display: 'flex',
|
||||||
|
gap: '20px',
|
||||||
|
alignItems: 'end',
|
||||||
|
justifyContent: 'flex-end'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{status === 200 ? (
|
||||||
|
<Button onClick={handleClose} color="warning" variant="contained">
|
||||||
|
OK
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button onClick={handleClose2} color="warning" variant="contained">
|
||||||
|
OK
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classe.mainHome}>
|
||||||
|
{modals()}
|
||||||
|
<div className={classeHome.header}>
|
||||||
|
<div className={classe.h1style}>
|
||||||
|
<div className={classeHome.blockTitle}>
|
||||||
|
<h1 style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
|
||||||
|
<FaCalendarPlus /> Ajout Année Scolaire
|
||||||
|
</h1>
|
||||||
|
<Link to={'#'} onClick={() => window.history.back()}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<IoMdReturnRight style={{ fontSize: '20px' }} />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={classeHome.boxEtudiantsCard}>
|
||||||
|
<Paper
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%', // Auto height to make the grid responsive
|
||||||
|
minHeight: 500, // Ensures a minimum height
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<form
|
||||||
|
onSubmit={formSubmit}
|
||||||
|
style={{
|
||||||
|
width: '50%',
|
||||||
|
padding: '1%',
|
||||||
|
height: '20%',
|
||||||
|
border: 'solid 2px orange',
|
||||||
|
borderRadius: '10px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<h4 style={{ textAlign: 'center', padding: '0 0 3% 0' }}>
|
||||||
|
Creation de nouvelle Année Scolaire
|
||||||
|
</h4>
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid item xs={12} sm={6}>
|
||||||
|
<TextField
|
||||||
|
label={'Année Scolaire'}
|
||||||
|
name={'code'}
|
||||||
|
placeholder="2024-2025"
|
||||||
|
color="warning"
|
||||||
|
fullWidth
|
||||||
|
value={formData.code}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<FaCalendarAlt />
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
inputRef={codeRef}
|
||||||
|
className="inputAddNote"
|
||||||
|
sx={{
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
'&:hover fieldset': {
|
||||||
|
borderColor: '#ff9800' // Set the border color on hover
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'& .MuiInputBase-input::placeholder': {
|
||||||
|
fontSize: '14px' // Set the placeholder font size
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6}>
|
||||||
|
<TextField
|
||||||
|
label={'Date de début'}
|
||||||
|
name={'debut'}
|
||||||
|
color="warning"
|
||||||
|
onChange={handleInputChange}
|
||||||
|
inputRef={debutRef}
|
||||||
|
value={formData.debut}
|
||||||
|
fullWidth
|
||||||
|
type="date"
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<FaCalendarAlt />
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
className="inputAddNote"
|
||||||
|
sx={{
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
'&:hover fieldset': {
|
||||||
|
borderColor: '#ff9800' // Set the border color on hover
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'& .MuiInputBase-input::placeholder': {
|
||||||
|
fontSize: '11px' // Set the placeholder font size
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6}>
|
||||||
|
<TextField
|
||||||
|
label={'Date de fin'}
|
||||||
|
name={'fin'}
|
||||||
|
color="warning"
|
||||||
|
fullWidth
|
||||||
|
type="date"
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<FaCalendarAlt />
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
inputRef={finRef}
|
||||||
|
value={formData.fin}
|
||||||
|
className="inputAddNote"
|
||||||
|
sx={{
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
'&:hover fieldset': {
|
||||||
|
borderColor: '#ff9800' // Set the border color on hover
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'& .MuiInputBase-input::placeholder': {
|
||||||
|
fontSize: '11px' // Set the placeholder font size
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid
|
||||||
|
item
|
||||||
|
xs={12}
|
||||||
|
style={{ display: 'flex', gap: '30px', justifyContent: 'flex-end' }}
|
||||||
|
>
|
||||||
|
<Button type="submit" color="warning" variant="contained">
|
||||||
|
Enregister
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</form>
|
||||||
|
</Paper>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AddAnneeScolaire
|
||||||
317
src/renderer/src/components/AddNotes.jsx
Normal file
317
src/renderer/src/components/AddNotes.jsx
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
|
import classe from '../assets/AllStyleComponents.module.css'
|
||||||
|
import classeAdd from '../assets/AddNotes.module.css'
|
||||||
|
import classeHome from '../assets/Home.module.css'
|
||||||
|
import { Modal, Box, Typography, Button, InputAdornment, TextField, Grid } from '@mui/material'
|
||||||
|
import { CgNotes } from 'react-icons/cg'
|
||||||
|
import { IoMdReturnRight } from 'react-icons/io'
|
||||||
|
import { Link, useParams, useNavigate } from 'react-router-dom'
|
||||||
|
import svgSuccess from '../assets/success.svg'
|
||||||
|
import svgError from '../assets/error.svg'
|
||||||
|
import validateAddNote from './validation/AddNote'
|
||||||
|
import ModalUpdateParcoursEtudiant from './ModalUpdateParcoursEtudiant'
|
||||||
|
|
||||||
|
const AddNotes = () => {
|
||||||
|
const { id, niveau, mention_id, parcours } = useParams()
|
||||||
|
const [matieres, setMatieres] = useState([])
|
||||||
|
const [formData, setFormData] = useState({}) // Initialize with an empty object
|
||||||
|
const [etudiants, setEtudiants] = useState([])
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const [openModal1, setOpenModal1] = useState(false)
|
||||||
|
const oncloseModal1 = () => {
|
||||||
|
setOpenModal1(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetching the matieres
|
||||||
|
*/
|
||||||
|
useEffect(() => {
|
||||||
|
window.matieres.displayMatiereFromForm({ niveau, mention_id, parcours }).then((response) => {
|
||||||
|
setMatieres(response)
|
||||||
|
})
|
||||||
|
|
||||||
|
window.etudiants.getSingle({ id }).then((response) => {
|
||||||
|
setEtudiants(response)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (parcours == 'Pas de parcours' && niveau != 'L1') {
|
||||||
|
setOpenModal1(true)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const [isSubmitted, setIsSubmitted] = useState(false)
|
||||||
|
const [parcoursChange, setParcourChanges] = useState('')
|
||||||
|
const handleFormSubmit = (status, parcours) => {
|
||||||
|
setIsSubmitted(status)
|
||||||
|
setParcourChanges(parcours)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isSubmitted) {
|
||||||
|
let parcours = parcoursChange
|
||||||
|
|
||||||
|
window.matieres.displayMatiereFromForm({ niveau, mention_id, parcours }).then((response) => {
|
||||||
|
setMatieres(response)
|
||||||
|
console.log("resulat teste:1", response);
|
||||||
|
console.log("resulat teste:2", mention_id);
|
||||||
|
console.log("resulat teste:3", parcours);
|
||||||
|
})
|
||||||
|
setIsSubmitted(false)
|
||||||
|
}
|
||||||
|
}, [isSubmitted])
|
||||||
|
|
||||||
|
let niveauEtudiant = etudiants.niveau
|
||||||
|
let AnneeScolaireEtudiant = etudiants.annee_scolaire
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update formData whenever matieres change
|
||||||
|
*/
|
||||||
|
useEffect(() => {
|
||||||
|
const initialFormData = matieres.reduce((acc, mat) => {
|
||||||
|
acc[mat.id] = '' // Initialize each key with an empty string
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
setFormData(initialFormData)
|
||||||
|
}, [matieres]) // Dependency array ensures this runs whenever `matieres` is updated
|
||||||
|
|
||||||
|
const [disabled, setDisabled] = useState(false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle form submission
|
||||||
|
*/
|
||||||
|
const handleSubmit = async (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
const etudiant_id = id
|
||||||
|
const etudiant_niveau = niveauEtudiant
|
||||||
|
let valid = validateAddNote()
|
||||||
|
let annee_scolaire = AnneeScolaireEtudiant
|
||||||
|
let mention_id = etudiants.mention_id
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
let response = await window.notes.insertNote({
|
||||||
|
etudiant_id,
|
||||||
|
etudiant_niveau,
|
||||||
|
mention_id,
|
||||||
|
formData,
|
||||||
|
annee_scolaire
|
||||||
|
})
|
||||||
|
console.log(response)
|
||||||
|
if (response.success) {
|
||||||
|
setOpen(true)
|
||||||
|
setStatut(200)
|
||||||
|
setDisabled(true)
|
||||||
|
const resetFormData = matieres.reduce((acc, mat) => {
|
||||||
|
acc[mat.id] = '' // Reset each field to an empty string
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
setFormData(resetFormData)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setOpen(true)
|
||||||
|
setStatut(400)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('matiere: ',matieres);
|
||||||
|
|
||||||
|
const [statut, setStatut] = useState(200)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hook to open modal
|
||||||
|
*/
|
||||||
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function to close modal
|
||||||
|
*/
|
||||||
|
const handleClose = () => {
|
||||||
|
setOpen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClose2 = () => {
|
||||||
|
navigate('/notes')
|
||||||
|
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"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
width: 450,
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
boxShadow: 24,
|
||||||
|
p: 4
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{statut === 200 ? (
|
||||||
|
<Typography
|
||||||
|
style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '10px' }}
|
||||||
|
>
|
||||||
|
<img src={svgSuccess} alt="" width={70} height={70} />{' '}
|
||||||
|
<span>
|
||||||
|
Note de {etudiants.nom} {etudiants.prenom} en {etudiants.niveau} a été inserer avec
|
||||||
|
succès
|
||||||
|
</span>
|
||||||
|
</Typography>
|
||||||
|
) : (
|
||||||
|
<Typography
|
||||||
|
style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '10px' }}
|
||||||
|
>
|
||||||
|
<img src={svgError} alt="" width={70} height={70} />{' '}
|
||||||
|
<span>Inserer au moin un champ</span>
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginTop: '2%',
|
||||||
|
display: 'flex',
|
||||||
|
gap: '20px',
|
||||||
|
alignItems: 'end',
|
||||||
|
justifyContent: 'flex-end'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{statut == 200 ? (
|
||||||
|
<Button onClick={handleClose2} color="warning" variant="contained">
|
||||||
|
OK
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button onClick={handleClose} color="warning" variant="contained">
|
||||||
|
OK
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classe.mainHome}>
|
||||||
|
{modals()}
|
||||||
|
<ModalUpdateParcoursEtudiant
|
||||||
|
onClose={oncloseModal1}
|
||||||
|
open={openModal1}
|
||||||
|
user_id={etudiants.id}
|
||||||
|
onSubmit={handleFormSubmit}
|
||||||
|
/>
|
||||||
|
<div className={classeAdd.header}>
|
||||||
|
<div className={classe.h1style}>
|
||||||
|
<div className={classeHome.blockTitle}>
|
||||||
|
<h1 style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
|
||||||
|
<CgNotes />
|
||||||
|
Ajout note
|
||||||
|
</h1>
|
||||||
|
<Link to={'/student'}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<IoMdReturnRight style={{ fontSize: '20px' }} />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* displaying */}
|
||||||
|
<div className={classeHome.boxEtudiantsCard}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '55%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
width: 700,
|
||||||
|
borderRadius: '2%',
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
boxShadow: 24,
|
||||||
|
p: 4
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginTop: '2%',
|
||||||
|
display: 'flex',
|
||||||
|
width: '100%',
|
||||||
|
gap: '20px',
|
||||||
|
alignItems: 'start',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<form onSubmit={handleSubmit} style={{ width: '100%' }}>
|
||||||
|
<h4 style={{ textAlign: 'center', marginBottom: '3%' }}>
|
||||||
|
Ajout des notes :{' '}
|
||||||
|
<span style={{ color: '#ff9800' }}>
|
||||||
|
{etudiants.nom} {etudiants.prenom} en {etudiants.niveau}
|
||||||
|
</span>
|
||||||
|
</h4>
|
||||||
|
|
||||||
|
{/* map the all matiere to the form */}
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
{matieres.map((mat) => (
|
||||||
|
<Grid item xs={12} sm={3} key={mat.nom}>
|
||||||
|
<TextField
|
||||||
|
label={mat.nom}
|
||||||
|
name={mat.id}
|
||||||
|
placeholder="point séparateur"
|
||||||
|
color="warning"
|
||||||
|
fullWidth
|
||||||
|
value={formData[mat.id] || ''} // Access the correct value from formData
|
||||||
|
onChange={
|
||||||
|
(e) => setFormData({ ...formData, [mat.id]: e.target.value }) // Update the specific key
|
||||||
|
}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<CgNotes />
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
className="inputAddNote"
|
||||||
|
sx={{
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
'&:hover fieldset': {
|
||||||
|
borderColor: '#ff9800' // Set the border color on hover
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'& .MuiInputBase-input::placeholder': {
|
||||||
|
fontSize: '11px' // Set the placeholder font size
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
<Grid
|
||||||
|
item
|
||||||
|
xs={12}
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
gap: '30px',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
marginTop: '1%'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button type="submit" color="warning" variant="contained" disabled={disabled}>
|
||||||
|
Enregister
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</form>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AddNotes
|
||||||
1070
src/renderer/src/components/AddStudent.jsx
Normal file
1070
src/renderer/src/components/AddStudent.jsx
Normal file
File diff suppressed because it is too large
Load Diff
319
src/renderer/src/components/AnneeScolaire.jsx
Normal file
319
src/renderer/src/components/AnneeScolaire.jsx
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import classe from '../assets/AllStyleComponents.module.css'
|
||||||
|
import classeHome from '../assets/Home.module.css'
|
||||||
|
import Paper from '@mui/material/Paper'
|
||||||
|
import { Modal, Box, Typography, Button, InputAdornment, TextField, Grid } from '@mui/material'
|
||||||
|
import { FaCalendarAlt, FaCheck, FaCheckCircle, FaSquare } from 'react-icons/fa'
|
||||||
|
import { DataGrid, GridToolbar, GridToolbarFilterButton } from '@mui/x-data-grid'
|
||||||
|
import { createTheme, ThemeProvider } from '@mui/material/styles'
|
||||||
|
import { frFR } from '@mui/x-data-grid/locales'
|
||||||
|
import { FaCalendarPlus } from 'react-icons/fa'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
import { FaPenToSquare, FaTrash } from 'react-icons/fa6'
|
||||||
|
import { Tooltip } from 'react-tooltip'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import warning from '../assets/warning.svg'
|
||||||
|
import success from '../assets/success.svg'
|
||||||
|
import { BsCalendar2Date } from 'react-icons/bs'
|
||||||
|
|
||||||
|
const AnneeScolaire = () => {
|
||||||
|
const theme = createTheme({
|
||||||
|
components: {
|
||||||
|
MuiIconButton: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: 'gray' // Change the color of toolbar icons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MuiButton: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: '#121212' // Change the color of toolbar icons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const [anneeScolaire, setAnneeScolaire] = useState([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.anneescolaire.getAnneeScolaire().then((response) => {
|
||||||
|
setAnneeScolaire(response)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const [isDeleted, setIsDeleted] = useState(false)
|
||||||
|
const [ids, setIds] = useState(0)
|
||||||
|
|
||||||
|
const column = [
|
||||||
|
{ field: 'code', headerName: 'Année Scolaire', width: 130 },
|
||||||
|
{ field: 'debut', headerName: 'Date de début', width: 130 },
|
||||||
|
{ field: 'fin', headerName: 'Date de fin', width: 130 },
|
||||||
|
{
|
||||||
|
field: 'action',
|
||||||
|
headerName: 'Action',
|
||||||
|
flex: 1,
|
||||||
|
renderCell: (params) => (
|
||||||
|
<div style={{ display: 'flex', gap: '10px' }}>
|
||||||
|
<Link to={`/anneescolaire/${params.value}`}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<FaPenToSquare
|
||||||
|
style={{ fontSize: '20px', color: 'white' }}
|
||||||
|
className={`update${params.value}`}
|
||||||
|
/>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.update${params.value}`}
|
||||||
|
style={{ fontSize: '15px', zIndex: 22 }}
|
||||||
|
place="top"
|
||||||
|
>
|
||||||
|
Modifier
|
||||||
|
</Tooltip>
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
to={`#`}
|
||||||
|
onClick={() => {
|
||||||
|
setIds(params.row.id)
|
||||||
|
setOpen(true)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button color="error" variant="contained">
|
||||||
|
<FaTrash
|
||||||
|
style={{ fontSize: '20px', color: 'white' }}
|
||||||
|
className={`delete${params.value}`}
|
||||||
|
/>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.delete${params.value}`}
|
||||||
|
style={{ fontSize: '15px', zIndex: 22 }}
|
||||||
|
place="top"
|
||||||
|
>
|
||||||
|
Supprimer
|
||||||
|
</Tooltip>
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'current',
|
||||||
|
headerName: 'Année en cours',
|
||||||
|
flex: 1,
|
||||||
|
renderCell: (params) => (
|
||||||
|
<div style={{ display: 'flex', gap: '10px' }}>
|
||||||
|
<Link to={`#`}>
|
||||||
|
<Button color="success" variant="contained">
|
||||||
|
{params.value.current == 1 ? (
|
||||||
|
<FaCheck
|
||||||
|
style={{ fontSize: '20px', color: 'white' }}
|
||||||
|
className={`courrants${params.value.id}`}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<FaSquare
|
||||||
|
style={{ fontSize: '20px', color: 'white' }}
|
||||||
|
className={`courrant${params.value.id}`}
|
||||||
|
onClick={() => setCurrent(params.value.id)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.courrants${params.value.id}`}
|
||||||
|
style={{ fontSize: '15px', zIndex: 22 }}
|
||||||
|
place="top"
|
||||||
|
>
|
||||||
|
Année en cours
|
||||||
|
</Tooltip>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const paginationModel = { page: 0, pageSize: 5 }
|
||||||
|
|
||||||
|
let data = anneeScolaire.map((annee) => ({
|
||||||
|
id: annee.id,
|
||||||
|
code: annee.code,
|
||||||
|
debut: dayjs(annee.debut).format('DD-MM-YYYY'),
|
||||||
|
fin: dayjs(annee.fin).format('DD-MM-YYYY'),
|
||||||
|
action: annee.id,
|
||||||
|
current: { current: annee.is_current, id: annee.id }
|
||||||
|
}))
|
||||||
|
|
||||||
|
const setCurrent = async (id) => {
|
||||||
|
// let response = await window.anneescolaire.setCurrent({id});
|
||||||
|
// console.log(response);
|
||||||
|
// if (response.changes) {
|
||||||
|
// window.anneescolaire.getAnneeScolaire().then((response) => {
|
||||||
|
// setAnneeScolaire(response);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteButton = async (id) => {
|
||||||
|
let response = await window.anneescolaire.deleteAnneeScolaire({ id })
|
||||||
|
if (response.success) {
|
||||||
|
const updatedAnneeScolaire = anneeScolaire.filter((anneeScolaire) => anneeScolaire.id !== id)
|
||||||
|
setAnneeScolaire(updatedAnneeScolaire)
|
||||||
|
setIsDeleted(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const CustomToolbar = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<GridToolbarFilterButton />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hook to open modal
|
||||||
|
*/
|
||||||
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function to close modal
|
||||||
|
*/
|
||||||
|
const handleClose = () => {
|
||||||
|
setOpen(false)
|
||||||
|
setIsDeleted(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function to return the view Modal
|
||||||
|
*
|
||||||
|
* @returns {JSX}
|
||||||
|
*/
|
||||||
|
const modals = () => (
|
||||||
|
<Modal
|
||||||
|
open={open}
|
||||||
|
onClose={handleClose}
|
||||||
|
aria-labelledby="modal-title"
|
||||||
|
aria-describedby="modal-description"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
width: 450,
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
boxShadow: 24,
|
||||||
|
p: 4
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isDeleted ? (
|
||||||
|
<Typography
|
||||||
|
style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '10px' }}
|
||||||
|
>
|
||||||
|
<img src={success} alt="" width={50} height={50} /> <span>Suprimer avec succèss</span>
|
||||||
|
</Typography>
|
||||||
|
) : (
|
||||||
|
<Typography
|
||||||
|
style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '10px' }}
|
||||||
|
>
|
||||||
|
<img src={warning} alt="" width={50} height={50} />{' '}
|
||||||
|
<span>Voulez vous supprimer cette année ?</span>
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginTop: '2%',
|
||||||
|
display: 'flex',
|
||||||
|
gap: '20px',
|
||||||
|
alignItems: 'end',
|
||||||
|
justifyContent: 'flex-end'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isDeleted ? (
|
||||||
|
<Button onClick={handleClose} color="warning" variant="contained">
|
||||||
|
OK
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
onClick={() => deleteButton(ids)}
|
||||||
|
sx={{ mr: 1 }}
|
||||||
|
color="warning"
|
||||||
|
variant="contained"
|
||||||
|
>
|
||||||
|
Oui
|
||||||
|
</Button>
|
||||||
|
<Button onClick={handleClose} color="warning" variant="contained">
|
||||||
|
Non
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classe.mainHome}>
|
||||||
|
{modals()}
|
||||||
|
<div className={classeHome.header}>
|
||||||
|
<div className={classe.h1style}>
|
||||||
|
<div className={classeHome.blockTitle}>
|
||||||
|
<h1 style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
|
||||||
|
<BsCalendar2Date /> Année Scolaire
|
||||||
|
</h1>
|
||||||
|
<Link to={'/addanneescolaire'}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<FaCalendarPlus style={{ fontSize: '20px' }} /> Ajouter
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={classeHome.boxEtudiantsCard}>
|
||||||
|
<Paper
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%', // Auto height to make the grid responsive
|
||||||
|
minHeight: 500, // Ensures a minimum height
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column', // Stacks content vertically on smaller screens,
|
||||||
|
width: '100%'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DataGrid
|
||||||
|
rows={data}
|
||||||
|
columns={column}
|
||||||
|
initialState={{ pagination: { paginationModel } }}
|
||||||
|
pageSizeOptions={[5, 10]}
|
||||||
|
sx={{
|
||||||
|
border: 0,
|
||||||
|
width: 'auto', // Ensures the DataGrid takes full width
|
||||||
|
height: '50%', // Ensures it grows to fit content
|
||||||
|
minHeight: 400, // Minimum height for the DataGrid
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
'@media (max-width: 600px)': {
|
||||||
|
width: '100%', // 100% width on small screens
|
||||||
|
height: 'auto' // Allow height to grow with content
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
slots={{ toolbar: CustomToolbar }}
|
||||||
|
localeText={frFR.components.MuiDataGrid.defaultProps.localeText}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ThemeProvider>
|
||||||
|
</Paper>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AnneeScolaire
|
||||||
68
src/renderer/src/components/Apropos.jsx
Normal file
68
src/renderer/src/components/Apropos.jsx
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import classe from '../assets/AllStyleComponents.module.css'
|
||||||
|
import classeHome from '../assets/Home.module.css'
|
||||||
|
import logo from '../assets/logo or.png'
|
||||||
|
import { Box } from '@mui/material'
|
||||||
|
import classeAdd from '../assets/AddStudent.module.css'
|
||||||
|
|
||||||
|
const Apropos = () => {
|
||||||
|
return (
|
||||||
|
<div className={classe.mainHome}>
|
||||||
|
<div className={classeHome.header}>
|
||||||
|
<div className={classe.h1style}>
|
||||||
|
<div className={classeHome.blockTitle}>
|
||||||
|
<h1>A propos</h1>
|
||||||
|
|
||||||
|
{/* contenu */}
|
||||||
|
<div className={classeHome.contenaire}>
|
||||||
|
<div className={classeAdd.boxEtudiantsCard}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
width: 700,
|
||||||
|
borderRadius: '3%',
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
boxShadow: 24,
|
||||||
|
p: 4
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginTop: '5%',
|
||||||
|
display: 'flex',
|
||||||
|
gap: '10px',
|
||||||
|
alignItems: 'start',
|
||||||
|
flexDirection: 'column',
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: 'sans-serif',
|
||||||
|
justifyContent: 'flex-end'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span style={{ display: 'flex', marginLeft: '30%' }}>
|
||||||
|
<img src={logo} alt="" height={250} width={250} />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<p style={{ color: 'black' }}>
|
||||||
|
Nom du Logiciel: CUniversity <br />
|
||||||
|
<br /> Description : logiciel de gestion d'espt <br /> <br />
|
||||||
|
Createur: CPAY COMPANY FOR MADAGASCAR <br />
|
||||||
|
<br /> Licence: A vie <br />
|
||||||
|
<br /> Contact: 0348415301
|
||||||
|
<br /> <br />
|
||||||
|
E-mail: director@c4m.mg
|
||||||
|
</p>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Apropos
|
||||||
527
src/renderer/src/components/ExportEtudiants.jsx
Normal file
527
src/renderer/src/components/ExportEtudiants.jsx
Normal file
@ -0,0 +1,527 @@
|
|||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import classe from '../assets/AllStyleComponents.module.css'
|
||||||
|
import classeAdd from '../assets/AddStudent.module.css'
|
||||||
|
import classeHome from '../assets/Home.module.css'
|
||||||
|
import { IoMdReturnRight } from 'react-icons/io'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
import { FaFileExcel, FaCloudUploadAlt, FaCloudDownloadAlt } from 'react-icons/fa'
|
||||||
|
import { Box, Button, Typography, ThemeProvider, Modal } from '@mui/material'
|
||||||
|
import { styled, createTheme } from '@mui/material/styles'
|
||||||
|
import * as XLSX from 'xlsx'
|
||||||
|
import Papa from 'papaparse'
|
||||||
|
import { DataGrid, GridToolbarContainer, GridToolbarColumnsButton } from '@mui/x-data-grid'
|
||||||
|
import { frFR } from '@mui/x-data-grid/locales'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import CustomBar from './CustomBar'
|
||||||
|
import svgSuccess from '../assets/success.svg'
|
||||||
|
import svgError from '../assets/error.svg'
|
||||||
|
import { MenuItem, Select, FormControl, InputLabel } from '@mui/material'
|
||||||
|
|
||||||
|
const ExportEtudiants = () => {
|
||||||
|
const [tableData, setTableData] = useState([])
|
||||||
|
const [error, setError] = useState('')
|
||||||
|
const [isInserted, setIsinserted] = useState(true)
|
||||||
|
const [message, setMessage] = useState('')
|
||||||
|
|
||||||
|
const theme = createTheme({
|
||||||
|
components: {
|
||||||
|
MuiIconButton: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: 'gray' // Toolbar icons color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MuiButton: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: '#121212' // Button text color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const [header, setHeader] = useState([])
|
||||||
|
let field = []
|
||||||
|
const [dynamicColumns, setColumns] = useState([])
|
||||||
|
|
||||||
|
for (let index = 0; index < header.length; index++) {
|
||||||
|
field.push(header[index].toLowerCase().replace(/\s+/g, '_'))
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setColumns(
|
||||||
|
header.map((col, index) => ({
|
||||||
|
field: field[index], // Converts the header text to field names (e.g., "Nom" -> "nom")
|
||||||
|
headerName: col, // Display the header as is
|
||||||
|
width: 150 // Adjust the width as needed
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
}, [header])
|
||||||
|
|
||||||
|
const paginationModel = { page: 0, pageSize: 5 }
|
||||||
|
|
||||||
|
// Assuming `tableData` is an array where each entry corresponds to a student's data
|
||||||
|
const dataRow = tableData.map((etudiant, index) => {
|
||||||
|
// Dynamically create an object with fields from the header and data from `etudiant`
|
||||||
|
let row = { id: index + 1 } // Unique ID for each row
|
||||||
|
|
||||||
|
field.forEach((fieldName, idx) => {
|
||||||
|
if (fieldName === 'date_de_naissance') {
|
||||||
|
row[fieldName] = dayjs(etudiant[idx]).format('DD-MM-YYYY') // Format date
|
||||||
|
} else {
|
||||||
|
row[fieldName] = etudiant[idx] // Assign value to field dynamically
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return row
|
||||||
|
})
|
||||||
|
|
||||||
|
const VisuallyHiddenInput = styled('input')({
|
||||||
|
clip: 'rect(0 0 0 0)',
|
||||||
|
clipPath: 'inset(50%)',
|
||||||
|
height: 1,
|
||||||
|
overflow: 'hidden',
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
width: 1
|
||||||
|
})
|
||||||
|
|
||||||
|
const [files, setFiles] = useState()
|
||||||
|
|
||||||
|
const handleFileChange = (event) => {
|
||||||
|
const file = event.target.files[0]
|
||||||
|
setFiles(event.target.files[0])
|
||||||
|
if (!file) {
|
||||||
|
setError('No file selected')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileExtension = file.name.split('.').pop().toLowerCase()
|
||||||
|
|
||||||
|
if (fileExtension === 'xlsx') {
|
||||||
|
const reader = new FileReader()
|
||||||
|
reader.onload = (e) => {
|
||||||
|
const data = new Uint8Array(e.target.result)
|
||||||
|
const workbook = XLSX.read(data, { type: 'array' })
|
||||||
|
|
||||||
|
// Extract data from all sheets and combine
|
||||||
|
const allData = []
|
||||||
|
workbook.SheetNames.forEach((sheetName) => {
|
||||||
|
const worksheet = workbook.Sheets[sheetName]
|
||||||
|
const rows = XLSX.utils.sheet_to_json(worksheet, { header: 1 })
|
||||||
|
setHeader(rows[0]) // keep the header
|
||||||
|
allData.push(...rows.slice(1)) // Skip header row for each sheet
|
||||||
|
})
|
||||||
|
setTableData(allData)
|
||||||
|
}
|
||||||
|
reader.readAsArrayBuffer(file)
|
||||||
|
} else if (fileExtension === 'csv') {
|
||||||
|
const reader = new FileReader()
|
||||||
|
reader.onload = (e) => {
|
||||||
|
Papa.parse(e.target.result, {
|
||||||
|
complete: (results) => {
|
||||||
|
setHeader(results.data[0]) // keep the header
|
||||||
|
console.log(results.data)
|
||||||
|
setTableData(results.data.slice(1)) // Skip header row
|
||||||
|
},
|
||||||
|
header: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
reader.readAsText(file)
|
||||||
|
} else {
|
||||||
|
setError('Unsupported file format. Please upload .xlsx or .csv file.')
|
||||||
|
setTableData([])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fonction qui envoye dans le back
|
||||||
|
*/
|
||||||
|
const handleImport = async () => {
|
||||||
|
if (!files) {
|
||||||
|
setError("Veuillez choisir un fichier d'abord.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
let response = await window.etudiants.importExcel(files.path)
|
||||||
|
|
||||||
|
console.log(response)
|
||||||
|
|
||||||
|
if (response.message) {
|
||||||
|
setMessage(response.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
setIsinserted(false)
|
||||||
|
setOpen(true)
|
||||||
|
// Ne vide pas tableData, ça permet à l'utilisateur de corriger le fichier
|
||||||
|
} else {
|
||||||
|
setIsinserted(true)
|
||||||
|
setOpen(true)
|
||||||
|
setTableData([]) // vider seulement si insertion réussie
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setMessage('Erreur inattendue lors de l’import')
|
||||||
|
setIsinserted(false)
|
||||||
|
setOpen(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hook to open modal
|
||||||
|
*/
|
||||||
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
width: 450,
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
boxShadow: 24,
|
||||||
|
p: 4
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isInserted ? (
|
||||||
|
<Typography
|
||||||
|
style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '10px' }}
|
||||||
|
>
|
||||||
|
<img src={svgSuccess} alt="" width={50} height={50} />{' '}
|
||||||
|
<span>Importation a été effectuée avec succès</span>
|
||||||
|
</Typography>
|
||||||
|
) : (
|
||||||
|
<Typography
|
||||||
|
style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '10px' }}
|
||||||
|
>
|
||||||
|
<img src={svgError} alt="" width={50} height={50} />{' '}
|
||||||
|
<span>
|
||||||
|
L'importation n'a pas été effectuée
|
||||||
|
<br />
|
||||||
|
{message}
|
||||||
|
</span>
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginTop: '2%',
|
||||||
|
display: 'flex',
|
||||||
|
gap: '20px',
|
||||||
|
alignItems: 'end',
|
||||||
|
justifyContent: 'flex-end'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button onClick={handleClose} color="warning" variant="contained">
|
||||||
|
OK
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
|
||||||
|
const exemplaireFileExcel = [
|
||||||
|
{
|
||||||
|
nom: 'nom2',
|
||||||
|
prenom: 'prenom2',
|
||||||
|
niveau: 'L1',
|
||||||
|
date_naissance: 'jj/mm/AAAA',
|
||||||
|
annee_scolaire: '2024-2025',
|
||||||
|
mention: 'INFO',
|
||||||
|
num_inscription: 'azertyuiop',
|
||||||
|
sexe: 'F',
|
||||||
|
cin: '1234567890987',
|
||||||
|
date_de_delivrance: 'JJ/MM/AAAA',
|
||||||
|
nationaliter: 'Malagasy',
|
||||||
|
annee_baccalaureat: 'AAAA',
|
||||||
|
serie: 'D',
|
||||||
|
code_redoublement: 'N si nouveau, P si passant, R si redoublant RM si renvoyer, A si ancient',
|
||||||
|
boursier: 'Non',
|
||||||
|
domaine: "(S) Science de l'ingénieur",
|
||||||
|
contact: '0387205654'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nom: 'nom1',
|
||||||
|
prenom: 'prenom2',
|
||||||
|
niveau: 'L2',
|
||||||
|
date_naissance: 'jj/mm/AAAA',
|
||||||
|
annee_scolaire: '2024-2025',
|
||||||
|
mention: 'Informatique',
|
||||||
|
num_inscription: 'azertyuiop',
|
||||||
|
sexe: 'M',
|
||||||
|
cin: '1234567890987',
|
||||||
|
date_de_delivrance: 'JJ/MM/AAAA',
|
||||||
|
nationaliter: 'Malagasy',
|
||||||
|
annee_baccalaureat: 'AAAA',
|
||||||
|
serie: 'D',
|
||||||
|
code_redoublement: 'N si nouveau, P si passant, R si redoublant RM si renvoyer, A si ancient',
|
||||||
|
boursier: 'Non',
|
||||||
|
domaine: "(S) Science de l'ingénieur",
|
||||||
|
contact: '0387205654'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const convertToExcel = () => {
|
||||||
|
// convert json to sheet
|
||||||
|
const worksheet = XLSX.utils.json_to_sheet(exemplaireFileExcel)
|
||||||
|
|
||||||
|
// Create a new workbook and append the worksheet
|
||||||
|
const workbook = XLSX.utils.book_new()
|
||||||
|
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
|
||||||
|
|
||||||
|
// Write the workbook to a Blob and create a download link
|
||||||
|
const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' })
|
||||||
|
const data = new Blob([excelBuffer], { type: 'application/octet-stream' })
|
||||||
|
const url = URL.createObjectURL(data)
|
||||||
|
|
||||||
|
// Trigger a download
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = url
|
||||||
|
link.download = 'exemplaire_etudiant.xlsx'
|
||||||
|
link.click()
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
URL.revokeObjectURL(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleColumnVisibilityChange = (model) => {
|
||||||
|
// Get the currently visible columns
|
||||||
|
const visibleColumns = dynamicColumns.filter((column) => model[column.field] !== false)
|
||||||
|
|
||||||
|
// Create a new Excel file with visible columns
|
||||||
|
createExcelFile(visibleColumns)
|
||||||
|
}
|
||||||
|
|
||||||
|
const createExcelFile = (columns) => {
|
||||||
|
// Extract and set the header
|
||||||
|
const header = columns.reduce((acc, col) => {
|
||||||
|
acc[col.field] = col.headerName || col.field // Use headerName or field as default
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
|
||||||
|
// Map the data rows to match the extracted headers
|
||||||
|
const worksheetData = dataRow.map((row) => {
|
||||||
|
const filteredRow = {}
|
||||||
|
columns.forEach((col) => {
|
||||||
|
const headerName = header[col.field]
|
||||||
|
filteredRow[headerName] = row[col.field]
|
||||||
|
})
|
||||||
|
return filteredRow
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create a worksheet from the data
|
||||||
|
const ws = XLSX.utils.json_to_sheet(worksheetData)
|
||||||
|
|
||||||
|
// Create a workbook and add the worksheet to it
|
||||||
|
const wb = XLSX.utils.book_new()
|
||||||
|
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1')
|
||||||
|
|
||||||
|
// Generate the Excel file as binary data
|
||||||
|
const excelFile = XLSX.write(wb, { bookType: 'xlsx', type: 'array' })
|
||||||
|
|
||||||
|
// Create a Blob for the Excel data
|
||||||
|
const blob = new Blob([excelFile], {
|
||||||
|
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create a link element to trigger the download
|
||||||
|
const url = URL.createObjectURL(blob)
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = url
|
||||||
|
link.download = 'original-file.xlsx' // Original file name or any desired name
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()
|
||||||
|
document.body.removeChild(link)
|
||||||
|
URL.revokeObjectURL(url) // Clean up
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle header name change for a specific field and auto-export to Excel
|
||||||
|
const handleHeaderChange = (field, newHeaderName) => {
|
||||||
|
setColumns((prevColumns) =>
|
||||||
|
prevColumns.map((col) => (col.field === field ? { ...col, headerName: newHeaderName } : col))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classe.mainHome}>
|
||||||
|
{modals()}
|
||||||
|
<div className={classeAdd.header}>
|
||||||
|
<div className={classe.h1style}>
|
||||||
|
<div className={classeHome.blockTitle}>
|
||||||
|
<h1 style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
|
||||||
|
<FaFileExcel /> Export
|
||||||
|
</h1>
|
||||||
|
<Link to={'/addstudent'}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<IoMdReturnRight style={{ fontSize: '20px' }} />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
// position: 'absolute',
|
||||||
|
// top: '52%',
|
||||||
|
// left: '52%',
|
||||||
|
// transform: 'translate(-50%, -50%)',
|
||||||
|
width: '99.5%',
|
||||||
|
borderRadius: '2%',
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
boxShadow: 24,
|
||||||
|
p: 4
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ mt: 2, display: 'flex', alignItems: 'center', flexDirection: 'column' }}>
|
||||||
|
<div style={{ display: 'flex', gap: '20px', marginBottom: '20px' }}>
|
||||||
|
<Button
|
||||||
|
component="label"
|
||||||
|
variant="contained"
|
||||||
|
color="warning"
|
||||||
|
startIcon={<FaCloudUploadAlt />}
|
||||||
|
>
|
||||||
|
Charger un fichier excel
|
||||||
|
<VisuallyHiddenInput type="file" onChange={handleFileChange} accept=".xlsx, .csv" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
component="label"
|
||||||
|
variant="contained"
|
||||||
|
color="error"
|
||||||
|
startIcon={<FaCloudDownloadAlt />}
|
||||||
|
onClick={convertToExcel}
|
||||||
|
>
|
||||||
|
Télécharger le modèle d'import
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{error && (
|
||||||
|
<Typography color="error" variant="body2">
|
||||||
|
{error}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
{tableData.length > 0 && (
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
flexWrap: 'wrap'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Dropdowns for each column */}
|
||||||
|
{dynamicColumns.map((col) => (
|
||||||
|
<FormControl
|
||||||
|
key={col.field}
|
||||||
|
sx={{
|
||||||
|
m: 1,
|
||||||
|
width: '100%',
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
'&:hover fieldset': {
|
||||||
|
borderColor: '#ff9800' // Set the border color on hover
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
size="small"
|
||||||
|
color="warning"
|
||||||
|
variant="outlined"
|
||||||
|
style={{ margin: 10, width: 200 }}
|
||||||
|
>
|
||||||
|
<InputLabel id={col.headerName}>{col.headerName}</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId={col.headerName}
|
||||||
|
value={col.headerName}
|
||||||
|
label={col.headerName}
|
||||||
|
color="warning"
|
||||||
|
name={col.headerName}
|
||||||
|
onChange={(e) => handleHeaderChange(col.field, e.target.value)}
|
||||||
|
>
|
||||||
|
<MenuItem value={col.headerName}>{col.headerName}</MenuItem>
|
||||||
|
<MenuItem value={'nom'}>nom</MenuItem>
|
||||||
|
<MenuItem value={'prenom'}>prenom</MenuItem>
|
||||||
|
<MenuItem value={`niveau`}>niveau</MenuItem>
|
||||||
|
<MenuItem value={`date_naissance`}>date de naissance</MenuItem>
|
||||||
|
<MenuItem value={`annee_scolaire`}>année scolaire</MenuItem>
|
||||||
|
<MenuItem value={`mention`}>mention</MenuItem>
|
||||||
|
<MenuItem value={`num_inscription`}>numéro d'inscription</MenuItem>
|
||||||
|
<MenuItem value={`nationalite`}>Nationaliter</MenuItem>
|
||||||
|
<MenuItem value={`sexe`}>Sexe</MenuItem>
|
||||||
|
<MenuItem value={`cin`}>CIN</MenuItem>
|
||||||
|
<MenuItem value={`date_de_livraison`}>Date de livraison</MenuItem>
|
||||||
|
<MenuItem value={`annee_baccalaureat`}>Année du baccalaureat</MenuItem>
|
||||||
|
<MenuItem value={`serie`}>Série</MenuItem>
|
||||||
|
<MenuItem value={`code_redoublement`}>Code redoublement</MenuItem>
|
||||||
|
<MenuItem value={`boursier`}>Boursier</MenuItem>
|
||||||
|
<MenuItem value={`domaine`}>Domaine</MenuItem>
|
||||||
|
<MenuItem value={`contact`}>Contact</MenuItem>
|
||||||
|
<MenuItem value={`parcours`}>Parcours</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
flexDirection: 'column',
|
||||||
|
width: '100%'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DataGrid
|
||||||
|
rows={dataRow}
|
||||||
|
columns={dynamicColumns}
|
||||||
|
initialState={{ pagination: { paginationModel } }}
|
||||||
|
onColumnVisibilityModelChange={handleColumnVisibilityChange} // Listen for column visibility changes
|
||||||
|
pageSizeOptions={[5, 10]}
|
||||||
|
disableRowSelectionOnClick
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
minHeight: 400,
|
||||||
|
maxWidth: '100%', // Prevents grid from exceeding the container width
|
||||||
|
'@media (max-width: 600px)': {
|
||||||
|
width: '100%',
|
||||||
|
height: 'auto', // Adjust height for smaller screens
|
||||||
|
fontSize: '0.8rem' // Smaller font size for better readability on small screens
|
||||||
|
},
|
||||||
|
'@media (max-width: 960px)': {
|
||||||
|
fontSize: '1rem' // Adjust font size for medium screens
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
slots={{ toolbar: CustomBar }}
|
||||||
|
slotProps={{ toolbar: { onImport: handleImport } }}
|
||||||
|
localeText={frFR.components.MuiDataGrid.defaultProps.localeText}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ThemeProvider>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ExportEtudiants
|
||||||
564
src/renderer/src/components/Matieres.jsx
Normal file
564
src/renderer/src/components/Matieres.jsx
Normal file
@ -0,0 +1,564 @@
|
|||||||
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
|
import classe from '../assets/AllStyleComponents.module.css'
|
||||||
|
import classeAdd from '../assets/AddStudent.module.css'
|
||||||
|
import classeHome from '../assets/Home.module.css'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
import { BsBookmarkPlusFill } from 'react-icons/bs'
|
||||||
|
import {
|
||||||
|
FaUserCircle,
|
||||||
|
FaBook,
|
||||||
|
FaUserCog,
|
||||||
|
FaTrash,
|
||||||
|
FaPlus,
|
||||||
|
FaRegPlusSquare,
|
||||||
|
FaNewspaper
|
||||||
|
} from 'react-icons/fa'
|
||||||
|
import { Box, Button, InputAdornment, Typography, Modal, TextField, Grid } from '@mui/material'
|
||||||
|
import Paper from '@mui/material/Paper'
|
||||||
|
import { createTheme, ThemeProvider } from '@mui/material/styles'
|
||||||
|
import { DataGrid, GridToolbar } from '@mui/x-data-grid'
|
||||||
|
import { frFR } from '@mui/x-data-grid/locales'
|
||||||
|
import { Fa1, Fa2, Fa3, FaM, FaP, FaPenToSquare, FaS } from 'react-icons/fa6'
|
||||||
|
import { Tooltip } from 'react-tooltip'
|
||||||
|
import warning from '../assets/warning.svg'
|
||||||
|
import success from '../assets/success.svg'
|
||||||
|
import { GiTeacher } from 'react-icons/gi'
|
||||||
|
import ModalAddProf from './ModalAddProf'
|
||||||
|
import ParcourMatiere from './ParcourMatiere'
|
||||||
|
import UpdateModalProf from './UpdateModalProf'
|
||||||
|
import ModalProcessFichePresence from './ModalProcessFichePresence'
|
||||||
|
import ModalExportFichr from './ModalExportFichr'
|
||||||
|
import NiveauMatiere from './NiveauMatiere'
|
||||||
|
|
||||||
|
const Matieres = () => {
|
||||||
|
const [matiere, setMatiere] = useState([])
|
||||||
|
const [openAssignNiveau, setOpenAssignNiveau] = useState(false)
|
||||||
|
const [matiereIdAssign, setMatiereIdAssign] = useState(null)
|
||||||
|
const [Enseignants, setEnseignants] = useState([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.matieres.getMatiere().then((response) => {
|
||||||
|
setMatiere(response)
|
||||||
|
})
|
||||||
|
|
||||||
|
window.matieres.getENseignant().then((response) => {
|
||||||
|
setEnseignants(response)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const theme = createTheme({
|
||||||
|
components: {
|
||||||
|
MuiIconButton: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: 'gray' // Change the color of toolbar icons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MuiButton: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: '#121212' // Change the color of toolbar icons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const openAssignNiveauModal = (id) => {
|
||||||
|
setMatiereIdAssign(id)
|
||||||
|
setOpenAssignNiveau(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeAssignNiveauModal = () => {
|
||||||
|
setOpenAssignNiveau(false)
|
||||||
|
setMatiereIdAssign(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleNiveauAssignSuccess = (status) => {
|
||||||
|
if (status) {
|
||||||
|
// Rafraîchir les données des matières et enseignants
|
||||||
|
window.matieres.getMatiere().then((response) => {
|
||||||
|
setMatiere(response)
|
||||||
|
})
|
||||||
|
|
||||||
|
window.matieres.getENseignant().then((response) => {
|
||||||
|
setEnseignants(response)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const [isDeleted, setIsDeleted] = useState(false)
|
||||||
|
const [ids, setIds] = useState(0)
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{ field: 'nom', headerName: 'Nom', width: 230 },
|
||||||
|
{ field: 'credit', headerName: 'Crédit', width: 80 },
|
||||||
|
{ field: 'heure', headerName: 'Heure', width: 80 },
|
||||||
|
{ field: 'uniter', headerName: "Unité d'enseignement", width: 180 },
|
||||||
|
{ field: 'ue', headerName: 'UE', width: 80 },
|
||||||
|
{ field: 'niveau_id', headerName: 'Niveau', width: 80 },
|
||||||
|
{ field: 'enseignant', headerName: 'Professeur actuele', width: 230 },
|
||||||
|
{
|
||||||
|
field: 'action',
|
||||||
|
headerName: 'Action',
|
||||||
|
width: 600,
|
||||||
|
renderCell: (params) => (
|
||||||
|
<div style={{ display: 'flex', gap: '10px' }}>
|
||||||
|
<Link to={`/singlematiere/${params.value}`}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<FaPenToSquare
|
||||||
|
style={{ fontSize: '20px', color: 'white' }}
|
||||||
|
className={`update${params.value}`}
|
||||||
|
/>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.update${params.value}`}
|
||||||
|
style={{ fontSize: '15px', zIndex: 22 }}
|
||||||
|
place="top"
|
||||||
|
>
|
||||||
|
Modifier
|
||||||
|
</Tooltip>
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
<Link to={`/asignmatiere/${params.value}`}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<FaM
|
||||||
|
className={`asignMention${params.value}`}
|
||||||
|
style={{ fontSize: '20px', color: 'white' }}
|
||||||
|
/>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.asignMention${params.value}`}
|
||||||
|
style={{ fontSize: '15px', zIndex: 9 }}
|
||||||
|
place="top"
|
||||||
|
>
|
||||||
|
Assigner a un mension
|
||||||
|
</Tooltip>
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
to={`/asignmatieresemestre/${params.value}`}
|
||||||
|
className={`sem${params.value}`}
|
||||||
|
style={{ textDecoration: 'none' }}
|
||||||
|
>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.sem${params.value}`}
|
||||||
|
style={{ fontSize: '15px', zIndex: 9 }}
|
||||||
|
place="top"
|
||||||
|
>
|
||||||
|
Assigner à un semestre
|
||||||
|
</Tooltip>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<FaS style={{ fontSize: '20px', color: 'white' }} />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* ----------- BOUTON ASSIGNER NIVEAU ----------- */}
|
||||||
|
<Link
|
||||||
|
to="#"
|
||||||
|
className={`niveau${params.value}`}
|
||||||
|
style={{ textDecoration: 'none' }}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault(); // empêche le # de provoquer un scroll
|
||||||
|
openAssignNiveauModal(params.value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.niveau${params.value}`}
|
||||||
|
style={{ fontSize: '15px', zIndex: 9 }}
|
||||||
|
place="top"
|
||||||
|
>
|
||||||
|
Assigner à un niveau
|
||||||
|
</Tooltip>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
{/* Icône de ton choix, ici FaRegPlusSquare par exemple */}
|
||||||
|
<FaRegPlusSquare style={{ fontSize: '20px', color: 'white' }} />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
to="#"
|
||||||
|
style={{ textDecoration: 'none' }}
|
||||||
|
className={`parcour${params.value}`}
|
||||||
|
onClick={() => openParcoursFunction(params.value)}
|
||||||
|
>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.parcour${params.value}`}
|
||||||
|
style={{ fontSize: '15px', zIndex: 9 }}
|
||||||
|
place="top"
|
||||||
|
>
|
||||||
|
Assigner à des parcours
|
||||||
|
</Tooltip>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<FaP style={{ fontSize: '20px', color: 'white' }} />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<Link to={`#`}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<GiTeacher
|
||||||
|
style={{ fontSize: '20px', color: 'white' }}
|
||||||
|
className={`asignProf${params.value}`}
|
||||||
|
/>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.asignProf${params.value}`}
|
||||||
|
style={{ fontSize: '15px', zIndex: 22 }}
|
||||||
|
place="top"
|
||||||
|
clickable
|
||||||
|
>
|
||||||
|
<Link style={{ zIndex: 99, display: 'flex', alignItems: 'center', gap: '10px' }}>
|
||||||
|
<Button
|
||||||
|
color="warning"
|
||||||
|
variant="contained"
|
||||||
|
onClick={() => openFormModal(params.value)}
|
||||||
|
>
|
||||||
|
<FaPlus
|
||||||
|
style={{ fontSize: '20px', color: 'white' }}
|
||||||
|
className={`adprofModal${params.value}`}
|
||||||
|
/>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.adprofModal${params.value}`}
|
||||||
|
style={{ fontSize: '15px', zIndex: 9 }}
|
||||||
|
place="top"
|
||||||
|
>
|
||||||
|
Ajouter un nouveau professeur
|
||||||
|
</Tooltip>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
color="warning"
|
||||||
|
variant="contained"
|
||||||
|
onClick={() => openUppdateProfFunction(params.value)}
|
||||||
|
>
|
||||||
|
<FaPenToSquare
|
||||||
|
style={{ fontSize: '20px', color: 'white' }}
|
||||||
|
className={`updateprofModal${params.value}`}
|
||||||
|
/>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.updateprofModal${params.value}`}
|
||||||
|
style={{ fontSize: '15px', zIndex: 9 }}
|
||||||
|
place="top"
|
||||||
|
>
|
||||||
|
Modifier un professeur
|
||||||
|
</Tooltip>
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</Tooltip>
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
<Link to={`/fiche/${params.value}/${params.row.nom}`}>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.presence${params.value}`}
|
||||||
|
style={{ fontSize: '15px', zIndex: 22 }}
|
||||||
|
place="top"
|
||||||
|
>
|
||||||
|
Fiche de presence éxamen
|
||||||
|
</Tooltip>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<FaNewspaper
|
||||||
|
style={{ fontSize: '20px', color: 'white' }}
|
||||||
|
className={`presence${params.value}`}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
to={`#`}
|
||||||
|
onClick={() => {
|
||||||
|
setIds(params.row.id)
|
||||||
|
setOpen(true)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button color="error" variant="contained">
|
||||||
|
<FaTrash
|
||||||
|
style={{ fontSize: '20px', color: 'white' }}
|
||||||
|
className={`supprimer${params.value}`}
|
||||||
|
/>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.supprimer${params.value}`}
|
||||||
|
style={{ fontSize: '15px', zIndex: 22 }}
|
||||||
|
place="top"
|
||||||
|
>
|
||||||
|
Supprimer
|
||||||
|
</Tooltip>
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const compareMatieres = (matiere_id) => {
|
||||||
|
let NomPrenom = ''
|
||||||
|
for (let index = 0; index < Enseignants.length; index++) {
|
||||||
|
if (Enseignants[index].matiere_id == matiere_id) {
|
||||||
|
NomPrenom = `${Enseignants[index].nom_enseignant} ${Enseignants[index].prenom_enseignant}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NomPrenom
|
||||||
|
}
|
||||||
|
|
||||||
|
const paginationModel = { page: 0, pageSize: 5 }
|
||||||
|
|
||||||
|
let dataRow = matiere.map((mat) => ({
|
||||||
|
id: mat.id, // Ensure this exists and is unique for each etudiant
|
||||||
|
nom: mat.nom,
|
||||||
|
credit: mat.credit,
|
||||||
|
heure: mat.heure,
|
||||||
|
uniter: mat.unite_enseignement,
|
||||||
|
ue: mat.ue,
|
||||||
|
niveau_id: mat.niveau_nom ?? 'pas de niveau',
|
||||||
|
enseignant:
|
||||||
|
compareMatieres(mat.id) != '' ? compareMatieres(mat.id) : 'Veuillez assigner un professeur',
|
||||||
|
action: mat.id // Ensure this is a valid URL for the image
|
||||||
|
}))
|
||||||
|
|
||||||
|
const deleteButton = async (id) => {
|
||||||
|
let response = await window.matieres.deleteMatiere(id);
|
||||||
|
if (response.success) {
|
||||||
|
const updatedMatieres = matiere.filter((matiere) => matiere.id !== id)
|
||||||
|
setMatiere(updatedMatieres)
|
||||||
|
setIsDeleted(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hook to open modal
|
||||||
|
*/
|
||||||
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function to close modal
|
||||||
|
*/
|
||||||
|
const handleClose = () => {
|
||||||
|
setOpen(false)
|
||||||
|
setIsDeleted(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function to return the view Modal
|
||||||
|
*
|
||||||
|
* @returns {JSX}
|
||||||
|
*/
|
||||||
|
const modals = () => (
|
||||||
|
<Modal
|
||||||
|
open={open}
|
||||||
|
onClose={handleClose}
|
||||||
|
aria-labelledby="modal-title"
|
||||||
|
aria-describedby="modal-description"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
width: 450,
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
boxShadow: 24,
|
||||||
|
p: 4
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isDeleted ? (
|
||||||
|
<Typography
|
||||||
|
style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '10px' }}
|
||||||
|
>
|
||||||
|
<img src={success} alt="" width={50} height={50} /> <span>Suprimer avec succèss</span>
|
||||||
|
</Typography>
|
||||||
|
) : (
|
||||||
|
<Typography
|
||||||
|
style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '10px' }}
|
||||||
|
>
|
||||||
|
<img src={warning} alt="" width={50} height={50} />{' '}
|
||||||
|
<span>Voulez vous supprimer ce matiere ?</span>
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginTop: '2%',
|
||||||
|
display: 'flex',
|
||||||
|
gap: '20px',
|
||||||
|
alignItems: 'end',
|
||||||
|
justifyContent: 'flex-end'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isDeleted ? (
|
||||||
|
<Button onClick={handleClose} color="warning" variant="contained">
|
||||||
|
OK
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
onClick={() => deleteButton(ids)}
|
||||||
|
sx={{ mr: 1 }}
|
||||||
|
color="warning"
|
||||||
|
variant="contained"
|
||||||
|
>
|
||||||
|
Oui
|
||||||
|
</Button>
|
||||||
|
<Button onClick={handleClose} color="warning" variant="contained">
|
||||||
|
Non
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
|
||||||
|
const [openForm, setOpenForm] = useState(false)
|
||||||
|
const [matiereId, setMatiereId] = useState('')
|
||||||
|
const [isSubmitted, setIsSubmitted] = useState(false)
|
||||||
|
|
||||||
|
// Callback function to receive the submission status
|
||||||
|
const handleFormSubmit = (status) => {
|
||||||
|
setIsSubmitted(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isSubmitted) {
|
||||||
|
window.matieres
|
||||||
|
.getMatiere()
|
||||||
|
.then((response) => {
|
||||||
|
setMatiere(response)
|
||||||
|
setIsSubmitted(false) // Reset isSubmitted after fetching data
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error fetching matiere:', error)
|
||||||
|
setIsSubmitted(false) // Ensure reset even on error
|
||||||
|
})
|
||||||
|
|
||||||
|
window.matieres.getENseignant().then((response) => {
|
||||||
|
setEnseignants(response)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [isSubmitted])
|
||||||
|
|
||||||
|
const closeForm = () => {
|
||||||
|
setOpenForm(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const openFormModal = (id) => {
|
||||||
|
setOpenForm(true)
|
||||||
|
setMatiereId(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
const [openParcours, setOpenParcours] = useState(false)
|
||||||
|
const onCloseParcours = () => setOpenParcours(false)
|
||||||
|
const [idToSend, setIdToSend] = useState(null)
|
||||||
|
const openParcoursFunction = (id) => {
|
||||||
|
setIdToSend(id)
|
||||||
|
setOpenParcours(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const [openUppdateProf, setOpenUpdateProf] = useState(false)
|
||||||
|
const onCloseUpdateProf = () => setOpenUpdateProf(false)
|
||||||
|
const [idSends, setIdSend] = useState('')
|
||||||
|
const openUppdateProfFunction = (id) => {
|
||||||
|
setIdSend(id)
|
||||||
|
setOpenUpdateProf(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const [openFiche, setOpenFiche] = useState(false)
|
||||||
|
const onCloseFiche = () => setOpenFiche(false)
|
||||||
|
const [dataFiche, setDataFiche] = useState(null)
|
||||||
|
const paperRef = useRef()
|
||||||
|
|
||||||
|
// const extractFiche = async (matiere_id) => {
|
||||||
|
// let response = await
|
||||||
|
// setDataFiche(response)
|
||||||
|
// }
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classe.mainHome}>
|
||||||
|
{modals()}
|
||||||
|
<ModalAddProf
|
||||||
|
open={openForm}
|
||||||
|
onClose={closeForm}
|
||||||
|
matiere_id={matiereId}
|
||||||
|
onSubmitSuccess={handleFormSubmit}
|
||||||
|
/>
|
||||||
|
<ParcourMatiere matiere_id={idToSend} onClose={onCloseParcours} open={openParcours} />
|
||||||
|
<UpdateModalProf
|
||||||
|
matiere_id={idSends}
|
||||||
|
onClose={onCloseUpdateProf}
|
||||||
|
onSubmitSuccess={handleFormSubmit}
|
||||||
|
open={openUppdateProf}
|
||||||
|
/>
|
||||||
|
<ModalProcessFichePresence matiere_id={matiereId} onClose={onCloseFiche} open={openFiche} />
|
||||||
|
|
||||||
|
{/* Modal NiveauMatiere */}
|
||||||
|
<NiveauMatiere
|
||||||
|
open={openAssignNiveau}
|
||||||
|
onClose={closeAssignNiveauModal}
|
||||||
|
matiere_id={matiereIdAssign}
|
||||||
|
onSubmitSuccess={handleNiveauAssignSuccess}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className={classeAdd.header}>
|
||||||
|
<div className={classe.h1style}>
|
||||||
|
<div className={classeHome.blockTitle}>
|
||||||
|
<h1 style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
|
||||||
|
<FaBook />
|
||||||
|
Matiere
|
||||||
|
</h1>
|
||||||
|
<Link to={'/addmatiere'}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<BsBookmarkPlusFill style={{ fontSize: '20px' }} /> AJouter
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* displaying data */}
|
||||||
|
<div className={classeHome.boxEtudiantsCard}>
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'center' }}>
|
||||||
|
<Paper
|
||||||
|
sx={{
|
||||||
|
height: 'auto', // Auto height to make the grid responsive
|
||||||
|
minHeight: 500, // Ensures a minimum height
|
||||||
|
display: 'flex',
|
||||||
|
// alignItems: "center",
|
||||||
|
// justifyContent: "center",
|
||||||
|
width: '100%'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
flexDirection: 'column', // Stacks content vertically on smaller screens
|
||||||
|
width: '100%'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DataGrid
|
||||||
|
rows={dataRow}
|
||||||
|
columns={columns}
|
||||||
|
initialState={{ pagination: { paginationModel } }}
|
||||||
|
pageSizeOptions={[5, 10]}
|
||||||
|
sx={{
|
||||||
|
border: 0,
|
||||||
|
width: '100%', // Ensures the DataGrid takes full width
|
||||||
|
height: '100%', // Ensures it grows to fit content
|
||||||
|
minHeight: 400, // Minimum height for the DataGrid
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
'@media (max-width: 600px)': {
|
||||||
|
width: '100%', // 100% width on small screens
|
||||||
|
height: 'auto' // Allow height to grow with content
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
slots={{ toolbar: GridToolbar }}
|
||||||
|
localeText={frFR.components.MuiDataGrid.defaultProps.localeText}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ThemeProvider>
|
||||||
|
</Paper>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Matieres
|
||||||
220
src/renderer/src/components/ModalExportFichr.jsx
Normal file
220
src/renderer/src/components/ModalExportFichr.jsx
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
|
import { Link, useParams } from 'react-router-dom'
|
||||||
|
import classe from '../assets/AllStyleComponents.module.css'
|
||||||
|
import classeAdd from '../assets/AddStudent.module.css'
|
||||||
|
import classeHome from '../assets/Home.module.css'
|
||||||
|
import { FaBook, FaDownload } from 'react-icons/fa'
|
||||||
|
import { IoMdReturnRight } from 'react-icons/io'
|
||||||
|
import { Box, Button, Typography, ThemeProvider, Modal } from '@mui/material'
|
||||||
|
import Paper from '@mui/material/Paper'
|
||||||
|
import html2cancas from 'html2canvas'
|
||||||
|
import jsPDF from 'jspdf'
|
||||||
|
import autoTable from 'jspdf-autotable'
|
||||||
|
|
||||||
|
const ModalExportFichr = () => {
|
||||||
|
const [fiche, setFiche] = useState([])
|
||||||
|
const [mentions, setMentions] = useState([])
|
||||||
|
const PaperRef = useRef()
|
||||||
|
|
||||||
|
let { matiere_id } = useParams()
|
||||||
|
let { nom } = useParams()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (matiere_id !== null && matiere_id !== undefined) {
|
||||||
|
window.notesysteme.extractFiches({ matiere_id }).then((response) => {
|
||||||
|
setFiche(response)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
window.mention.getMention().then((response) => {
|
||||||
|
setMentions(response)
|
||||||
|
})
|
||||||
|
}, [matiere_id])
|
||||||
|
|
||||||
|
// Sort by NomPrenom alphabetically
|
||||||
|
const sortedStudents = fiche.sort((a, b) => a.nom.localeCompare(b.nom))
|
||||||
|
|
||||||
|
function compareMention(id) {
|
||||||
|
let mentionText
|
||||||
|
mentions.map((ment) => {
|
||||||
|
if (id == ment.id) {
|
||||||
|
mentionText = ment.nom
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return mentionText
|
||||||
|
}
|
||||||
|
|
||||||
|
// const download = () => {
|
||||||
|
// const generatePDF = async () => {
|
||||||
|
// try {
|
||||||
|
// await new Promise((resolve) => setTimeout(resolve, 500));
|
||||||
|
|
||||||
|
// const canvas = await html2cancas(PaperRef.current, {
|
||||||
|
// scale: 2,
|
||||||
|
// useCORS: true,
|
||||||
|
// logging: false,
|
||||||
|
// backgroundColor: "#ffffff",
|
||||||
|
// imageTimeout: 0, // ⬅️ Prevent timeout errors
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const imgData = canvas.toDataURL("image/jpeg", 0.8); // Use JPEG for smaller size
|
||||||
|
// const pdf = new jsPDF({
|
||||||
|
// orientation: "portrait",
|
||||||
|
// unit: "mm",
|
||||||
|
// format: "a4",
|
||||||
|
// compress: true,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// let imgWidth = 210;
|
||||||
|
// let imgHeight = (canvas.height * imgWidth) / canvas.width;
|
||||||
|
// let yPosition = 0;
|
||||||
|
|
||||||
|
// // If image height is greater than A4 page height, add multiple pages
|
||||||
|
// while (yPosition < imgHeight) {
|
||||||
|
// pdf.addImage(imgData, "JPEG", 0, yPosition * -1, imgWidth, imgHeight);
|
||||||
|
// if (yPosition + 297 < imgHeight) pdf.addPage(); // A4 height = 297mm
|
||||||
|
// yPosition += 297;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pdf.save("document.pdf");
|
||||||
|
|
||||||
|
// } catch (error) {
|
||||||
|
// console.error("Error generating PDF:", error);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// generatePDF();
|
||||||
|
// }
|
||||||
|
|
||||||
|
const download = () => {
|
||||||
|
const generatePDF = () => {
|
||||||
|
try {
|
||||||
|
const pdf = new jsPDF({
|
||||||
|
orientation: 'portrait',
|
||||||
|
unit: 'mm',
|
||||||
|
format: 'a4'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Select the table
|
||||||
|
autoTable(pdf, {
|
||||||
|
html: '#myTable', // ID de la table
|
||||||
|
startY: 20,
|
||||||
|
theme: 'grid',
|
||||||
|
headStyles: {
|
||||||
|
fillColor: 'gray',
|
||||||
|
halign: 'center',
|
||||||
|
fontStyle: 'bold',
|
||||||
|
textColor: 'black'
|
||||||
|
}, // Supprimer la couleur et centrer
|
||||||
|
margin: { top: 10 },
|
||||||
|
styles: { fontSize: 8, cellPadding: 2, halign: 'center' }, // Centrer le texte des cellules
|
||||||
|
didDrawPage: (data) => {
|
||||||
|
pdf.text('', 14, 10)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
pdf.save('document.pdf')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error generating PDF:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
generatePDF()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classe.mainHome}>
|
||||||
|
<div className={classeAdd.header}>
|
||||||
|
<div className={classe.h1style}>
|
||||||
|
<div className={classeHome.blockTitle}>
|
||||||
|
<h1 style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
|
||||||
|
<FaBook />
|
||||||
|
Matiere
|
||||||
|
</h1>
|
||||||
|
<div style={{ display: 'flex', gap: '10px' }}>
|
||||||
|
<Link to={'#'} onClick={download}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<FaDownload style={{ fontSize: '20px' }} />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
<Link to={'/matiere'}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<IoMdReturnRight style={{ fontSize: '20px' }} />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={classeHome.boxEtudiantsCard}>
|
||||||
|
<Paper
|
||||||
|
sx={{
|
||||||
|
// alignItems: "center",
|
||||||
|
// justifyContent: "center",
|
||||||
|
width: '100%'
|
||||||
|
}}
|
||||||
|
ref={PaperRef}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
padding: '10px',
|
||||||
|
textAlign: 'center',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<table style={{ border: 'solid 1px gray', fontSize: '20px' }} id="myTable">
|
||||||
|
<thead>
|
||||||
|
<tr style={{ textAlign: 'center', borderBottom: 'solid 1px gray' }}>
|
||||||
|
<th colSpan={4}> {nom} </th>
|
||||||
|
</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' }}>Mention</th>
|
||||||
|
<th>Emergement</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{sortedStudents.map((fi, index) => (
|
||||||
|
<tr key={index}>
|
||||||
|
<td
|
||||||
|
style={{
|
||||||
|
borderRight: 'solid 1px gray',
|
||||||
|
borderBottom: 'solid 1px gray',
|
||||||
|
padding: '5px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{index + 1}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
style={{
|
||||||
|
borderRight: 'solid 1px gray',
|
||||||
|
borderBottom: 'solid 1px gray',
|
||||||
|
padding: '5px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{fi.nom} {fi.prenom}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
style={{
|
||||||
|
borderRight: 'solid 1px gray',
|
||||||
|
borderBottom: 'solid 1px gray',
|
||||||
|
padding: '5px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{compareMention(fi.mention_id)}
|
||||||
|
</td>
|
||||||
|
<td style={{ borderBottom: 'solid 1px gray', padding: '5px' }}></td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</Paper>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ModalExportFichr
|
||||||
132
src/renderer/src/components/NiveauMatiere.jsx
Normal file
132
src/renderer/src/components/NiveauMatiere.jsx
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
Button,
|
||||||
|
Box,
|
||||||
|
Grid,
|
||||||
|
FormControl,
|
||||||
|
InputLabel,
|
||||||
|
Select,
|
||||||
|
OutlinedInput,
|
||||||
|
MenuItem
|
||||||
|
} from '@mui/material'
|
||||||
|
|
||||||
|
const NiveauMatiere = ({ open, onClose, matiere_id }) => {
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
niveau_id: '',
|
||||||
|
id: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const [niveaux, setNiveaux] = useState([])
|
||||||
|
const [niveauxMatiere, setNiveauxMatiere] = useState([])
|
||||||
|
console.log(niveaux);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.niveaus.getNiveau().then((response) => {
|
||||||
|
setNiveaux(response)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (niveauxMatiere.length !== 0) {
|
||||||
|
const niveauIds = niveauxMatiere.map((item) => item.niveau_id)
|
||||||
|
|
||||||
|
setFormData((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
niveau_id: niveauIds
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}, [niveauxMatiere])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (matiere_id) {
|
||||||
|
setFormData(prev => ({
|
||||||
|
...prev,
|
||||||
|
id: matiere_id
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}, [matiere_id]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const handleChange = (event) => {
|
||||||
|
const { name, value } = event.target
|
||||||
|
|
||||||
|
setFormData(prevState => ({
|
||||||
|
...prevState,
|
||||||
|
niveau_id: value // pas de tableau
|
||||||
|
}));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const formSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
console.log("Form envoyé côté front:", formData);
|
||||||
|
let response = await window.matieres.updateMatiereNiveau(formData);
|
||||||
|
console.log("Réponse backend:", response);
|
||||||
|
if (response.success) {
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open} onClose={onClose}>
|
||||||
|
<form action="" onSubmit={formSubmit}>
|
||||||
|
<DialogTitle>Assignation à des niveaux</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid item xs={12} sm={6}>
|
||||||
|
<FormControl sx={{ m: 1, width: 300 }}>
|
||||||
|
<InputLabel id="niveaux-select-label" color="warning">
|
||||||
|
Niveaux
|
||||||
|
</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId="niveaux-select-label"
|
||||||
|
id="niveaux-select"
|
||||||
|
name="niveau_id"
|
||||||
|
value={formData.niveau_id || ''}
|
||||||
|
onChange={handleChange}
|
||||||
|
color="warning"
|
||||||
|
size="small"
|
||||||
|
required
|
||||||
|
input={<OutlinedInput label="Niveaux" />}
|
||||||
|
MenuProps={{
|
||||||
|
PaperProps: {
|
||||||
|
style: {
|
||||||
|
maxHeight: 200,
|
||||||
|
width: 250
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{niveaux.map((niveau) => (
|
||||||
|
<MenuItem key={niveau.niveau_id} value={niveau.niveau_id}>
|
||||||
|
{niveau.nom}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={onClose} color="error">
|
||||||
|
Annuler
|
||||||
|
</Button>
|
||||||
|
<Button type="submit" color="warning">
|
||||||
|
Soumettre
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</form>
|
||||||
|
</Dialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NiveauMatiere
|
||||||
130
src/renderer/src/components/ParcourMatiere.jsx
Normal file
130
src/renderer/src/components/ParcourMatiere.jsx
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
TextField,
|
||||||
|
Button,
|
||||||
|
InputAdornment,
|
||||||
|
Box,
|
||||||
|
Grid,
|
||||||
|
FormControl,
|
||||||
|
InputLabel,
|
||||||
|
Select,
|
||||||
|
OutlinedInput,
|
||||||
|
MenuItem
|
||||||
|
} from '@mui/material'
|
||||||
|
|
||||||
|
const ParcourMatiere = ({ open, onClose, matiere_id }) => {
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
parcour_id: [],
|
||||||
|
matiere_id: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const [parcours, setParcours] = useState([])
|
||||||
|
const [parcoursMatiere, setParcoursMatiere] = useState([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.notesysteme.getParcours().then((response) => {
|
||||||
|
setParcours(response)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (matiere_id) {
|
||||||
|
setFormData({
|
||||||
|
matiere_id: matiere_id
|
||||||
|
})
|
||||||
|
|
||||||
|
window.notesysteme.getParcourMatiere({ matiere_id }).then((response) => {
|
||||||
|
setParcoursMatiere(response)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [matiere_id])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (parcoursMatiere.length !== 0) {
|
||||||
|
const parcourIds = parcoursMatiere.map((item) => item.parcour_id)
|
||||||
|
|
||||||
|
setFormData((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
parcour_id: parcourIds // Merge & remove duplicates
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}, [parcoursMatiere])
|
||||||
|
|
||||||
|
const handleChange = (event) => {
|
||||||
|
const { name, value } = event.target
|
||||||
|
|
||||||
|
setFormData((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
[name]: value // Ensures multiple selection works correctly
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
const formSubmit = async (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
let response = await window.notesysteme.parcourMatiere(formData)
|
||||||
|
if (response.success) {
|
||||||
|
onClose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open} onClose={onClose}>
|
||||||
|
<form action="" onSubmit={formSubmit}>
|
||||||
|
<DialogTitle>Assignation à des parcours</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid item xs={12} sm={6}>
|
||||||
|
<FormControl sx={{ m: 1, width: 300 }}>
|
||||||
|
<InputLabel id="parcours-select-label" color="warning">
|
||||||
|
Parcours
|
||||||
|
</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId="parcours-select-label"
|
||||||
|
id="parcours-select"
|
||||||
|
multiple
|
||||||
|
name="parcour_id"
|
||||||
|
value={formData.parcour_id || []}
|
||||||
|
onChange={handleChange}
|
||||||
|
color="warning"
|
||||||
|
size="small"
|
||||||
|
required
|
||||||
|
input={<OutlinedInput label="Parcours" />} // Fixed label name
|
||||||
|
MenuProps={{
|
||||||
|
PaperProps: {
|
||||||
|
style: {
|
||||||
|
maxHeight: 200, // Limit dropdown height
|
||||||
|
width: 250 // Adjust dropdown width if needed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{parcours.map((sem) => (
|
||||||
|
<MenuItem key={sem.id} value={sem.id}>
|
||||||
|
{sem.nom}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={onClose} color="error">
|
||||||
|
Annuler
|
||||||
|
</Button>
|
||||||
|
<Button type="submit" color="warning">
|
||||||
|
Soumettre
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</form>
|
||||||
|
</Dialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ParcourMatiere
|
||||||
199
src/renderer/src/components/Parcours.jsx
Normal file
199
src/renderer/src/components/Parcours.jsx
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import classe from '../assets/AllStyleComponents.module.css'
|
||||||
|
import classeAdd from '../assets/AddStudent.module.css'
|
||||||
|
import classeHome from '../assets/Home.module.css'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
import { MdRule } from 'react-icons/md'
|
||||||
|
import { FaPlus } from 'react-icons/fa'
|
||||||
|
import { Box, Button, InputAdornment, Typography, Modal, TextField, Grid } from '@mui/material'
|
||||||
|
import Paper from '@mui/material/Paper'
|
||||||
|
import { createTheme, ThemeProvider } from '@mui/material/styles'
|
||||||
|
import { DataGrid, GridToolbar } from '@mui/x-data-grid'
|
||||||
|
import { frFR } from '@mui/x-data-grid/locales'
|
||||||
|
import { Tooltip } from 'react-tooltip'
|
||||||
|
import warning from '../assets/warning.svg'
|
||||||
|
import success from '../assets/success.svg'
|
||||||
|
import AddParcours from './AddParcours'
|
||||||
|
import UpdateParcour from './UpdateParcour'
|
||||||
|
import { FaPenToSquare } from 'react-icons/fa6'
|
||||||
|
|
||||||
|
const Parcours = () => {
|
||||||
|
const [parcours, setParcours] = useState([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.notesysteme.getParcours().then((response) => {
|
||||||
|
setParcours(response)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const theme = createTheme({
|
||||||
|
components: {
|
||||||
|
MuiIconButton: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: 'gray' // Change the color of toolbar icons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MuiButton: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: '#121212' // Change the color of toolbar icons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{ field: 'nom', headerName: 'Nom', width: 230 },
|
||||||
|
{ field: 'uniter', headerName: 'Uniter', width: 180 },
|
||||||
|
{ field: 'mention', headerName: 'Mention', width: 230 },
|
||||||
|
{
|
||||||
|
field: 'action',
|
||||||
|
headerName: 'Action',
|
||||||
|
flex: 1,
|
||||||
|
renderCell: (params) => (
|
||||||
|
<div style={{ display: 'flex', gap: '10px' }}>
|
||||||
|
<Link to={`#`} onClick={() => openUpdate(params.value)}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<FaPenToSquare
|
||||||
|
style={{ fontSize: '20px', color: 'white', outline: 'none' }}
|
||||||
|
className={`update${params.value}`}
|
||||||
|
/>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.update${params.value}`}
|
||||||
|
style={{ fontSize: '15px', zIndex: 22 }}
|
||||||
|
place="top"
|
||||||
|
>
|
||||||
|
Modifier
|
||||||
|
</Tooltip>
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const paginationModel = { page: 0, pageSize: 5 }
|
||||||
|
|
||||||
|
const dataRow = parcours.map((parc) => ({
|
||||||
|
id: parc.id,
|
||||||
|
nom: parc.nom,
|
||||||
|
uniter: parc.uniter,
|
||||||
|
mention: parc.mention_nom || parc.mention || 'Mention non trouvée',
|
||||||
|
action: parc.id
|
||||||
|
}))
|
||||||
|
|
||||||
|
const [isSubmitted, setIsSubmitted] = useState(false)
|
||||||
|
const handleFormSubmit = (status) => {
|
||||||
|
setIsSubmitted(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isSubmitted) {
|
||||||
|
window.notesysteme.getParcours().then((response) => {
|
||||||
|
setParcours(response)
|
||||||
|
})
|
||||||
|
setIsSubmitted(false)
|
||||||
|
}
|
||||||
|
}, [isSubmitted])
|
||||||
|
|
||||||
|
const [openModalAdd, setOpenModalAdd] = useState(false)
|
||||||
|
const [openModalUpdate, setOpenModalUpdate] = useState(false)
|
||||||
|
const [idToSend, setIdToSend] = useState(null)
|
||||||
|
|
||||||
|
const closeUpdate = () => {
|
||||||
|
setOpenModalUpdate(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const openUpdate = (id) => {
|
||||||
|
setIdToSend(id)
|
||||||
|
setOpenModalUpdate(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const openModalAddFunction = () => {
|
||||||
|
setOpenModalAdd(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeModalAdd = () => {
|
||||||
|
setOpenModalAdd(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classe.mainHome}>
|
||||||
|
<AddParcours open={openModalAdd} onClose={closeModalAdd} onSubmitSuccess={handleFormSubmit} />
|
||||||
|
<UpdateParcour
|
||||||
|
id={idToSend}
|
||||||
|
onClose={closeUpdate}
|
||||||
|
onSubmitSuccess={handleFormSubmit}
|
||||||
|
open={openModalUpdate}
|
||||||
|
/>
|
||||||
|
<div className={classeAdd.header}>
|
||||||
|
<div className={classe.h1style}>
|
||||||
|
<div className={classeHome.blockTitle}>
|
||||||
|
<h1 style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
|
||||||
|
<MdRule />
|
||||||
|
Parcours
|
||||||
|
</h1>
|
||||||
|
<Link to={'#'} onClick={openModalAddFunction}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<FaPlus style={{ fontSize: '20px' }} /> AJouter
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={classeHome.boxEtudiantsCard}>
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'center' }}>
|
||||||
|
<Paper
|
||||||
|
sx={{
|
||||||
|
height: 'auto', // Auto height to make the grid responsive
|
||||||
|
minHeight: 500, // Ensures a minimum height
|
||||||
|
display: 'flex',
|
||||||
|
// alignItems: "center",
|
||||||
|
// justifyContent: "center",
|
||||||
|
width: '100%'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
flexDirection: 'column', // Stacks content vertically on smaller screens
|
||||||
|
width: '100%'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DataGrid
|
||||||
|
rows={dataRow}
|
||||||
|
columns={columns}
|
||||||
|
initialState={{ pagination: { paginationModel } }}
|
||||||
|
pageSizeOptions={[5, 10]}
|
||||||
|
sx={{
|
||||||
|
border: 0,
|
||||||
|
width: '100%', // Ensures the DataGrid takes full width
|
||||||
|
height: '100%', // Ensures it grows to fit content
|
||||||
|
minHeight: 400, // Minimum height for the DataGrid
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
'@media (max-width: 600px)': {
|
||||||
|
width: '100%', // 100% width on small screens
|
||||||
|
height: 'auto' // Allow height to grow with content
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
slots={{ toolbar: GridToolbar }}
|
||||||
|
localeText={frFR.components.MuiDataGrid.defaultProps.localeText}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ThemeProvider>
|
||||||
|
</Paper>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Parcours
|
||||||
218
src/renderer/src/components/Resultat.jsx
Normal file
218
src/renderer/src/components/Resultat.jsx
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
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 { IoMdReturnRight } from 'react-icons/io'
|
||||||
|
import jsPDF from 'jspdf'
|
||||||
|
import autoTable from 'jspdf-autotable'
|
||||||
|
import { FaDownload } from 'react-icons/fa'
|
||||||
|
|
||||||
|
const Resultat = () => {
|
||||||
|
const { niveau, scolaire } = useParams()
|
||||||
|
const formData = {
|
||||||
|
niveau,
|
||||||
|
scolaire
|
||||||
|
}
|
||||||
|
const [etudiants, setEtudiants] = useState([])
|
||||||
|
const [mention, setMention] = useState([])
|
||||||
|
const [session, setSession] = useState([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.notes.getMoyenne(formData).then((response) => {
|
||||||
|
setEtudiants(response)
|
||||||
|
})
|
||||||
|
window.noteRepech.getMoyenneRepech(formData).then((response) => {
|
||||||
|
setSession(response)
|
||||||
|
})
|
||||||
|
window.mention.getMention().then((response) => {
|
||||||
|
setMention(response)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
let dataToMap = []
|
||||||
|
|
||||||
|
function returnmention(id) {
|
||||||
|
let mentions
|
||||||
|
for (let index = 0; index < mention.length; index++) {
|
||||||
|
if (mention[index].id == id) {
|
||||||
|
mentions = mention[index].nom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mentions
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkNull(params) {
|
||||||
|
if (params == null || params == undefined) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
const print = () => {
|
||||||
|
const generatePDF = () => {
|
||||||
|
try {
|
||||||
|
const pdf = new jsPDF({
|
||||||
|
orientation: 'portrait',
|
||||||
|
unit: 'mm',
|
||||||
|
format: 'a4'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Select the table
|
||||||
|
autoTable(pdf, {
|
||||||
|
html: '#myTable2', // ID de la table
|
||||||
|
startY: 20,
|
||||||
|
theme: 'grid',
|
||||||
|
headStyles: {
|
||||||
|
fillColor: 'gray',
|
||||||
|
halign: 'center',
|
||||||
|
fontStyle: 'bold',
|
||||||
|
textColor: 'black'
|
||||||
|
}, // Supprimer la couleur et centrer
|
||||||
|
margin: { top: 10 },
|
||||||
|
styles: { fontSize: 8, cellPadding: 2, halign: 'center' }, // Centrer le texte des cellules
|
||||||
|
didDrawPage: (data) => {
|
||||||
|
pdf.text('', 14, 10)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
pdf.save(`Resultat-${niveau}-${scolaire}.pdf`)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error generating PDF:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
generatePDF()
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareSessionNotes(session1, session2) {
|
||||||
|
let notes
|
||||||
|
if (session2) {
|
||||||
|
if (session1 < session2.note) {
|
||||||
|
notes = session2.note
|
||||||
|
} else {
|
||||||
|
notes = session1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
notes = session1
|
||||||
|
}
|
||||||
|
return notes
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let index = 0; index < etudiants.length; index++) {
|
||||||
|
let total = 0
|
||||||
|
let note = 0
|
||||||
|
let totalCredit = 0
|
||||||
|
|
||||||
|
// Create a new object for each student
|
||||||
|
let modelJson = {
|
||||||
|
id: '',
|
||||||
|
nom: '',
|
||||||
|
prenom: '',
|
||||||
|
photos: '',
|
||||||
|
moyenne: '',
|
||||||
|
mention: '',
|
||||||
|
anneescolaire: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let j = 0; j < etudiants[index].length; j++) {
|
||||||
|
modelJson.id = etudiants[index][j].etudiant_id
|
||||||
|
modelJson.nom = etudiants[index][j].nom
|
||||||
|
modelJson.prenom = etudiants[index][j].prenom
|
||||||
|
modelJson.photos = etudiants[index][j].photos
|
||||||
|
modelJson.mention = etudiants[index][j].mention_id
|
||||||
|
modelJson.anneescolaire = etudiants[index][j].annee_scolaire
|
||||||
|
|
||||||
|
// console.log(checkNull(session[index][j]));
|
||||||
|
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
|
||||||
|
}
|
||||||
|
totalCredit += etudiants[index][j].credit
|
||||||
|
}
|
||||||
|
|
||||||
|
total = note / totalCredit
|
||||||
|
modelJson.moyenne = total.toFixed(2)
|
||||||
|
|
||||||
|
// Add the new object to the array
|
||||||
|
dataToMap.push(modelJson)
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortedStudents = dataToMap
|
||||||
|
.filter((student) => parseFloat(student.moyenne) >= 10)
|
||||||
|
.sort((a, b) => parseFloat(b.moyenne) - parseFloat(a.moyenne))
|
||||||
|
|
||||||
|
console.log(sortedStudents)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classe.mainHome}>
|
||||||
|
<div className={classeHome.header}>
|
||||||
|
<div className={classe.h1style}>
|
||||||
|
<div className={classeHome.blockTitle}>
|
||||||
|
<h1>
|
||||||
|
Resultat des {niveau} en {scolaire}
|
||||||
|
</h1>
|
||||||
|
<div style={{ display: 'flex', gap: '10px' }}>
|
||||||
|
<Link to={'#'} onClick={print}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<FaDownload style={{ fontSize: '20px' }} />
|
||||||
|
Télécharger
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
<Link to={'#'} onClick={() => window.history.back()}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<IoMdReturnRight style={{ fontSize: '20px' }} />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={classeHome.boxEtudiantsCard}>
|
||||||
|
<Paper
|
||||||
|
sx={{
|
||||||
|
height: 'auto', // Auto height to make the grid responsive
|
||||||
|
width: '100%',
|
||||||
|
// minHeight: 500, // Ensures a minimum height
|
||||||
|
display: 'flex',
|
||||||
|
padding: '2%'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<table className="table table-bordered table-striped text-center shadow-sm" id="myTable2">
|
||||||
|
<thead className="table-secondary">
|
||||||
|
<tr>
|
||||||
|
<td colSpan={4} className="py-3">
|
||||||
|
<h6>
|
||||||
|
Niveau {niveau} | Année Scolaire {scolaire}
|
||||||
|
</h6>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Nom</th>
|
||||||
|
<th>Prenom</th>
|
||||||
|
<th>Mention</th>
|
||||||
|
<th>Moyenne</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{sortedStudents.map((sorted) => (
|
||||||
|
<tr key={sorted.id}>
|
||||||
|
<td>{sorted.nom}</td>
|
||||||
|
<td>{sorted.prenom}</td>
|
||||||
|
<td>{returnmention(sorted.mention)}</td>
|
||||||
|
<td className="fw-bold">{sorted.moyenne}</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</Paper>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Resultat
|
||||||
283
src/renderer/src/components/Sidenav.jsx
Normal file
283
src/renderer/src/components/Sidenav.jsx
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
import React, { useState } from 'react'
|
||||||
|
import classe from '../assets/Sidenav.module.css'
|
||||||
|
import { RiDashboardHorizontalFill } from 'react-icons/ri'
|
||||||
|
import { PiStudentFill } from 'react-icons/pi'
|
||||||
|
import { IoMdHelpCircleOutline } from 'react-icons/io'
|
||||||
|
import { CgNotes } from 'react-icons/cg'
|
||||||
|
import { FaUserCircle, FaBook, FaUserCog } from 'react-icons/fa'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
import { useLocation } from 'react-router-dom'
|
||||||
|
import { Tooltip } from 'react-tooltip'
|
||||||
|
import { LuLogOut } from 'react-icons/lu'
|
||||||
|
import { GiUpgrade } from 'react-icons/gi'
|
||||||
|
import Menu from '@mui/material/Menu'
|
||||||
|
import MenuItem from '@mui/material/MenuItem'
|
||||||
|
import { useAuthContext } from '../contexts/AuthContext'
|
||||||
|
import { MdAdminPanelSettings, MdRule } from 'react-icons/md'
|
||||||
|
import { BsCalendar2Date } from 'react-icons/bs'
|
||||||
|
import { SiVitest } from 'react-icons/si'
|
||||||
|
import { GrManual } from 'react-icons/gr'
|
||||||
|
import { FaClipboardList } from 'react-icons/fa6'
|
||||||
|
|
||||||
|
const Sidenav = () => {
|
||||||
|
const [anchorEl, setAnchorEl] = useState(null)
|
||||||
|
const open = Boolean(anchorEl)
|
||||||
|
const { setToken } = useAuthContext()
|
||||||
|
|
||||||
|
const handleClick = (event) => {
|
||||||
|
setAnchorEl(event.currentTarget)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setAnchorEl(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't touch it, i don't know why but the active button stop workin without this
|
||||||
|
const location = useLocation()
|
||||||
|
|
||||||
|
const logout = () => {
|
||||||
|
localStorage.removeItem('ACCESS_TOKEN')
|
||||||
|
setToken(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<nav className={classe.navbar}>
|
||||||
|
<style>
|
||||||
|
{`
|
||||||
|
.custom-tooltip {
|
||||||
|
font-size: 15px;
|
||||||
|
border: solid 1px white !important;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
</style>
|
||||||
|
<ul className={classe.liste1}>
|
||||||
|
<li>
|
||||||
|
<Link
|
||||||
|
to={'/'}
|
||||||
|
className={classe.nav_link}
|
||||||
|
style={{
|
||||||
|
outline: 'none',
|
||||||
|
borderBottom: window.location.hash == '#/' ? '2px solid white' : 'none'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RiDashboardHorizontalFill className="dashboard" style={{ outline: 'none' }} />
|
||||||
|
<Tooltip anchorSelect=".dashboard" className="custom-tooltip" place="top">
|
||||||
|
Dashboard
|
||||||
|
</Tooltip>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link
|
||||||
|
to={'/student'}
|
||||||
|
className={classe.nav_link}
|
||||||
|
style={{
|
||||||
|
outline: 'none',
|
||||||
|
borderBottom: window.location.hash == '#/student' ? '2px solid white' : 'none'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PiStudentFill className="student" style={{ outline: 'none' }} />
|
||||||
|
<Tooltip anchorSelect=".student" className="custom-tooltip" place="top">
|
||||||
|
Etudiants
|
||||||
|
</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>
|
||||||
|
<li>
|
||||||
|
<Link
|
||||||
|
to={'/mention'}
|
||||||
|
className={classe.nav_link}
|
||||||
|
style={{
|
||||||
|
outline: 'none',
|
||||||
|
borderBottom: window.location.hash == '#/mention' ? '2px solid white' : 'none'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FaClipboardList className="mention" style={{ outline: 'none' }} />
|
||||||
|
<Tooltip anchorSelect=".mention" className="custom-tooltip" place="top">
|
||||||
|
Mentions
|
||||||
|
</Tooltip>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link
|
||||||
|
to={'/matiere'}
|
||||||
|
className={classe.nav_link}
|
||||||
|
style={{
|
||||||
|
outline: 'none',
|
||||||
|
borderBottom: window.location.hash == '#/matiere' ? '2px solid white' : 'none'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FaBook className="matiere" style={{ outline: 'none' }} />
|
||||||
|
<Tooltip anchorSelect=".matiere" className="custom-tooltip" place="top">
|
||||||
|
Matières
|
||||||
|
</Tooltip>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link
|
||||||
|
to={'/niveau'}
|
||||||
|
className={classe.nav_link}
|
||||||
|
style={{
|
||||||
|
outline: 'none',
|
||||||
|
borderBottom: window.location.hash == '#/niveau' ? '2px solid white' : 'none'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<GiUpgrade className="niveau" style={{ outline: 'none' }} />
|
||||||
|
<Tooltip anchorSelect=".niveau" className="custom-tooltip" place="top">
|
||||||
|
Niveau
|
||||||
|
</Tooltip>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link
|
||||||
|
to={'/anneescolaire'}
|
||||||
|
className={classe.nav_link}
|
||||||
|
style={{
|
||||||
|
outline: 'none',
|
||||||
|
borderBottom: window.location.hash == '#/niveau' ? '2px solid white' : 'none'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<BsCalendar2Date className="anneescolaire" style={{ outline: 'none' }} />
|
||||||
|
<Tooltip anchorSelect=".anneescolaire" className="custom-tooltip" place="top">
|
||||||
|
Année Scolaire
|
||||||
|
</Tooltip>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link
|
||||||
|
to={'/parcours'}
|
||||||
|
className={classe.nav_link}
|
||||||
|
style={{
|
||||||
|
outline: 'none',
|
||||||
|
borderBottom: window.location.hash == '#/parcours' ? '2px solid white' : 'none'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MdRule className="rules" style={{ outline: 'none' }} />
|
||||||
|
<Tooltip anchorSelect=".rules" className="custom-tooltip" place="top">
|
||||||
|
Parcours
|
||||||
|
</Tooltip>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link
|
||||||
|
to={'/apropos'}
|
||||||
|
className={classe.nav_link}
|
||||||
|
style={{
|
||||||
|
outline: 'none',
|
||||||
|
borderBottom: window.location.hash == '#/apropos' ? '2px solid white' : 'none'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IoMdHelpCircleOutline className="Apropos" style={{ outline: 'none' }} />
|
||||||
|
<Tooltip anchorSelect=".Apropos" className="custom-tooltip" place="top">
|
||||||
|
A propos
|
||||||
|
</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>
|
||||||
|
<Link
|
||||||
|
id="basic-button"
|
||||||
|
aria-controls={open ? 'basic-menu' : undefined}
|
||||||
|
aria-haspopup="true"
|
||||||
|
aria-expanded={open ? 'true' : undefined}
|
||||||
|
onClick={handleClick}
|
||||||
|
style={{
|
||||||
|
outline: 'none',
|
||||||
|
borderBottom:
|
||||||
|
window.location.hash == '#/admin' || window.location.hash == '#/para'
|
||||||
|
? '2px solid white'
|
||||||
|
: 'none'
|
||||||
|
}}
|
||||||
|
to={'#'}
|
||||||
|
className={classe.nav_link}
|
||||||
|
>
|
||||||
|
<FaUserCircle className="admin" style={{ outline: 'none' }} />
|
||||||
|
<Tooltip anchorSelect=".admin" place="top" className="custom-tooltip">
|
||||||
|
Admin
|
||||||
|
</Tooltip>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<Menu
|
||||||
|
id="basic-menu"
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
open={open}
|
||||||
|
onClose={handleClose}
|
||||||
|
MenuListProps={{
|
||||||
|
'aria-labelledby': 'basic-button'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MenuItem>
|
||||||
|
<Link
|
||||||
|
to="/systemenote"
|
||||||
|
style={{ color: 'black', textDecoration: 'none' }}
|
||||||
|
onClick={handleClose}
|
||||||
|
>
|
||||||
|
<CgNotes /> Système des notes
|
||||||
|
</Link>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem>
|
||||||
|
<Link
|
||||||
|
to="/admin"
|
||||||
|
style={{ color: 'black', textDecoration: 'none' }}
|
||||||
|
onClick={handleClose}
|
||||||
|
>
|
||||||
|
<MdAdminPanelSettings /> Admin
|
||||||
|
</Link>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem>
|
||||||
|
<Link
|
||||||
|
to="/para"
|
||||||
|
style={{ color: 'black', textDecoration: 'none' }}
|
||||||
|
onClick={handleClose}
|
||||||
|
>
|
||||||
|
<FaUserCog /> Paramètre
|
||||||
|
</Link>
|
||||||
|
</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">
|
||||||
|
Déconnexion
|
||||||
|
</Tooltip>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Sidenav
|
||||||
268
src/renderer/src/components/SingleAnneeScolaire.jsx
Normal file
268
src/renderer/src/components/SingleAnneeScolaire.jsx
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import classe from '../assets/AllStyleComponents.module.css'
|
||||||
|
import classeHome from '../assets/Home.module.css'
|
||||||
|
import Paper from '@mui/material/Paper'
|
||||||
|
import { Link, useParams } from 'react-router-dom'
|
||||||
|
import { IoMdReturnRight } from 'react-icons/io'
|
||||||
|
import { Modal, Box, Typography, Button, InputAdornment, TextField, Grid } from '@mui/material'
|
||||||
|
import { FaCalendarAlt } from 'react-icons/fa'
|
||||||
|
import svgError from '../assets/error.svg'
|
||||||
|
import svgSuccess from '../assets/success.svg'
|
||||||
|
import { BsCalendar2Date } from 'react-icons/bs'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
|
||||||
|
const SingleAnneeScolaire = () => {
|
||||||
|
const { id } = useParams()
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
code: '',
|
||||||
|
debut: '',
|
||||||
|
fin: '',
|
||||||
|
id: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const [scolaire, setScolaire] = useState([])
|
||||||
|
const [status, setStatus] = useState(200)
|
||||||
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.anneescolaire.getSingleAnneeScolaire({ id }).then((response) => {
|
||||||
|
setScolaire(response)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setFormData((prev) => ({
|
||||||
|
...prev,
|
||||||
|
code: scolaire.code,
|
||||||
|
debut: dayjs(scolaire.debut).format('YYYY-MM-DD'),
|
||||||
|
fin: dayjs(scolaire.fin).format('YYYY-MM-DD'),
|
||||||
|
id: scolaire.id
|
||||||
|
}))
|
||||||
|
}, [scolaire])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function to set the data in state
|
||||||
|
* @param {*} e
|
||||||
|
*/
|
||||||
|
const handleInputChange = (e) => {
|
||||||
|
const { name, value } = e.target
|
||||||
|
setFormData((prevData) => ({
|
||||||
|
...prevData,
|
||||||
|
[name]: value
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
const formSubmit = async (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
let response = await window.anneescolaire.updateAnneeScolaire(formData)
|
||||||
|
|
||||||
|
if (response.success) {
|
||||||
|
setOpen(true)
|
||||||
|
setStatus(200)
|
||||||
|
} else {
|
||||||
|
setStatus(400)
|
||||||
|
setOpen(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClose = () => setOpen(false)
|
||||||
|
|
||||||
|
const modals = () => (
|
||||||
|
<Modal
|
||||||
|
open={open}
|
||||||
|
onClose={handleClose}
|
||||||
|
aria-labelledby="modal-title"
|
||||||
|
aria-describedby="modal-description"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
width: 450,
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
boxShadow: 24,
|
||||||
|
p: 4
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 2
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img src={status === 200 ? svgSuccess : svgError} alt="" width={70} height={70} />
|
||||||
|
<span> {status === 200 ? 'Mise à jour effectuée avec succès' : 'Erreur'}</span>
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginTop: 2,
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'flex-end'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button onClick={handleClose} color="warning" variant="contained">
|
||||||
|
OK
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classe.mainHome}>
|
||||||
|
{modals()}
|
||||||
|
<div className={classeHome.header}>
|
||||||
|
<div className={classe.h1style}>
|
||||||
|
<div className={classeHome.blockTitle}>
|
||||||
|
<h1 style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
|
||||||
|
<BsCalendar2Date />
|
||||||
|
Mise a jour Année Scolaire
|
||||||
|
</h1>
|
||||||
|
<Link to={'#'} onClick={() => window.history.back()}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<IoMdReturnRight style={{ fontSize: '20px' }} />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={classeHome.boxEtudiantsCard}>
|
||||||
|
<Paper
|
||||||
|
sx={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%', // Auto height to make the grid responsive
|
||||||
|
minHeight: 500, // Ensures a minimum height
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<form
|
||||||
|
style={{
|
||||||
|
width: '50%',
|
||||||
|
padding: '1%',
|
||||||
|
height: '20%',
|
||||||
|
border: 'solid 2px orange',
|
||||||
|
borderRadius: '10px'
|
||||||
|
}}
|
||||||
|
onSubmit={formSubmit}
|
||||||
|
>
|
||||||
|
<h4 style={{ textAlign: 'center', padding: '0 0 3% 0' }}>
|
||||||
|
mise a jour Année Scolaire
|
||||||
|
</h4>
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid item xs={12} sm={6}>
|
||||||
|
<TextField
|
||||||
|
label={'Année Scolaire'}
|
||||||
|
name={'code'}
|
||||||
|
placeholder="2024-2025"
|
||||||
|
color="warning"
|
||||||
|
fullWidth
|
||||||
|
value={formData.code}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<FaCalendarAlt />
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
required
|
||||||
|
className="inputAddNote"
|
||||||
|
sx={{
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
'&:hover fieldset': {
|
||||||
|
borderColor: '#ff9800' // Set the border color on hover
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'& .MuiInputBase-input::placeholder': {
|
||||||
|
fontSize: '14px' // Set the placeholder font size
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6}>
|
||||||
|
<TextField
|
||||||
|
label={'Date de début'}
|
||||||
|
name={'debut'}
|
||||||
|
color="warning"
|
||||||
|
onChange={handleInputChange}
|
||||||
|
required
|
||||||
|
value={formData.debut}
|
||||||
|
fullWidth
|
||||||
|
type="date"
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<FaCalendarAlt />
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
className="inputAddNote"
|
||||||
|
sx={{
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
'&:hover fieldset': {
|
||||||
|
borderColor: '#ff9800' // Set the border color on hover
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'& .MuiInputBase-input::placeholder': {
|
||||||
|
fontSize: '11px' // Set the placeholder font size
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6}>
|
||||||
|
<TextField
|
||||||
|
label={'Date de fin'}
|
||||||
|
name={'fin'}
|
||||||
|
color="warning"
|
||||||
|
fullWidth
|
||||||
|
type="date"
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<FaCalendarAlt />
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
required
|
||||||
|
value={formData.fin}
|
||||||
|
className="inputAddNote"
|
||||||
|
sx={{
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
'&:hover fieldset': {
|
||||||
|
borderColor: '#ff9800' // Set the border color on hover
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'& .MuiInputBase-input::placeholder': {
|
||||||
|
fontSize: '11px' // Set the placeholder font size
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid
|
||||||
|
item
|
||||||
|
xs={12}
|
||||||
|
style={{ display: 'flex', gap: '30px', justifyContent: 'flex-end' }}
|
||||||
|
>
|
||||||
|
<Button type="submit" color="warning" variant="contained">
|
||||||
|
Enregister
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</form>
|
||||||
|
</Paper>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SingleAnneeScolaire
|
||||||
1156
src/renderer/src/components/SingleEtudiant.jsx
Normal file
1156
src/renderer/src/components/SingleEtudiant.jsx
Normal file
File diff suppressed because it is too large
Load Diff
584
src/renderer/src/components/Student.jsx
Normal file
584
src/renderer/src/components/Student.jsx
Normal file
@ -0,0 +1,584 @@
|
|||||||
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
|
import { Link, Navigate } 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, InputAdornment } from '@mui/material'
|
||||||
|
import { PiStudentFill } from 'react-icons/pi'
|
||||||
|
import { DataGrid, GridToolbar } from '@mui/x-data-grid'
|
||||||
|
import { frFR } from '@mui/x-data-grid/locales'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import { FaCertificate, FaGraduationCap, FaPlus, FaReceipt, FaToolbox } from 'react-icons/fa'
|
||||||
|
import { createTheme, ThemeProvider } from '@mui/material/styles'
|
||||||
|
import InputLabel from '@mui/material/InputLabel'
|
||||||
|
import MenuItem from '@mui/material/MenuItem'
|
||||||
|
import FormControl from '@mui/material/FormControl'
|
||||||
|
import Select from '@mui/material/Select'
|
||||||
|
import { Tooltip } from 'react-tooltip'
|
||||||
|
import { FaPenToSquare, FaFilePdf } from 'react-icons/fa6'
|
||||||
|
import { CgNotes } from 'react-icons/cg'
|
||||||
|
import { IoEyeSharp } from 'react-icons/io5'
|
||||||
|
import PDFEditor from './function/PDFEditor'
|
||||||
|
import ModalCertificate from './ModalCertificate'
|
||||||
|
import ModalStage from './ModalStage'
|
||||||
|
import ModalRecepice from './ModalRecepice'
|
||||||
|
import { processPdf } from './function/PDFEditorV2'
|
||||||
|
import { MdVerified } from 'react-icons/md'
|
||||||
|
|
||||||
|
const Student = () => {
|
||||||
|
const theme = createTheme({
|
||||||
|
components: {
|
||||||
|
MuiIconButton: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: 'gray' // Change the color of toolbar icons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MuiButton: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: '#121212' // Change the color of toolbar icons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const [status, setStatus] = useState([])
|
||||||
|
const [mention, setMention] = useState([])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hook for displaying the students
|
||||||
|
*/
|
||||||
|
const [etudiants, setEtudiants] = useState([])
|
||||||
|
const [notes, setNotes] = useState([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.etudiants.getEtudiants().then((response) => {
|
||||||
|
setEtudiants(response)
|
||||||
|
})
|
||||||
|
|
||||||
|
window.notes.getMoyenneVerify().then((response) => {
|
||||||
|
setNotes(response)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const [niveaus, setNiveau] = useState([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.niveaus.getNiveau().then((response) => {
|
||||||
|
setNiveau(response)
|
||||||
|
})
|
||||||
|
|
||||||
|
window.statuss.getStatus().then((response) => {
|
||||||
|
setStatus(response)
|
||||||
|
})
|
||||||
|
|
||||||
|
window.mention.getMention().then((response) => {
|
||||||
|
setMention(response)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const SeeNote = ({ params }) => {
|
||||||
|
const matchingNote = notes.find(
|
||||||
|
(element) =>
|
||||||
|
element.etudiant_niveau === params.row.niveau && element.etudiant_id === params.value
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ display: 'flex', gap: '10px' }}>
|
||||||
|
{matchingNote ? (
|
||||||
|
<Link
|
||||||
|
to={`/single/notes/${params.value}/${params.row.niveau}/${params.row.annee_scolaire}`}
|
||||||
|
>
|
||||||
|
<Button color="warning" variant="contained" className={`voirs${params.value}`}>
|
||||||
|
<IoEyeSharp style={{ fontSize: '20px', color: 'white' }} />
|
||||||
|
</Button>
|
||||||
|
<Tooltip anchorSelect={`.voirs${params.value}`} className="custom-tooltip" place="top">
|
||||||
|
Voir les notes
|
||||||
|
</Tooltip>
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<Link
|
||||||
|
to={`/addnotes/${params.value}/${params.row.niveau}/${params.row.mention_id}/${params.row.parcour}`}
|
||||||
|
>
|
||||||
|
<Button color="warning" variant="contained" className={`note${params.value}`}>
|
||||||
|
<CgNotes style={{ fontSize: '20px', color: 'white' }} />
|
||||||
|
</Button>
|
||||||
|
<Tooltip anchorSelect={`.note${params.value}`} className="custom-tooltip" place="top">
|
||||||
|
Ajouter un notes à cet étudiant
|
||||||
|
</Tooltip>
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function to return the date to local date string
|
||||||
|
*
|
||||||
|
* @param {string} dateString
|
||||||
|
* @returns string
|
||||||
|
*/
|
||||||
|
function formatDate(dateString) {
|
||||||
|
// Convert the string to a Date object
|
||||||
|
const dateObject = new Date(dateString)
|
||||||
|
|
||||||
|
// Format the date using toLocaleDateString
|
||||||
|
const formattedDate = dateObject.toLocaleDateString('fr-FR', {
|
||||||
|
day: '2-digit',
|
||||||
|
month: 'long',
|
||||||
|
year: 'numeric'
|
||||||
|
})
|
||||||
|
|
||||||
|
return formattedDate
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* data column, header of the grid
|
||||||
|
*/
|
||||||
|
const columns = [
|
||||||
|
{ field: 'nom', headerName: 'Nom', width: 180 },
|
||||||
|
{ field: 'prenom', headerName: 'Prenom', width: 180 },
|
||||||
|
{ field: 'sexe', headerName: 'Sexe', width: 80 },
|
||||||
|
{ field: 'cin', headerName: 'CIN', width: 180 },
|
||||||
|
{ field: 'date_deli', headerName: 'Date de delivrance', width: 80 },
|
||||||
|
{ field: 'nation', headerName: 'Natoinalité', width: 120 },
|
||||||
|
{ field: 'annee_bacc', headerName: 'Année du Baccalauréat', width: 80 },
|
||||||
|
{ field: 'serie', headerName: 'Série', width: 80 },
|
||||||
|
{ field: 'bourse', headerName: 'Boursier', width: 80 },
|
||||||
|
{ field: 'domaine', headerName: 'Domaine', width: 180 },
|
||||||
|
{ field: 'contact', headerName: 'Contact', width: 180 },
|
||||||
|
{ field: 'niveau', headerName: 'Niveau', width: 80 },
|
||||||
|
{ field: 'date_naissance', headerName: 'Date de naissance', width: 130 },
|
||||||
|
{ field: 'annee_scolaire', headerName: 'Année univarsitaire', width: 130 },
|
||||||
|
{ field: 'status', headerName: 'Status', width: 140 },
|
||||||
|
{ field: 'num_inscription', headerName: "Numéro d'inscription", width: 160 },
|
||||||
|
{ field: 'parcour', headerName: 'Parcours', width: 150 },
|
||||||
|
{
|
||||||
|
field: 'photos',
|
||||||
|
headerName: 'Image',
|
||||||
|
width: 100,
|
||||||
|
renderCell: (params) => (
|
||||||
|
<img
|
||||||
|
src={params.value} // Correct the access to the image source
|
||||||
|
alt={'image pdp'}
|
||||||
|
style={{ width: 50, height: 50, borderRadius: '50%', objectFit: 'cover' }}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'action',
|
||||||
|
headerName: 'Action',
|
||||||
|
width: 300,
|
||||||
|
renderCell: (params) => (
|
||||||
|
<div style={{ display: 'flex', gap: '10px' }}>
|
||||||
|
<Link to={`/single/${params.value}`}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<FaPenToSquare
|
||||||
|
style={{ fontSize: '20px', color: 'white' }}
|
||||||
|
className={`update${params.value}`}
|
||||||
|
/>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.update${params.value}`}
|
||||||
|
className="custom-tooltip"
|
||||||
|
place="top"
|
||||||
|
>
|
||||||
|
Modifier
|
||||||
|
</Tooltip>
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
<Link to={`/tranche/${params.value}`} className={`verif${params.value}`}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<MdVerified style={{ fontSize: '20px', color: 'white' }} />
|
||||||
|
</Button>
|
||||||
|
<Tooltip anchorSelect={`.verif${params.value}`} className="custom-tooltip" place="top">
|
||||||
|
Verification Frais de Formation
|
||||||
|
</Tooltip>
|
||||||
|
</Link>
|
||||||
|
<Link onClick={() => Print(params.value)}>
|
||||||
|
<Button color="warning" variant="contained" className={`export${params.value}`}>
|
||||||
|
<FaFilePdf style={{ fontSize: '20px', color: 'white' }} />
|
||||||
|
</Button>
|
||||||
|
<Tooltip anchorSelect={`.export${params.value}`} className="custom-tooltip" place="top">
|
||||||
|
Exporter carte d'etudiants
|
||||||
|
</Tooltip>
|
||||||
|
</Link>
|
||||||
|
<Link className={`voir${params.value}`}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<FaPlus style={{ fontSize: '20px', color: 'white' }} />
|
||||||
|
</Button>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.voir${params.value}`}
|
||||||
|
style={{
|
||||||
|
fontSize: '12px',
|
||||||
|
overflow: 'visible',
|
||||||
|
zIndex: 999222,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: '10px',
|
||||||
|
marginTop: "15px"
|
||||||
|
}}
|
||||||
|
place="left-end"
|
||||||
|
clickable
|
||||||
|
>
|
||||||
|
{/* Groupe 1 : Certificat */}
|
||||||
|
<Link style={{ display: 'flex', gap: '10px' }}>
|
||||||
|
<SeeNote params={params} />
|
||||||
|
<Link>
|
||||||
|
<Button
|
||||||
|
onClick={() => handleOpen(params.value)}
|
||||||
|
color="warning"
|
||||||
|
variant="contained"
|
||||||
|
className={`receip${params.value}`}
|
||||||
|
>
|
||||||
|
<FaCertificate style={{ fontSize: '20px', color: 'white' }} />
|
||||||
|
</Button>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.receip${params.value}`}
|
||||||
|
className="custom-tooltip"
|
||||||
|
place="top"
|
||||||
|
>
|
||||||
|
Télecharger le Certificat de scolariter
|
||||||
|
</Tooltip>
|
||||||
|
</Link>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Groupe 2 : Stage (affiché seulement pour L2) */}
|
||||||
|
<Link style={{ display: 'flex', gap: '10px' }}>
|
||||||
|
{params.row.niveau !== 'L1' && (
|
||||||
|
<Link>
|
||||||
|
<Button
|
||||||
|
onClick={() => handleOpen2()}
|
||||||
|
color="warning"
|
||||||
|
variant="contained"
|
||||||
|
className={`stage${params.value}`}
|
||||||
|
>
|
||||||
|
<FaToolbox style={{ fontSize: '20px', color: 'white' }} />
|
||||||
|
</Button>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.stage${params.value}`}
|
||||||
|
className="custom-tooltip"
|
||||||
|
place="top"
|
||||||
|
>
|
||||||
|
Télecharger l'autorisation de stage
|
||||||
|
</Tooltip>
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
<Link>
|
||||||
|
<Button
|
||||||
|
onClick={() => handleOpen3(params.value)}
|
||||||
|
color="warning"
|
||||||
|
variant="contained"
|
||||||
|
className={`recepice${params.value}`}
|
||||||
|
>
|
||||||
|
<FaReceipt style={{ fontSize: '20px', color: 'white' }} />
|
||||||
|
</Button>
|
||||||
|
<Tooltip
|
||||||
|
anchorSelect={`.recepice${params.value}`}
|
||||||
|
className="custom-tooltip"
|
||||||
|
place="top"
|
||||||
|
>
|
||||||
|
Télecharger le recepissé d'inscription
|
||||||
|
</Tooltip>
|
||||||
|
</Link>
|
||||||
|
</Link>
|
||||||
|
</Tooltip>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const Print = async (id) => {
|
||||||
|
console.log(id)
|
||||||
|
let etudiant = await window.etudiants.getSingle({ id })
|
||||||
|
|
||||||
|
if (etudiant) {
|
||||||
|
let data = {
|
||||||
|
f1: `${etudiant.nom} ${etudiant.prenom}`,
|
||||||
|
f2: `Naissances: ${dayjs(etudiant.date_de_naissances).format('DD-MM-YYYY')}`,
|
||||||
|
f3: `Niveau: ${etudiant.niveau}`,
|
||||||
|
f4: `Année: ${etudiant.annee_scolaire}`,
|
||||||
|
f5: `Inscription: ${etudiant.num_inscription}`,
|
||||||
|
f8: etudiant.photos
|
||||||
|
}
|
||||||
|
processPdf(data)
|
||||||
|
// PDFEditor(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ PAGINATION CORRIGÉE - États pour la pagination complète
|
||||||
|
const [paginationModel, setPaginationModel] = useState({
|
||||||
|
page: 0,
|
||||||
|
pageSize: 20
|
||||||
|
})
|
||||||
|
const [pageSizeOptions, setPageSizeOptions] = useState([20, 40, 60])
|
||||||
|
|
||||||
|
// ✅ Gestionnaire complet pour les changements de pagination (page ET pageSize)
|
||||||
|
const handlePaginationModelChange = (newModel) => {
|
||||||
|
console.log('📊 Pagination changed:', newModel) // Pour debug
|
||||||
|
|
||||||
|
setPaginationModel(newModel)
|
||||||
|
|
||||||
|
// Si l'utilisateur choisit la plus grande option, ajouter +20
|
||||||
|
const maxOption = Math.max(...pageSizeOptions)
|
||||||
|
if (newModel.pageSize === maxOption) {
|
||||||
|
setPageSizeOptions((prev) => [...prev, maxOption + 20])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that the array is flat (not wrapped in another array)
|
||||||
|
const dataRow = etudiants.map((etudiant) => ({
|
||||||
|
id: etudiant.id, // Ensure this exists and is unique for each etudiant
|
||||||
|
nom: etudiant.nom,
|
||||||
|
prenom: etudiant.prenom,
|
||||||
|
niveau: etudiant.niveau,
|
||||||
|
date_naissance: dayjs(etudiant.date_de_naissances).format('DD-MM-YYYY'),
|
||||||
|
annee_scolaire: etudiant.annee_scolaire,
|
||||||
|
status: comparestatut(etudiant.status),
|
||||||
|
num_inscription: etudiant.num_inscription,
|
||||||
|
parcour: etudiant.parcours == null ? 'Pas de parcours' : etudiant.parcours,
|
||||||
|
photos: etudiant.photos,
|
||||||
|
sexe: etudiant.sexe,
|
||||||
|
cin: etudiant.cin,
|
||||||
|
date_deli: dayjs(etudiant.date_delivrance).format('DD-MM-YYYY'),
|
||||||
|
nation: etudiant.nationalite,
|
||||||
|
annee_bacc: etudiant.annee_bacc,
|
||||||
|
serie: etudiant.serie,
|
||||||
|
bourse: etudiant.boursier,
|
||||||
|
domaine: etudiant.domaine,
|
||||||
|
contact: etudiant.contact,
|
||||||
|
mention_id: etudiant.mention_id,
|
||||||
|
action: etudiant.id // Ensure this is a valid URL for the image
|
||||||
|
}))
|
||||||
|
|
||||||
|
function comparestatut(statutID) {
|
||||||
|
let statusText
|
||||||
|
|
||||||
|
status.map((statu) => {
|
||||||
|
if (statutID == statu.id) {
|
||||||
|
statusText = statu.nom
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return statusText
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ✅ 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 }))
|
||||||
|
} else {
|
||||||
|
window.etudiants.getEtudiants().then((response) => {
|
||||||
|
setEtudiants(response)
|
||||||
|
// Reset vers la première page
|
||||||
|
setPaginationModel(prev => ({ ...prev, page: 0 }))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const [openModal, setOpenModal] = useState(false)
|
||||||
|
const [openModal2, setOpenModal2] = useState(false)
|
||||||
|
const [openModal3, setOpenModal3] = useState(false)
|
||||||
|
const [json, setJson] = useState()
|
||||||
|
const [json2, setJson2] = useState()
|
||||||
|
const [nom, setNom] = useState([])
|
||||||
|
const [nom2, setNom2] = useState([])
|
||||||
|
|
||||||
|
const handleOpen = (id) => {
|
||||||
|
window.etudiants.getSingle({ id }).then((response) => {
|
||||||
|
setNom(response)
|
||||||
|
})
|
||||||
|
setOpenModal(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOpen3 = (id) => {
|
||||||
|
window.etudiants.getSingle({ id }).then((response) => {
|
||||||
|
setNom2(response)
|
||||||
|
})
|
||||||
|
setOpenModal3(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOpen2 = () => {
|
||||||
|
setOpenModal2(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareMention(mentionID) {
|
||||||
|
let statusText
|
||||||
|
|
||||||
|
mention.map((statu) => {
|
||||||
|
if (mentionID == statu.id) {
|
||||||
|
statusText = statu.nom
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return statusText ? statusText.charAt(0).toUpperCase() + statusText.slice(1) : statusText
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setJson({
|
||||||
|
nomPrenom: nom.nom + ' ' + nom.prenom,
|
||||||
|
naissances: nom.date_de_naissances,
|
||||||
|
mention: compareMention(nom.mention_id),
|
||||||
|
niveau: nom.niveau,
|
||||||
|
annee: nom.annee_scolaire,
|
||||||
|
inscri: nom.num_inscription
|
||||||
|
})
|
||||||
|
}, [nom])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setJson2({
|
||||||
|
nomPrenom: nom.nom + ' ' + nom.prenom,
|
||||||
|
mention: compareMention(nom.mention_id),
|
||||||
|
niveau: nom.niveau,
|
||||||
|
annee: nom.annee_scolaire,
|
||||||
|
inscri: nom.num_inscription
|
||||||
|
})
|
||||||
|
}, [nom2])
|
||||||
|
|
||||||
|
const handleClose = () => setOpenModal(false)
|
||||||
|
const handleClose2 = () => setOpenModal2(false)
|
||||||
|
const handleClose3 = () => setOpenModal3(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classe.mainHome}>
|
||||||
|
<style>
|
||||||
|
{`
|
||||||
|
.custom-tooltip {
|
||||||
|
font-size: 15px;
|
||||||
|
border: solid 1px white !important;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
</style>
|
||||||
|
<div className={classeHome.header}>
|
||||||
|
<div className={classe.h1style}>
|
||||||
|
<div className={classeHome.blockTitle}>
|
||||||
|
<h1>Etudiants</h1>
|
||||||
|
<Link to={'/addstudent'}>
|
||||||
|
<Button color="warning" variant="contained">
|
||||||
|
<PiStudentFill style={{ fontSize: '20px' }} /> Ajouter
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* bare des filtre */}
|
||||||
|
<div className={classeHome.container}>
|
||||||
|
{/* filtre par niveau */}
|
||||||
|
<div style={{ width: '100%', textAlign: 'right' }}>
|
||||||
|
<FormControl
|
||||||
|
sx={{
|
||||||
|
m: 1,
|
||||||
|
width: '30%',
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
'&:hover fieldset': {
|
||||||
|
borderColor: '#ff9800' // Set the border color on hover
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
size="small"
|
||||||
|
variant="outlined"
|
||||||
|
>
|
||||||
|
<InputLabel
|
||||||
|
id="demo-select-small-label"
|
||||||
|
sx={{ color: 'black', fontSize: '18px' }}
|
||||||
|
color="warning"
|
||||||
|
>
|
||||||
|
Niveau
|
||||||
|
</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId="demo-select-small-label"
|
||||||
|
id="demo-select-small"
|
||||||
|
label="Niveau"
|
||||||
|
color="warning"
|
||||||
|
name="niveau"
|
||||||
|
defaultValue={''}
|
||||||
|
onChange={FilterData}
|
||||||
|
startAdornment={
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<FaGraduationCap />
|
||||||
|
</InputAdornment>
|
||||||
|
}
|
||||||
|
sx={{
|
||||||
|
background: 'white',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center', // Align icon and text vertically
|
||||||
|
'& .MuiSelect-icon': {
|
||||||
|
marginLeft: 'auto' // Keep the dropdown arrow to the right
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MenuItem value="">
|
||||||
|
<em>Tous les étudiants</em>
|
||||||
|
</MenuItem>
|
||||||
|
{niveaus.map((niveau) => (
|
||||||
|
<MenuItem value={niveau.nom} key={niveau.id}>
|
||||||
|
{niveau.nom}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* display the data-grid students */}
|
||||||
|
<div className={classeHome.boxEtudiantsCard}>
|
||||||
|
<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
|
||||||
|
display: 'flex'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column', // Stacks content vertically on smaller screens,
|
||||||
|
width: '100%'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DataGrid
|
||||||
|
rows={dataRow}
|
||||||
|
columns={columns}
|
||||||
|
pageSizeOptions={pageSizeOptions}
|
||||||
|
paginationModel={paginationModel} // ✅ Utilise l'état complet
|
||||||
|
onPaginationModelChange={handlePaginationModelChange} // ✅ Gère page ET pageSize
|
||||||
|
sx={{
|
||||||
|
border: 0,
|
||||||
|
width: 'auto', // Ensures the DataGrid takes full width
|
||||||
|
height: '50%', // Ensures it grows to fit content
|
||||||
|
minHeight: 400, // Minimum height for the DataGrid
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
'@media (max-width: 600px)': {
|
||||||
|
width: '100%', // 100% width on small screens
|
||||||
|
height: 'auto' // Allow height to grow with content
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
slots={{ toolbar: GridToolbar }}
|
||||||
|
localeText={frFR.components.MuiDataGrid.defaultProps.localeText}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ThemeProvider>
|
||||||
|
</Paper>
|
||||||
|
<ModalCertificate open={openModal} onClose={handleClose} json={json} />
|
||||||
|
<ModalStage open={openModal2} onClose={handleClose2} />
|
||||||
|
<ModalRecepice open={openModal3} onClose={handleClose3} json={json2} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Student
|
||||||
458
src/renderer/src/components/TesteDatagrid.jsx
Normal file
458
src/renderer/src/components/TesteDatagrid.jsx
Normal file
@ -0,0 +1,458 @@
|
|||||||
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
|
import classe from '../assets/AllStyleComponents.module.css'
|
||||||
|
import classeHome from '../assets/Home.module.css'
|
||||||
|
import Paper from '@mui/material/Paper'
|
||||||
|
import entete from '../assets/enteterelever.png'
|
||||||
|
import jsPDF from 'jspdf'
|
||||||
|
import html2Canvas from 'html2canvas'
|
||||||
|
|
||||||
|
const TesteDatagrid = ({ id, niveau, annee_scolaire, nomPrenom, inscription, refs }) => {
|
||||||
|
const [print, setPrint] = useState(refs)
|
||||||
|
const paperRef = useRef()
|
||||||
|
|
||||||
|
const [teste, setTeste] = useState([])
|
||||||
|
useEffect(() => {
|
||||||
|
window.notes.noteMatiere({ id, niveau, annee_scolaire }).then((response) => {
|
||||||
|
setTeste(response)
|
||||||
|
})
|
||||||
|
}, [id, niveau, annee_scolaire])
|
||||||
|
|
||||||
|
console.log(teste)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (refs) {
|
||||||
|
let certificat = paperRef.current
|
||||||
|
html2Canvas(certificat, { scale: 3 }).then((canvas) => {
|
||||||
|
const URLimg = canvas.toDataURL()
|
||||||
|
const doc = new jsPDF('portrait', 'mm', 'a4')
|
||||||
|
const width = doc.internal.pageSize.getWidth()
|
||||||
|
const height = doc.internal.pageSize.getHeight()
|
||||||
|
doc.addImage(URLimg, 'PNG', 0, 0, width, height)
|
||||||
|
doc.save(`releve_${nomPrenom}.pdf`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [refs])
|
||||||
|
|
||||||
|
// Step 1: Group by semestre
|
||||||
|
const groupedBySemestre = teste.reduce((acc, item) => {
|
||||||
|
const { semestre, unite_enseignement } = item
|
||||||
|
|
||||||
|
// Ensure a group exists for this `semestre`
|
||||||
|
if (!acc[semestre]) {
|
||||||
|
acc[semestre] = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Further group by unite_enseignement
|
||||||
|
if (!acc[semestre][unite_enseignement]) {
|
||||||
|
acc[semestre][unite_enseignement] = []
|
||||||
|
}
|
||||||
|
|
||||||
|
acc[semestre][unite_enseignement].push(item) // Add the item to the appropriate group
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
console.log(groupedBySemestre)
|
||||||
|
|
||||||
|
// Initialize semestre1 and semestre2
|
||||||
|
let semestre1 = {}
|
||||||
|
let semestre2 = {}
|
||||||
|
|
||||||
|
// Separate groupedBySemestre into semestre1 and semestre2 dynamically
|
||||||
|
Object.keys(groupedBySemestre).forEach((semestre) => {
|
||||||
|
// Check if the semester is odd or even
|
||||||
|
if (parseInt(semestre.replace('S', '')) % 2 !== 0) {
|
||||||
|
// Odd semesters (S1, S3, S5, ...)
|
||||||
|
semestre1[semestre] = groupedBySemestre[semestre]
|
||||||
|
} else {
|
||||||
|
// Even semesters (S2, S4, S6, ...)
|
||||||
|
semestre2[semestre] = groupedBySemestre[semestre]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Function to count the total elements in the groupedData
|
||||||
|
function countTotalElements(data) {
|
||||||
|
let totalCount = 0
|
||||||
|
|
||||||
|
// Iterate through each key in the object
|
||||||
|
Object.keys(data).forEach((key) => {
|
||||||
|
// Add the length of the array at the current key to totalCount
|
||||||
|
totalCount += data[key].length
|
||||||
|
})
|
||||||
|
|
||||||
|
return totalCount
|
||||||
|
}
|
||||||
|
|
||||||
|
function crontCredit() {
|
||||||
|
let total = 0
|
||||||
|
let credit = document.querySelectorAll('.classCredit')
|
||||||
|
for (let index = 0; index < credit.length; index++) {
|
||||||
|
total += Number(credit[index].textContent)
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
function countMoyenneGeneral() {
|
||||||
|
let total = 0
|
||||||
|
let moyenne = document.querySelectorAll('.classMoyenne')
|
||||||
|
for (let index = 0; index < moyenne.length; index++) {
|
||||||
|
total += Number(moyenne[index].textContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (total / moyenne.length).toFixed(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine both semesters into one object to handle them together
|
||||||
|
const combinedSemesters = { ...semestre1, ...semestre2 }
|
||||||
|
|
||||||
|
// Function to generate the rows
|
||||||
|
const generateTableRows = (semesters) => {
|
||||||
|
const rows = []
|
||||||
|
|
||||||
|
// Iterate over each semester's keys (S1, S2, etc.)
|
||||||
|
Object.keys(semesters).forEach((semestreKey) => {
|
||||||
|
const units = semesters[semestreKey]
|
||||||
|
|
||||||
|
// Iterate over each unite_enseignement
|
||||||
|
Object.keys(units).forEach((unitKey, idx) => {
|
||||||
|
const unitArray = units[unitKey]
|
||||||
|
const isFirstRow = idx === 0 // Check if it's the first row for this unit
|
||||||
|
|
||||||
|
unitArray.forEach((item, itemIdx) => {
|
||||||
|
rows.push(
|
||||||
|
<tr key={`${semestreKey}-${unitKey}-${item.id}`}>
|
||||||
|
{isFirstRow && itemIdx === 0 ? (
|
||||||
|
<td
|
||||||
|
rowSpan={countTotalElements(units)}
|
||||||
|
key={`${semestreKey}-semestre`}
|
||||||
|
style={{ borderBottom: 'solid 1px black', borderRight: 'solid 1px black' }}
|
||||||
|
>
|
||||||
|
<b>{semestreKey}</b>
|
||||||
|
</td>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{itemIdx === 0 ? (
|
||||||
|
<td
|
||||||
|
rowSpan={unitArray.length}
|
||||||
|
key={`${unitKey}-unit`}
|
||||||
|
style={{
|
||||||
|
borderBottom: 'solid 1px black',
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
fontSize: 12,
|
||||||
|
borderRight: 'solid 1px black'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<b>{unitKey}</b>
|
||||||
|
</td>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<td
|
||||||
|
style={{
|
||||||
|
borderBottom: 'solid 1px black',
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
fontSize: 12,
|
||||||
|
borderRight: 'solid 1px black'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.nom}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
style={{
|
||||||
|
borderBottom: 'solid 1px black',
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
fontSize: 12,
|
||||||
|
borderRight: 'solid 1px black'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{' '}
|
||||||
|
<span className="classCredit">{item.credit}</span>
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
style={{
|
||||||
|
borderBottom: 'solid 1px black',
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
fontSize: 12,
|
||||||
|
borderRight: 'solid 1px black'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.note}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
{/* Ensure this <td> renders only once for the unitArray */}
|
||||||
|
{itemIdx === 0 ? (
|
||||||
|
<td
|
||||||
|
rowSpan={unitArray.length}
|
||||||
|
style={{ borderBottom: 'solid 1px black', margin: 0, padding: 0, fontSize: 12 }}
|
||||||
|
>
|
||||||
|
<span className="classMoyenne">
|
||||||
|
{(
|
||||||
|
unitArray.reduce((sum, item) => sum + item.credit * item.note, 0) /
|
||||||
|
unitArray.reduce((sum, item) => sum + item.credit, 0)
|
||||||
|
).toFixed(2)}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
) : null}
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classe.mainHome}>
|
||||||
|
<div className={classeHome.boxEtudiantsCard}>
|
||||||
|
<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
|
||||||
|
display: 'flex',
|
||||||
|
padding: '1%'
|
||||||
|
}}
|
||||||
|
ref={paperRef}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<img src={entete} alt="image en tete" style={{ border: 'solid 1px gray' }} />
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
flexDirection: 'column',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
border: 'solid 1px gray',
|
||||||
|
margin: '1%',
|
||||||
|
width: '70%',
|
||||||
|
fontSize: '13px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>ECOLE SUPERIEURE POLYTECHNIQUE</span>
|
||||||
|
<span>REPOBLIKAN’I MADAGASIKARA</span>
|
||||||
|
<span>Fitiavana-Tanindrazana-Fandrosoana</span>
|
||||||
|
<span>*********************</span>
|
||||||
|
<h2>RELEVÉE DE NOTE</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{ fontSize: '13px', margin: '1%' }}>
|
||||||
|
<span>Nom & Prenoms: </span>
|
||||||
|
<span>{nomPrenom}</span>
|
||||||
|
<br />
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||||
|
<span>Année scolaire: </span>
|
||||||
|
<span>{annee_scolaire}</span>
|
||||||
|
<span>Niveau: </span>
|
||||||
|
<span>{niveau}</span>
|
||||||
|
<span>inscription: </span>
|
||||||
|
<span>{inscription}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table
|
||||||
|
style={{
|
||||||
|
border: 'solid 1px black',
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
fontSize: 12,
|
||||||
|
width: '100%'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th
|
||||||
|
style={{
|
||||||
|
borderBottom: 'solid 1px black',
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
fontSize: 12,
|
||||||
|
borderRight: 'solid 1px black'
|
||||||
|
}}
|
||||||
|
></th>
|
||||||
|
<th
|
||||||
|
style={{
|
||||||
|
borderBottom: 'solid 1px black',
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
fontSize: 12,
|
||||||
|
borderRight: 'solid 1px black',
|
||||||
|
textAlign: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Unités <br /> d’Enseignement <br /> (UE)
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
style={{
|
||||||
|
borderBottom: 'solid 1px black',
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
fontSize: 12,
|
||||||
|
borderRight: 'solid 1px black',
|
||||||
|
textAlign: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Eléments constitutifs
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
style={{
|
||||||
|
borderBottom: 'solid 1px black',
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
fontSize: 12,
|
||||||
|
borderRight: 'solid 1px black',
|
||||||
|
textAlign: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Crédits
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
style={{
|
||||||
|
borderBottom: 'solid 1px black',
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
fontSize: 12,
|
||||||
|
borderRight: 'solid 1px black',
|
||||||
|
textAlign: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Note
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
style={{
|
||||||
|
borderBottom: 'solid 1px black',
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
fontSize: 12,
|
||||||
|
textAlign: 'center',
|
||||||
|
width: '250px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Moyenne
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody style={{ margin: 0, padding: 0 }}>
|
||||||
|
{generateTableRows(combinedSemesters)}
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
colSpan={3}
|
||||||
|
style={{
|
||||||
|
borderBottom: 'solid 1px black',
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
fontSize: 13,
|
||||||
|
borderRight: 'solid 1px black',
|
||||||
|
textAlign: 'right',
|
||||||
|
paddingRight: '3px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{' '}
|
||||||
|
<b>Total crédit:</b>
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
style={{
|
||||||
|
borderBottom: 'solid 1px black',
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
fontSize: 13,
|
||||||
|
textAlignLast: 'left',
|
||||||
|
paddingLeft: '20px',
|
||||||
|
borderRight: 'solid 1px black'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<b>{crontCredit()}</b>
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
style={{
|
||||||
|
borderBottom: 'solid 1px black',
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
fontSize: 13,
|
||||||
|
borderRight: 'solid 1px black'
|
||||||
|
}}
|
||||||
|
></td>
|
||||||
|
<td
|
||||||
|
style={{
|
||||||
|
borderBottom: 'solid 1px black',
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
fontSize: 13
|
||||||
|
}}
|
||||||
|
></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
colSpan={5}
|
||||||
|
style={{
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
fontSize: 13,
|
||||||
|
borderRight: 'solid 1px black',
|
||||||
|
textAlign: 'right',
|
||||||
|
paddingRight: '3px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<b>Moyenne générale :</b>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<b>{countMoyenneGeneral()}</b>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
colSpan={5}
|
||||||
|
style={{
|
||||||
|
borderBottom: 'solid 1px black',
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
fontSize: 13,
|
||||||
|
borderRight: 'solid 1px black',
|
||||||
|
textAlign: 'right',
|
||||||
|
paddingRight: '3px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<b>Observation :</b>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
style={{
|
||||||
|
border: 'none',
|
||||||
|
outline: 'none',
|
||||||
|
width: '100%',
|
||||||
|
textAlign: 'center'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div style={{ textAlign: 'center', marginTop: '1%' }}>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'end' }}>
|
||||||
|
<span>Décision de jury :</span>
|
||||||
|
<input type="text" style={{ border: 'none', width: '300px', outline: 'none' }} />
|
||||||
|
</div>
|
||||||
|
<p>Le Directeur </p>
|
||||||
|
</div>
|
||||||
|
<p style={{ textAlign: 'right', marginTop: '5%' }}>RATSIMBAZAFY Christian Pierre</p>
|
||||||
|
</div>
|
||||||
|
</Paper>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TesteDatagrid
|
||||||
127
src/renderer/src/components/UpdateTranche.jsx
Normal file
127
src/renderer/src/components/UpdateTranche.jsx
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
TextField,
|
||||||
|
Button,
|
||||||
|
Autocomplete,
|
||||||
|
InputAdornment,
|
||||||
|
Box,
|
||||||
|
Grid
|
||||||
|
} from '@mui/material'
|
||||||
|
import { MdLabelImportantOutline } from 'react-icons/md'
|
||||||
|
|
||||||
|
const UpdateTranche = ({ open, onClose, onSubmitSuccess, id }) => {
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
id: id,
|
||||||
|
tranchename: '',
|
||||||
|
montant: ''
|
||||||
|
})
|
||||||
|
const [tranche, setTranche] = useState([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (id !== null) {
|
||||||
|
window.etudiants.getSingleTranche({ id }).then((response) => {
|
||||||
|
setTranche(response)
|
||||||
|
})
|
||||||
|
setFormData({
|
||||||
|
id: id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [id])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setFormData((prev) => ({
|
||||||
|
...prev,
|
||||||
|
tranchename: tranche.tranchename || '',
|
||||||
|
montant: tranche.montant || ''
|
||||||
|
}))
|
||||||
|
}, [tranche])
|
||||||
|
|
||||||
|
const handleChange = (e) => {
|
||||||
|
const { name, value } = e.target
|
||||||
|
setFormData({ ...formData, [name]: value })
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
let response = await window.etudiants.updateTranche(formData)
|
||||||
|
|
||||||
|
if (response.changes) {
|
||||||
|
onClose()
|
||||||
|
onSubmitSuccess(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open} onClose={onClose}>
|
||||||
|
<form action="" onSubmit={handleSubmit}>
|
||||||
|
<DialogTitle>Ajout tranche</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<Box sx={{ flexGrow: 1 }}>
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid item xs={12} sm={6}>
|
||||||
|
<TextField
|
||||||
|
autoFocus
|
||||||
|
margin="normal"
|
||||||
|
required
|
||||||
|
name="tranchename"
|
||||||
|
label="Désignation"
|
||||||
|
type="text"
|
||||||
|
fullWidth
|
||||||
|
placeholder="Tranche 1"
|
||||||
|
variant="outlined"
|
||||||
|
value={formData.tranchename}
|
||||||
|
color="warning"
|
||||||
|
onChange={handleChange}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<MdLabelImportantOutline />
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6}>
|
||||||
|
<TextField
|
||||||
|
autoFocus
|
||||||
|
margin="normal"
|
||||||
|
required
|
||||||
|
name="montant"
|
||||||
|
label="Montant"
|
||||||
|
type="number"
|
||||||
|
fullWidth
|
||||||
|
placeholder="Montant"
|
||||||
|
variant="outlined"
|
||||||
|
value={formData.montant}
|
||||||
|
color="warning"
|
||||||
|
onChange={handleChange}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<MdLabelImportantOutline />
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={onClose} color="error">
|
||||||
|
Annuler
|
||||||
|
</Button>
|
||||||
|
<Button type="submit" color="warning">
|
||||||
|
Soumettre
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</form>
|
||||||
|
</Dialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UpdateTranche
|
||||||
94
src/renderer/src/components/function/GenerateFiche.js
Normal file
94
src/renderer/src/components/function/GenerateFiche.js
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import { PDFDocument, rgb, StandardFonts } from 'pdf-lib'
|
||||||
|
|
||||||
|
export const generatePDF = async (students) => {
|
||||||
|
// Sort by NomPrenom alphabetically
|
||||||
|
const sortedStudents = students.sort((a, b) => a.nom.localeCompare(b.nom))
|
||||||
|
|
||||||
|
// function compareMention(id) {
|
||||||
|
// let mentionText;
|
||||||
|
// mentions.map((ment) => {
|
||||||
|
// if (id == ment.id) {
|
||||||
|
// mentionText = ment.nom
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
|
// return mentionText;
|
||||||
|
// }
|
||||||
|
const pdfDoc = await PDFDocument.create()
|
||||||
|
const pageWidth = 595 // A4 width in points
|
||||||
|
const pageHeight = 842 // A4 height in points
|
||||||
|
const margin = 40
|
||||||
|
const fontSize = 12
|
||||||
|
const rowHeight = 25
|
||||||
|
const tableStartY = pageHeight - margin - 50
|
||||||
|
const maxRowsPerPage = Math.floor((tableStartY - margin) / rowHeight)
|
||||||
|
|
||||||
|
const font = await pdfDoc.embedFont(StandardFonts.Helvetica)
|
||||||
|
const page = pdfDoc.addPage([pageWidth, pageHeight])
|
||||||
|
|
||||||
|
let y = tableStartY
|
||||||
|
let rowCount = 0
|
||||||
|
|
||||||
|
// Add Table Headers
|
||||||
|
page.drawText('Nom matieres', {
|
||||||
|
x: pageWidth / 2 - 50,
|
||||||
|
y,
|
||||||
|
size: 16,
|
||||||
|
font,
|
||||||
|
color: rgb(0, 0, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
y -= 30
|
||||||
|
|
||||||
|
const headers = ['N°', 'Nom et Prenom', 'Mention', 'Émergement']
|
||||||
|
const columnWidths = [50, 200, 100, 100]
|
||||||
|
const xPositions = [
|
||||||
|
margin,
|
||||||
|
margin + columnWidths[0],
|
||||||
|
margin + columnWidths[0] + columnWidths[1],
|
||||||
|
margin + columnWidths[0] + columnWidths[1] + columnWidths[2]
|
||||||
|
]
|
||||||
|
|
||||||
|
headers.forEach((header, index) => {
|
||||||
|
page.drawText(header, { x: xPositions[index], y, size: fontSize, font, color: rgb(0, 0, 0) })
|
||||||
|
})
|
||||||
|
|
||||||
|
y -= rowHeight
|
||||||
|
|
||||||
|
// Function to add a new page when needed
|
||||||
|
const addNewPage = () => {
|
||||||
|
const newPage = pdfDoc.addPage([pageWidth, pageHeight])
|
||||||
|
y = tableStartY
|
||||||
|
rowCount = 0
|
||||||
|
return newPage
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through student data and populate the table
|
||||||
|
sortedStudents.forEach((student, index) => {
|
||||||
|
if (rowCount >= maxRowsPerPage) {
|
||||||
|
page = addNewPage()
|
||||||
|
}
|
||||||
|
|
||||||
|
const rowData = [
|
||||||
|
(index + 1).toString(),
|
||||||
|
`${student.nom} ${student.prenom}`,
|
||||||
|
student.mention,
|
||||||
|
''
|
||||||
|
]
|
||||||
|
|
||||||
|
rowData.forEach((text, i) => {
|
||||||
|
page.drawText(text, { x: xPositions[i], y, size: fontSize, font, color: rgb(0, 0, 0) })
|
||||||
|
})
|
||||||
|
|
||||||
|
y -= rowHeight
|
||||||
|
rowCount++
|
||||||
|
})
|
||||||
|
|
||||||
|
// Save and download PDF
|
||||||
|
const pdfBytes = await pdfDoc.save()
|
||||||
|
const blob = new Blob([pdfBytes], { type: 'application/pdf' })
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = URL.createObjectURL(blob)
|
||||||
|
link.download = 'student_list.pdf'
|
||||||
|
link.click()
|
||||||
|
}
|
||||||
134
src/renderer/src/components/function/PDFEditor.js
Normal file
134
src/renderer/src/components/function/PDFEditor.js
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
import { PDFDocument } from 'pdf-lib'
|
||||||
|
import { saveAs } from 'file-saver'
|
||||||
|
import pdf from '../../assets/carte_etudiant.pdf'
|
||||||
|
import pdf2 from '../../assets/arriere.pdf'
|
||||||
|
import pdf3 from '../../assets/business_card_template_001_form.pdf'
|
||||||
|
import QRCode from 'qrcode'
|
||||||
|
|
||||||
|
const PDFEditor = async (data) => {
|
||||||
|
// Load the existing PDF files
|
||||||
|
const existingPdfBytes = await fetch(pdf).then((res) => res.arrayBuffer())
|
||||||
|
const existingPdfBytes2 = await fetch(pdf2).then((res) => res.arrayBuffer())
|
||||||
|
const existingPdfBytes3 = await fetch(pdf3).then((res) => res.arrayBuffer())
|
||||||
|
|
||||||
|
// Load the PDFs
|
||||||
|
const pdfDoc = await PDFDocument.load(existingPdfBytes)
|
||||||
|
const pdfDoc2 = await PDFDocument.load(existingPdfBytes2)
|
||||||
|
const pdfDoc3 = await PDFDocument.load(existingPdfBytes3)
|
||||||
|
|
||||||
|
// Get the form from the first PDF (front)
|
||||||
|
const form = pdfDoc.getForm()
|
||||||
|
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('num_inscription').setText("Numéro d'inscription: " + data.f5)
|
||||||
|
form.flatten()
|
||||||
|
|
||||||
|
// ----------------------------------------- carte frontale ----------------------------------------------------
|
||||||
|
const canvas = document.createElement('canvas')
|
||||||
|
const context = canvas.getContext('2d')
|
||||||
|
const diameter = 90
|
||||||
|
const resolutionScale = 4
|
||||||
|
canvas.width = diameter * resolutionScale
|
||||||
|
canvas.height = diameter * resolutionScale
|
||||||
|
|
||||||
|
const base64Data = data.f8.split(',')[1]
|
||||||
|
const img = new Image()
|
||||||
|
img.src = `data:image/png;base64,${base64Data}`
|
||||||
|
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
img.onload = resolve
|
||||||
|
})
|
||||||
|
|
||||||
|
context.scale(resolutionScale, resolutionScale)
|
||||||
|
context.beginPath()
|
||||||
|
context.arc(diameter / 2, diameter / 2, diameter / 2, 0, Math.PI * 2)
|
||||||
|
context.closePath()
|
||||||
|
context.clip()
|
||||||
|
context.drawImage(img, 0, 0, diameter, diameter)
|
||||||
|
|
||||||
|
const canvasImageBase64 = canvas.toDataURL('image/png')
|
||||||
|
const canvasImageBytes = Uint8Array.from(atob(canvasImageBase64.split(',')[1]), (char) =>
|
||||||
|
char.charCodeAt(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
const image = await pdfDoc.embedPng(canvasImageBytes)
|
||||||
|
const page = pdfDoc.getPage(0)
|
||||||
|
page.drawImage(image, {
|
||||||
|
x: 74 - diameter / 2,
|
||||||
|
y: 77 - diameter / 2,
|
||||||
|
width: diameter,
|
||||||
|
height: diameter
|
||||||
|
})
|
||||||
|
|
||||||
|
const form2 = pdfDoc2.getForm()
|
||||||
|
const form3 = pdfDoc3.getForm()
|
||||||
|
const field = form2.getField('f6')
|
||||||
|
if (field) {
|
||||||
|
form2.removeField(field)
|
||||||
|
form3.removeField(field)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------- carte arriere -------------------------------------------
|
||||||
|
const paperContent = `
|
||||||
|
CUniversity
|
||||||
|
Nom et prenom: ${data.f1}
|
||||||
|
Date de naissance: ${data.f2}
|
||||||
|
Niveau: ${data.f3}
|
||||||
|
Année scolaire: ${data.f4}
|
||||||
|
Numéro d'inscription: ${data.f5}
|
||||||
|
`
|
||||||
|
|
||||||
|
const qrCanvas = document.createElement('canvas')
|
||||||
|
const qrWidth = 300
|
||||||
|
QRCode.toCanvas(
|
||||||
|
qrCanvas,
|
||||||
|
paperContent,
|
||||||
|
{ errorCorrectionLevel: 'H', width: qrWidth },
|
||||||
|
(error) => {
|
||||||
|
if (error) {
|
||||||
|
console.error(error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const qrImageBase64 = qrCanvas.toDataURL('image/png')
|
||||||
|
const qrImageBytes = Uint8Array.from(atob(qrImageBase64.split(',')[1]), (char) =>
|
||||||
|
char.charCodeAt(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
;(async () => {
|
||||||
|
const page2 = pdfDoc2.getPage(0)
|
||||||
|
const qrImage = await pdfDoc2.embedPng(qrImageBytes)
|
||||||
|
|
||||||
|
const x = 7
|
||||||
|
const y = 75
|
||||||
|
const qrSize = 95
|
||||||
|
|
||||||
|
page2.drawImage(qrImage, {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width: qrSize,
|
||||||
|
height: qrSize
|
||||||
|
})
|
||||||
|
|
||||||
|
// Merge the front and back (pages) into a new document
|
||||||
|
const newPdfDoc = await PDFDocument.create()
|
||||||
|
// const [frontPage] = await newPdfDoc.copyPages(pdfDoc, [0]); // Front page
|
||||||
|
const [frontPage] = await newPdfDoc.copyPages(pdfDoc3, [0]) // Front page
|
||||||
|
const [backPage] = await newPdfDoc.copyPages(pdfDoc2, [0]) // Back page
|
||||||
|
|
||||||
|
newPdfDoc.addPage(frontPage)
|
||||||
|
newPdfDoc.addPage(backPage)
|
||||||
|
|
||||||
|
const pdfBytes = await newPdfDoc.save()
|
||||||
|
|
||||||
|
// Trigger the download of the merged PDF
|
||||||
|
const blob = new Blob([pdfBytes], { type: 'application/pdf' })
|
||||||
|
saveAs(blob, `carte_etudiant_${data.f1}.pdf`)
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PDFEditor
|
||||||
151
src/renderer/src/components/function/PDFEditorV2.js
Normal file
151
src/renderer/src/components/function/PDFEditorV2.js
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
import { PDFDocument, PDFTextField } from 'pdf-lib'
|
||||||
|
import PDF from '../../assets/business_card_template_001_form.pdf'
|
||||||
|
import PDF2 from '../../assets/business_card_template_002.pdf'
|
||||||
|
import QRCode from 'qrcode'
|
||||||
|
|
||||||
|
async function fillPdfFields(jsonData) {
|
||||||
|
const response = await fetch(PDF) // Load the PDF file
|
||||||
|
const response2 = await fetch(PDF2) // Load the second PDF file
|
||||||
|
const pdfBytes = await response.arrayBuffer()
|
||||||
|
const pdfBytes2 = await response2.arrayBuffer()
|
||||||
|
const pdfDoc = await PDFDocument.load(pdfBytes)
|
||||||
|
const pdfDoc2 = await PDFDocument.load(pdfBytes2)
|
||||||
|
const form = pdfDoc.getForm()
|
||||||
|
|
||||||
|
const fields = form
|
||||||
|
.getFields()
|
||||||
|
.filter((field) => field instanceof PDFTextField)
|
||||||
|
.map((field) => ({ name: field.getName(), field }))
|
||||||
|
|
||||||
|
const dataMapping = {
|
||||||
|
f1: jsonData.f1,
|
||||||
|
f2: jsonData.f2,
|
||||||
|
f3: jsonData.f3,
|
||||||
|
f4: jsonData.f4,
|
||||||
|
f5: jsonData.f5
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill text fields
|
||||||
|
Object.keys(dataMapping).forEach((key, index) => {
|
||||||
|
if (fields[index]) {
|
||||||
|
const { field } = fields[index]
|
||||||
|
field.setText(dataMapping[key] || '')
|
||||||
|
console.log(`Setting ${key}: ${dataMapping[key]} -> ${fields[index].name}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// ---------------------------------calculate and paste the image in pdf--------------------------------------
|
||||||
|
if (jsonData.f8) {
|
||||||
|
const diameter = 90
|
||||||
|
const resolutionScale = 4
|
||||||
|
|
||||||
|
const canvas = document.createElement('canvas')
|
||||||
|
const context = canvas.getContext('2d')
|
||||||
|
canvas.width = diameter * resolutionScale
|
||||||
|
canvas.height = diameter * resolutionScale
|
||||||
|
|
||||||
|
const base64Data = jsonData.f8.startsWith('data:image')
|
||||||
|
? jsonData.f8.split(',')[1]
|
||||||
|
: jsonData.f8 // Handle case where "data:image/png;base64," is missing
|
||||||
|
|
||||||
|
const img = new Image()
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
img.onload = resolve
|
||||||
|
img.onerror = reject
|
||||||
|
img.src = `data:image/png;base64,${base64Data}`
|
||||||
|
})
|
||||||
|
|
||||||
|
context.scale(resolutionScale, resolutionScale)
|
||||||
|
context.beginPath()
|
||||||
|
context.arc(diameter / 2, diameter / 2, diameter / 2, 0, Math.PI * 2)
|
||||||
|
context.closePath()
|
||||||
|
context.clip()
|
||||||
|
context.drawImage(img, 0, 0, diameter, diameter)
|
||||||
|
|
||||||
|
const canvasImageBase64 = canvas.toDataURL('image/png')
|
||||||
|
const image = await pdfDoc.embedPng(canvasImageBase64)
|
||||||
|
|
||||||
|
const page = pdfDoc.getPage(0)
|
||||||
|
|
||||||
|
page.drawImage(image, {
|
||||||
|
x: 186.4 - diameter / 2, // Keep the same X position
|
||||||
|
y: 90 - diameter / 2, // Keep the same Y position
|
||||||
|
width: diameter * 0.8, // Reduce size (e.g., 70% of original)
|
||||||
|
height: diameter * 0.8 // Reduce size (e.g., 70% of original)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------paste the qrCode in the pd--------------------------------------
|
||||||
|
|
||||||
|
const paperContent = `
|
||||||
|
C-University
|
||||||
|
Nom et prenom: ${jsonData.f1}
|
||||||
|
Date de naissance: ${jsonData.f2}
|
||||||
|
Niveau: ${jsonData.f3}
|
||||||
|
Année scolaire: ${jsonData.f4}
|
||||||
|
Numéro d'inscription: ${jsonData.f5}
|
||||||
|
`
|
||||||
|
|
||||||
|
const qrCanvas = document.createElement('canvas')
|
||||||
|
const qrWidth = 300
|
||||||
|
|
||||||
|
QRCode.toCanvas(
|
||||||
|
qrCanvas,
|
||||||
|
paperContent,
|
||||||
|
{ errorCorrectionLevel: 'H', width: qrWidth },
|
||||||
|
(error) => {
|
||||||
|
if (error) {
|
||||||
|
console.error(error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const qrImageBase64 = qrCanvas.toDataURL('image/png')
|
||||||
|
const qrImageBytes = Uint8Array.from(atob(qrImageBase64.split(',')[1]), (char) =>
|
||||||
|
char.charCodeAt(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
;(async () => {
|
||||||
|
const page2 = pdfDoc2.getPage(0)
|
||||||
|
const qrImage = await pdfDoc2.embedPng(qrImageBytes)
|
||||||
|
|
||||||
|
const x = 4
|
||||||
|
const y = 39
|
||||||
|
const qrSize = 92
|
||||||
|
|
||||||
|
page2.drawImage(qrImage, {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width: qrSize,
|
||||||
|
height: qrSize
|
||||||
|
})
|
||||||
|
|
||||||
|
// Merge the front and back (pages) into a new document
|
||||||
|
const newPdfDoc = await PDFDocument.create()
|
||||||
|
// const [frontPage] = await newPdfDoc.copyPages(pdfDoc, [0]); // Front page
|
||||||
|
const [frontPage] = await newPdfDoc.copyPages(pdfDoc, [0]) // Front page
|
||||||
|
const [backPage] = await newPdfDoc.copyPages(pdfDoc2, [0]) // Back page
|
||||||
|
|
||||||
|
newPdfDoc.addPage(frontPage)
|
||||||
|
newPdfDoc.addPage(backPage)
|
||||||
|
|
||||||
|
const pdfBytes = await newPdfDoc.save()
|
||||||
|
|
||||||
|
// Trigger the download of the merged PDF
|
||||||
|
const blob = new Blob([pdfBytes], { type: 'application/pdf' })
|
||||||
|
saveAs(blob, `carte_etudiant_${jsonData.f1}.pdf`)
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Serialize the PDF and return the modified document
|
||||||
|
const modifiedPdfBytes = await pdfDoc.save()
|
||||||
|
return modifiedPdfBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function who export and filled PDF data
|
||||||
|
* @param {JSON} jsonData
|
||||||
|
*/
|
||||||
|
export const processPdf = async (jsonData) => {
|
||||||
|
await fillPdfFields(jsonData)
|
||||||
|
}
|
||||||
54
src/renderer/src/test/qr.html
Normal file
54
src/renderer/src/test/qr.html
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="stylesheet" href="style.css" />
|
||||||
|
<title>Document</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="cart">
|
||||||
|
<div class="title">
|
||||||
|
<h1>université de toamasina</h1>
|
||||||
|
<p>***********</p>
|
||||||
|
<p>
|
||||||
|
ecole superieure <br />
|
||||||
|
polytechnique
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="cart-photos">
|
||||||
|
<img src="../images/fab.jpg" alt="" />
|
||||||
|
</div>
|
||||||
|
<div class="cart-info">
|
||||||
|
<p><b>Nom</b> : BE</p>
|
||||||
|
<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>Num inscription</b> : 12345678900</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cart">
|
||||||
|
<div class="qrContent">
|
||||||
|
<div class="gauche">
|
||||||
|
<h1>QR en ligne</h1>
|
||||||
|
<img
|
||||||
|
src="https://upload.wikimedia.org/wikipedia/commons/thumb/d/d0/QR_code_for_mobile_English_Wikipedia.svg/800px-QR_code_for_mobile_English_Wikipedia.svg.png"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="droite">
|
||||||
|
<h1>QR locale</h1>
|
||||||
|
<img
|
||||||
|
src="https://upload.wikimedia.org/wikipedia/commons/thumb/d/d0/QR_code_for_mobile_English_Wikipedia.svg/800px-QR_code_for_mobile_English_Wikipedia.svg.png"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
74
src/renderer/src/test/relever.html
Normal file
74
src/renderer/src/test/relever.html
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Relevé de Note</title>
|
||||||
|
<link rel="stylesheet" href="style.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="header">
|
||||||
|
<h1>REPOBLIKAN’I MADAGASIKARA</h1>
|
||||||
|
<h2>Fitiavana-Tanindrazana-Fandrosoana</h2>
|
||||||
|
<hr />
|
||||||
|
<h2>MINISTÈRE DE L’ENSEIGNEMENT SUPÉRIEUR ET DE LA RECHERCHE SCIENTIFIQUE</h2>
|
||||||
|
<h3>UNIVERSITÉ DE TOAMASINA</h3>
|
||||||
|
<h3>ECOLE SUPERIEURE POLYTECHNIQUE</h3>
|
||||||
|
<p>Fahaizaña sy Fañahy</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="releve">
|
||||||
|
<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>
|
||||||
|
</p>
|
||||||
|
<p><strong>N° inscription :</strong> F42</p>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Unités d’Enseignement (UE)</th>
|
||||||
|
<th>Eléments constitutifs</th>
|
||||||
|
<th>Crédits</th>
|
||||||
|
<th>Note</th>
|
||||||
|
<th>Moyenne</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>UEMI1</td>
|
||||||
|
<td>Algèbre</td>
|
||||||
|
<td>4</td>
|
||||||
|
<td>F6</td>
|
||||||
|
<td>F8</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>UEMI1</td>
|
||||||
|
<td>Analyse</td>
|
||||||
|
<td>5</td>
|
||||||
|
<td>F5</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>UEPI1</td>
|
||||||
|
<td>Mécanique Général I</td>
|
||||||
|
<td>4</td>
|
||||||
|
<td>F9</td>
|
||||||
|
<td>F13</td>
|
||||||
|
</tr>
|
||||||
|
<!-- Add more rows as needed following this structure -->
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><strong>Total crédit</strong></td>
|
||||||
|
<td colspan="3">30</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p><strong>Moyenne générale :</strong> F41</p>
|
||||||
|
<p><strong>Observation :</strong> F47</p>
|
||||||
|
<p><strong>Décision de jury :</strong> F46</p>
|
||||||
|
<p><strong>Le Directeur :</strong> RATSIMBAZAFY Christian Pierre</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Reference in New Issue
Block a user