diff --git a/app/static/js/assiduites.js b/app/static/js/assiduites.js
index 0d12635cfdc10b224a79b31a90256bf1c52453e3..4bcb8396072f605fbbac277c8788ff6c36bb44e9 100644
--- a/app/static/js/assiduites.js
+++ b/app/static/js/assiduites.js
@@ -168,6 +168,10 @@ function creerLigneEtudiant(etud, index) {
     date_fin: null,
   };
 
+  /**Retourne une liste d'assiduité en conflit avec la période actuelle
+   * @param {Array} assiduites - Les assiduités de l'étudiant
+   * @returns {Array} Les assiduités en conflit
+   */
   function recupConflitsAssiduites(assiduites) {
     const period = getPeriodAsDate();
 
@@ -182,9 +186,12 @@ function creerLigneEtudiant(etud, index) {
       );
     });
   }
-
+  // Pas de conflit en readonly
   const conflits = readOnly ? [] : recupConflitsAssiduites(etud.assiduites);
 
+  // Si il y a des conflits, on prend le premier pour l'afficher
+  // si les dates de début et de fin sont les mêmes, c'est une édition
+  // sinon c'est un conflit
   if (conflits.length > 0) {
     currentAssiduite = conflits[0];
 
@@ -200,6 +207,49 @@ function creerLigneEtudiant(etud, index) {
         : "conflit";
   }
 
+  // Création de la ligne étudiante en DOM
+  /* exemple de ligne étudiante
+   <div class="etud_row" id="etud_row_497">
+      <div class="index">1</div>
+      <div class="name_field"><img src="../../api/etudiant/etudid/497/photo?size=small" alt="Baudin Joseph" class="pdp"><a
+              class="name_set" href="bilan_etud?etudid=497">
+              <h4 class="nom">Baudin</h4>
+              <h5 class="prenom">Joseph</h5>
+          </a></div>
+      <div class="assiduites_bar">
+          <div id="prevDateAssi" class="vide"></div>
+          <div class="mini-timeline"><span class="mini_tick" style="left: 47.5%;">13h</span>
+              <div class="mini-timeline-block creneau" style="left: 20%; width: 17.5%;"></div>
+          </div>
+      </div>
+      <fieldset class="btns_field single" etudid="497" type="creation" assiduite_id="-1">
+        <input 
+          type="checkbox"
+          value="present"
+          name="btn_assiduites_1"
+          id="rbtn_present" 
+          class="rbtn present"
+          title="present"
+        >
+        <input 
+          type="checkbox"
+          value="retard"
+          name="btn_assiduites_1"
+          id="rbtn_retard" 
+          class="rbtn retard"
+          title="retard"
+        >
+        <input 
+          type="checkbox"
+          value="absent"
+          name="btn_assiduites_1"
+          id="rbtn_absent" 
+          class="rbtn absent"
+          title="absent"
+        >
+      </fieldset>
+  </div>
+   */
   const ligneEtud = document.createElement("div");
   ligneEtud.classList.add("etud_row");
   if (Object.keys(etudsDefDem).includes(etud.id)) {
@@ -388,6 +438,9 @@ async function creerTousLesEtudiants(etuds) {
   etudsDiv.innerHTML = "";
   const moduleImplId = readOnly ? null : $("#moduleimpl_select").val();
   const inscriptions = await getInscriptionModule(moduleImplId);
+  // on trie les étudiants par ordre alphabétique
+  // et on garde ceux qui sont inscrits au module
+  // puis pour chaque étudiant on crée une ligne
   [...etuds.values()]
     .sort((a, b) => {
       return a.sort_key > b.sort_key ? 1 : -1;
@@ -496,10 +549,9 @@ async function getInscriptionModule(moduleimpl_id) {
 
   return inscriptionsModules.get(moduleimpl_id);
 }
-
+// Mise à jour de la ligne étudiant
 async function MiseAJourLigneEtud(etud) {
   //Récupérer ses assiduités
-
   function RecupAssiduitesEtudiant(etudid) {
     const date = $("#date").datepicker("getDate");
     const date_debut = date.add(-1, "days").format("YYYY-MM-DDTHH:mm");
@@ -527,6 +579,8 @@ async function MiseAJourLigneEtud(etud) {
   }
 
   await RecupAssiduitesEtudiant(etud.id);
+  // Une fois les assiduités récupérées, on met à jour la ligne étudiant
+  // on replace l'ancienne ligne par la nouvellement générée
 
   const etudRow = document.getElementById(`etud_row_${etud.id}`);
   if (etudRow == null) return;
@@ -540,12 +594,14 @@ async function MiseAJourLigneEtud(etud) {
   etudRow.replaceWith(ligneEtud);
 }
 
+// Action appelée lors d'un clic sur un bouton d'assiduité
+// Création, édition ou suppression d'une assiduité
 async function actionAssiduite(etud, etat, type, assiduite = null) {
   const modimpl_id = $("#moduleimpl_select").val();
   if (assiduite && assiduite.etat.toLowerCase() === etat) type = "suppression";
 
   const { deb, fin } = getPeriodAsDate();
-
+  // génération d'un objet assiduité basique qui sera complété
   let assiduiteObjet = assiduite ?? {
     date_debut: deb,
     date_fin: fin,
@@ -554,7 +610,8 @@ async function actionAssiduite(etud, etat, type, assiduite = null) {
 
   assiduiteObjet.etat = etat;
   assiduiteObjet.moduleimpl_id = modimpl_id;
-
+  // En fonction du type d'action on appelle la bonne route
+  // avec les bonnes valeurs
   if (type === "creation") {
     await async_post(
       `../../api/assiduite/${etud.id}/create`,
@@ -606,7 +663,9 @@ async function actionAssiduite(etud, etat, type, assiduite = null) {
     );
   }
 }
-
+// Fonction pour afficher un message d'erreur si le module n'est pas renseigné
+// ou si l'étudiant n'est pas inscrit au module.
+// On donne le message d'erreur d'une requête api et cela affiche le message correspondant
 function erreurModuleImpl(message) {
   if (message == "Module non renseigné") {
     const HTML = `
@@ -635,7 +694,9 @@ function erreurModuleImpl(message) {
     openAlertModal("Sélection du module", content);
   }
 }
-
+// Fonction pour ajouter en lot une assiduité à tous les étudiants
+// Fonctionne uniquement pour créer ou supprimer des assiduités
+// Pas d'édition possible
 function mettreToutLeMonde(etat, el = null) {
   const lignesEtuds = [...document.querySelectorAll("fieldset.btns_field")];
 
@@ -709,7 +770,7 @@ function mettreToutLeMonde(etat, el = null) {
         }
         envoiToastTous("remove", assiduites_id.length);
         if (Object.keys(unDeleted).length == 0) return;
-
+        // CAS : des assiduités d'étudiants n'ont pas pu être supprimés
         let unDeletedEtuds = `
         <ul>
         ${Object.keys(unDeleted)
@@ -771,6 +832,7 @@ function mettreToutLeMonde(etat, el = null) {
   });
 }
 
+// Affichage d'un loader (animation jeu pong)
 function afficheLoader() {
   const loaderDiv = document.createElement("div");
   loaderDiv.id = "loader";
@@ -782,11 +844,13 @@ function afficheLoader() {
   loaderDiv.appendChild(loader);
   document.body.appendChild(loaderDiv);
 }
-
+// Retrait du loader (animation jeu pong)
 function retirerLoader() {
   document.getElementById("loader").remove();
 }
 
+// Simplification de l'envoie de toast pour un étudiant
+// affiche le nom, le prénom et l'état de l'assiduité avec une couleur spécifique
 function envoiToastEtudiant(etat, etud) {
   let etatAffiche;
 
@@ -810,8 +874,10 @@ function envoiToastEtudiant(etat, etud) {
 
   pushToast(generateToast(span, getToastColorFromEtat(etat.toUpperCase()), 5));
 }
-
-// TODO commenter toutes les fonctions js
+// Fonction pour simplifier l'envoie de toast avec le bouton "mettre tout le monde"
+// On donne un etat et un compte et cela affichera le message associé.
+// ex : 12 assiduités ont été supprimées
+// ex : 15 étudiants ont été mis Absent.
 function envoiToastTous(etat, count) {
   const span = document.createElement("span");
   let etatAffiche = etat;
@@ -840,7 +906,9 @@ function envoiToastTous(etat, count) {
 
   pushToast(generateToast(span, getToastColorFromEtat(etat.toUpperCase()), 5));
 }
-
+// Permet de savoir si un jour est travaillé ou pas
+// jour : Date
+// nonWorkdays : Array[str] => ["mar", "sam", "dim"]
 function estJourTravail(jour, nonWorkdays) {
   const d = Intl.DateTimeFormat("fr-FR", {
     timeZone: SCO_TIMEZONE,
@@ -851,6 +919,9 @@ function estJourTravail(jour, nonWorkdays) {
   return !nonWorkdays.includes(d);
 }
 
+// Renvoie le dernier jour travaillé disponible.
+// par défaut va en arrière (dans le passé)
+// si anti == False => va dans le futur
 function retourJourTravail(date, anti = true) {
   const jourMiliSecondes = 86400000; // 24 * 3600 * 1000 | H * s * ms
   let jour = date;
@@ -864,12 +935,18 @@ function retourJourTravail(date, anti = true) {
   }
   return jour;
 }
-
+// Vérifie si la date courante est travaillée
+// Si ce n'est pas le cas, on change la date pour le dernier jour travaillé (passé)
+// et on affiche une alerte
+// (utilise le datepicker #date)
 function dateCouranteEstTravaillee() {
   const date = $("#date").datepicker("getDate");
+
   if (!estJourTravail(date, nonWorkDays)) {
+    // récupération du jour travaillé le plus proche
     const nouvelleDate = retourJourTravail(date);
     $("#date").datepicker("setDate", nouvelleDate);
+    // Création du message d'alerte
     let msg = "Le jour sélectionné";
     if (new Date().format("YYYY-MM-DD") == date.format("YYYY-MM-DD")) {
       msg = "Aujourd'hui";
@@ -889,13 +966,15 @@ function dateCouranteEstTravaillee() {
         )}.`
       )
     );
+    // Affichage de l'alerte
     openAlertModal("Attention", div, "", "#eec660");
 
     return false;
   }
   return true;
 }
-
+// Fonction pour passer au jour suivant
+// anti : bool => si true, on va dans le passé
 function jourSuivant(anti = false) {
   let date = $("#date").datepicker("getDate");
 
diff --git a/app/templates/assiduites/pages/bilan_etud.j2 b/app/templates/assiduites/pages/bilan_etud.j2
index 6bb97053c199b897a2f6d97b20668b84e5d04314..74586c5ff946f00cc083cf238241d8461ee3a4da 100644
--- a/app/templates/assiduites/pages/bilan_etud.j2
+++ b/app/templates/assiduites/pages/bilan_etud.j2
@@ -111,7 +111,13 @@ Bilan assiduité de {{sco.etud.nomprenom}}
     <script src="{{scu.STATIC_DIR}}/js/date_utils.js"></script>
 
     <script>
+
+    // Récupération des statistiques d'assiduité et affichage
+    // Fonction appelée lors du clic sur le bouton "Actualiser"
+    // Et au chargement de la page
     function stats() {
+        // On prend les dates de début et de fin 
+        // (format DD/MM/YYYY) et on les convertit en Date()
         const dd_val = document.getElementById('stats_date_debut').value;
         const df_val = document.getElementById('stats_date_fin').value;
         let date_debut = new Date(Date.fromFRA(dd_val));
@@ -120,7 +126,7 @@ Bilan assiduité de {{sco.etud.nomprenom}}
             openAlertModal("Dates invalides", document.createTextNode('Les dates sélectionnées sont invalides'));
             return;
         }
-
+        // On met les dates à 00h et 23h59 pour avoir la journée entière
         date_debut = date_debut.startOf("day")
         date_fin = date_fin.endOf("day")
 
@@ -128,10 +134,15 @@ Bilan assiduité de {{sco.etud.nomprenom}}
             openAlertModal("Dates invalides", document.createTextNode('La date de début se situe après la date de fin.'));
             return;
         }
+        // Appel à l'api et affichage des stats sur la page
         countAssiduites(date_debut.toFakeIso(), date_fin.toFakeIso())
 
     }
-
+    // Appel à l'api pour récupérer les statistiques d'assiduité
+    // Effectue l'action passée en paramètre sur les données récupérées
+    // dateDeb : date de début au format ISO
+    // dateFin : date de fin au format ISO
+    // action : fonction à appeler sur les données récupérées
     function getAssiduitesCount(dateDeb, dateFin, action) {
         const url_api = `../../api/assiduites/${etudid}/count/query?date_debut=${dateDeb}&date_fin=${dateFin}&etat=absent,retard,present&split`;
         async_get(
@@ -142,6 +153,9 @@ Bilan assiduité de {{sco.etud.nomprenom}}
     }
 
     function showStats(data){
+        // Initialisation d'un objet contenant les résultats
+        // Sera mis à jour avec le reste des valeurs dans la suite
+        // du code
         const counter = {
             "present": {
                 "total": data["present"],
@@ -155,33 +169,39 @@ Bilan assiduité de {{sco.etud.nomprenom}}
                 "justi": data["absent"]["justifie"],
             }
         }
-
+        // Reset du DOM
         const values = document.querySelector('.stats-values');
         values.innerHTML = "";
-
+        // Pour chaque état d'assiduité (present, retard, absent)
         Object.keys(counter).forEach((key) => {
+
+            // On créé les éléments HTML qui serviront d'affichage
             const item = document.createElement('div');
             item.classList.add('stats-values-item');
 
             const div = document.createElement('div');
             div.classList.add('stats-values-part');
 
+            // Fonction anonyme pour éviter de réécrire tout le temps un test
+            // Si l'état est "present" alors cela renvoie "" (=> pas de nb justifié)
+            // Sinon cela renvoie "dont X justifiées"
             const withJusti = (key, metric) => {
                 if (key == "present") return "";
                 return ` dont ${counter[key].justi[metric]} justifiées`
             }
-
+            // HEURE : aroundie à 2 décimales.
             const heure = document.createElement('span');
             heure.textContent = `${counter[key].total.heure.toFixed(2)} heure(s)${withJusti(key, "heure")}`;
-
+            // DEMI-JOURNEE
             const demi = document.createElement('span');
             demi.textContent = `${counter[key].total.demi} demi-journée(s)${withJusti(key, "demi")}`;
-
+            // JOURNEE
             const jour = document.createElement('span');
             jour.textContent = `${counter[key].total.journee} journée(s)${withJusti(key, "journee")}`;
-
+            
+            // On met à jour le DOM avec les valeurs calculées
+            // On met l'état en Titre pour chaque partie
             div.append(jour, demi, heure);
-
             const title = document.createElement('h5');
             title.textContent = key.capitalize();
 
@@ -190,8 +210,10 @@ Bilan assiduité de {{sco.etud.nomprenom}}
             values.appendChild(item);
         });
 
+        // On vérifie si l'étudiant a trop d'absences
         const nbAbs = data["absent"]["non_justifie"][assi_metric];
         if (nbAbs > assi_seuil) {
+            // L'étudiant est au dessus du seuil (défini dans les préférences du département)
             document.querySelector('.alerte').classList.remove('invisible');
             document.querySelector('.alerte p').textContent = `Attention, cet étudiant a trop d'absences ${nbAbs} / ${assi_seuil} (${metriques[assi_metric]})`
         } else {
@@ -202,7 +224,8 @@ Bilan assiduité de {{sco.etud.nomprenom}}
     function countAssiduites(dateDeb, dateFin) {
         getAssiduitesCount(dateDeb, dateFin, showStats);
     }
-
+    // Table de conversion des métriques
+    // Utilisé pour afficher les valeurs en fonction de la métrique
     const metriques = {
         "heure": "H.",
         "demi": "1/2 J.",
@@ -210,7 +233,8 @@ Bilan assiduité de {{sco.etud.nomprenom}}
     }
 
 
-
+    // Récupération des données obligatoires pour les fonctions
+    // Depuis le contexte de la page (Jinja2)
     const etudid = {{ sco.etud.id }};
     const assi_metric = "{{ assi_metric | safe }}";
     const assi_seuil = {{ assi_seuil }};
@@ -218,6 +242,8 @@ Bilan assiduité de {{sco.etud.nomprenom}}
     const assi_date_debut = "{{date_debut}}";
     const assi_date_fin = "{{date_fin}}";
 
+    // Au chargement de la page, on met les dates par défaut
+    // Et on appelle la fonction stats() pour afficher les stats
     window.addEventListener('load', () => {
         document.getElementById('stats_date_fin').value = assi_date_fin;
         document.getElementById('stats_date_debut').value = assi_date_debut;
diff --git a/app/templates/assiduites/pages/calendrier_assi_etud.j2 b/app/templates/assiduites/pages/calendrier_assi_etud.j2
index b4fa38547c7f024f1ae6ca07fb6e750847f7f6ce..33275ba16d1233dd9d0bef4370f627e4a42c1f11 100644
--- a/app/templates/assiduites/pages/calendrier_assi_etud.j2
+++ b/app/templates/assiduites/pages/calendrier_assi_etud.j2
@@ -192,6 +192,8 @@ Calendrier de l'assiduité
     </style>
 
     <script>
+        // Retourne un object {show_pres: bool, show_reta: bool, mode_demi: bool}
+        // Correspondant aux options cochées. (voir les checkbox dans le html)
         function getOptions() {
             return {
                 "show_pres": document.getElementById("show_pres").checked,
@@ -200,31 +202,37 @@ Calendrier de l'assiduité
             }
         }
 
-
+        // Fonction qui recharge la page en fonction des options cochées
         function updatePage() {
+            // On génère un Objet URL à partir de l'url actuelle
             const url = new URL(location.href);
             const options = getOptions();
+            // grace à l'objet URL on peut modifier les paramètres de l'url
+            // sans devoir parser l'url et la reconstruire
             url.searchParams.set("annee", document.getElementById('annee').value);
             url.searchParams.set("mode_demi", options.mode_demi);
             url.searchParams.set("show_pres", options.show_pres);
             url.searchParams.set("show_reta", options.show_reta);
-
+            // On change l'url de la page si elle est différente de l'url actuelle
             if (location.href != url.href) {
                 location.href = url.href
             }
         }
-
+        // L'année scolaire par défaut
         const defAnnee = "{{ annee | safe}}"
+        // Les années disponibles pour l'étudiant (["2022-2023", "2021-2022", ...])
         let annees = {{ annees | safe }}
+        // On retire les doublons
         annees = annees.filter((x, i) => annees.indexOf(x) === i)
         const etudid = {{ sco.etud.id }};
-
+        // Peuplement du sélecteur d'année scolaire avec les années disponibles
         const select = document.querySelector('#annee');
         annees.forEach((a) => {
+            // <option value="2022">2022-2023</option>
             const opt = document.createElement("option");
             let a_1 = a.substring(0, 4)
             opt.value = a_1 + "",
-                opt.textContent = a
+            opt.textContent = a
             if (a_1 === defAnnee) {
                 opt.selected = true;
                 document.querySelector('.annee #label-annee').textContent = `Année scolaire ${a}`
@@ -232,13 +240,15 @@ Calendrier de l'assiduité
             }
             select.appendChild(opt)
         })
-
+        // On ajoute un écouteur d'événement pour le rechargement de la page
+        // donc effectué sur le sélecteur d'année scolaire et les checkbox
         document.querySelectorAll('input[type="checkbox"].memo, #annee').forEach(el => {
             el.addEventListener('change', function () {
                 updatePage();
             })
         });
-
+        // On ajoute un click event pour chaque case d'assiduité afin de rediriger
+        // Sur la page d'édition de l'assiduité
         document.querySelectorAll('[assi_id]').forEach((el, i) => {
             el.addEventListener('click', () => {
                 const assi_id = el.getAttribute('assi_id');
diff --git a/app/templates/assiduites/pages/visu_assi_group.j2 b/app/templates/assiduites/pages/visu_assi_group.j2
index 2b99c8a1f156f370132b65943a14ef5fd60a45c7..3dc48d26504d0323edf3b86602629d99c62a813d 100644
--- a/app/templates/assiduites/pages/visu_assi_group.j2
+++ b/app/templates/assiduites/pages/visu_assi_group.j2
@@ -44,10 +44,15 @@ label.stats_checkbox {
     const date_fin = "{{date_fin}}";
     const group_ids = "{{group_ids}}";
 
+    // Changement de la date de début ou de fin des statitiques
+    // Recharge la page avec les nouvelles dates
     function stats() {
         const deb = Date.fromFRA(document.querySelector('#stats_date_debut').value);
         const fin = Date.fromFRA(document.querySelector('#stats_date_fin').value);
-        location.href = `visu_assi_group?group_ids=${group_ids}&date_debut=${deb}&date_fin=${fin}`;
+        let url = new URL(window.location.href);
+        url.searchParams.set('date_debut', deb);
+        url.searchParams.set('date_fin', fin);
+        location.href = url.href;
     }
 
     window.addEventListener('load', () => {
diff --git a/app/templates/assiduites/widgets/alert.j2 b/app/templates/assiduites/widgets/alert.j2
index bf1f0bfec6545758ec29e2bc36be3a4a1244ba5a..7aa527ba621f35b7204f877d080f3330d27ab829 100644
--- a/app/templates/assiduites/widgets/alert.j2
+++ b/app/templates/assiduites/widgets/alert.j2
@@ -127,19 +127,29 @@
 
 <script>
     const alertmodal = document.getElementById("alertModal");
+    /**
+     * openAlertModal
+     * @param {string} titre // titre du modal
+     * @param {HTMLElement} contenu // contenu du modal
+     * @param {string} footer // texte du footer
+     * @param {string} color // valeur CSS de la couleur de fond
+     */
     function openAlertModal(titre, contenu, footer, color = "var(--color-error)") {
+        // On affiche le modal
         alertmodal.classList.add('is-active');
-
+        // On met à jour les valeurs du modal
         alertmodal.querySelector('.alertmodal-title').textContent = titre;
         alertmodal.querySelector('.alertmodal-body').innerHTML = ""
         alertmodal.querySelector('.alertmodal-body').appendChild(contenu);
         alertmodal.querySelector('.alertmodal-footer').textContent = footer;
 
+        // On met à jour les couleurs de chaque partie du modal
         const banners = Array.from(alertmodal.querySelectorAll('.alertmodal-footer,.alertmodal-header'))
         banners.forEach((ban) => {
             ban.style.backgroundColor = color;
         })
-
+        // On ajoute un écouteur d'événement pour fermer le modal
+        // si on clique en dehors de celui-ci
         alertmodal.addEventListener('click', (e) => {
             if (e.target.id == alertmodal.id) {
                 alertmodal.classList.remove('is-active');
@@ -148,9 +158,11 @@
             }
         })
     }
+    // Fonction pour fermer le modal de manière programmatique
     function closeAlertModal() {
         alertmodal.classList.remove("is-active")
     }
+    // On ajoute un écouteur d'événement pour fermer le modal avec la croix
     const alertClose = document.querySelector(".alertmodal-close");
     alertClose.onclick = function () {
         closeAlertModal()
diff --git a/app/templates/assiduites/widgets/minitimeline.j2 b/app/templates/assiduites/widgets/minitimeline.j2
index 1e2efdeef599e72e0ea36589a9a4538ace72e8b7..feab40fd7ac42a1b5c1363b36356fdf13996cb22 100644
--- a/app/templates/assiduites/widgets/minitimeline.j2
+++ b/app/templates/assiduites/widgets/minitimeline.j2
@@ -32,7 +32,9 @@
             });
 
         }
-
+        // Pour chaque assiduité (et pour le créneau) on vient créer un block
+        // le block est positionné en fonction de l'heure de début et de fin
+        // et prend une largeur proportionnelle à la durée de l'assiduité
         array.forEach((assiduité) => {
             if(assiduité.etat == "CRENEAU" && readOnly) return;
             let startDate = new Date(Date.removeUTC(assiduité.date_debut));
@@ -57,6 +59,8 @@
             block.style.width = `${widthPercentage}%`;
 
             if (assiduité.etat != "CRENEAU") {
+                // Si on clique dessus on veut pouvoir 
+                // mettre à jour la timeline principale et modifier le moduleimpl_select
                 block.addEventListener("click", () => {
                     let deb = startDate.getHours() + startDate.getMinutes() / 60;
                     let fin = endDate.getHours() + endDate.getMinutes() / 60;
@@ -90,7 +94,7 @@
 
         return timeline;
     }
-
+    // Ajout du "13h" sur la mini timeline
     function setMiniTick(timelineDate, dayStart, dayDuration) {
         const endDate = timelineDate.clone().startOf("day");
         endDate.setHours(13, 0);
diff --git a/app/templates/assiduites/widgets/prompt.j2 b/app/templates/assiduites/widgets/prompt.j2
index 008e02901e6664bfddb996dd39d0cd514f00ec12..e483d11e1bd10ade4626d3c535469dd73d4fce83 100644
--- a/app/templates/assiduites/widgets/prompt.j2
+++ b/app/templates/assiduites/widgets/prompt.j2
@@ -157,65 +157,92 @@
 </style>
 
 <script>
+    // Récupère l'élément modal par son ID
     const promptModal = document.getElementById("promptModal");
+
+    /**
+    * Ouvre la fenêtre modale avec les paramètres spécifiés.
+    * @param {string} titre - Le titre de la modale.
+    * @param {HTMLElement} contenu - Le contenu de la modale.
+    * @param {Function} success - La fonction à appeler en cas de succès.
+    * @param {Function} [cancel] - La fonction à appeler en cas d'annulation (optionnelle).
+    * @param {string} [color="var(--color-error)"] - La couleur de fond des bannières de la modale (optionnelle).
+    */
     function openPromptModal(titre, contenu, success, cancel = () => { }, color = "var(--color-error)") {
+        // Active la modale en ajoutant une classe
         promptModal.classList.add('is-active');
 
+        // Met à jour le titre et le contenu de la modale
         promptModal.querySelector('.promptModal-title').textContent = titre;
-        promptModal.querySelector('.promptModal-body').innerHTML = ""
+        promptModal.querySelector('.promptModal-body').innerHTML = "";
         promptModal.querySelector('.promptModal-body').appendChild(contenu);
 
-        promptModal.querySelector('.promptModal-footer').innerHTML = ""
+        // Vide le pied de page et ajoute les boutons d'action
+        promptModal.querySelector('.promptModal-footer').innerHTML = "";
         promptModalButtonAction(success, cancel).forEach((btnPrompt) => {
-            promptModal.querySelector('.promptModal-footer').appendChild(btnPrompt)
-        })
-
+            promptModal.querySelector('.promptModal-footer').appendChild(btnPrompt);
+        });
 
-        const banners = Array.from(promptModal.querySelectorAll('.promptModal-footer,.promptModal-header'))
+        // Change la couleur de fond des bannières de la modale
+        const banners = Array.from(promptModal.querySelectorAll('.promptModal-footer, .promptModal-header'));
         banners.forEach((ban) => {
             ban.style.backgroundColor = color;
-        })
+        });
 
+        // Ajoute un écouteur d'événement pour fermer la modale en cliquant en dehors
         promptModal.addEventListener('click', (e) => {
             if (e.target.id == promptModal.id) {
                 promptModal.classList.remove('is-active');
-                promptModal.removeEventListener('click', this)
+                promptModal.removeEventListener('click', this);
             }
-        })
+        });
 
+        // Désactive le défilement de la page principale
         document.body.style.overflow = "hidden";
-
     }
 
+    /**
+    * Crée les boutons de validation et d'annulation pour la modale.
+    * @param {Function} success - La fonction à appeler en cas de succès.
+    * @param {Function} cancel - La fonction à appeler en cas d'annulation.
+    * @returns {HTMLElement[]} - Les boutons de validation et d'annulation.
+    */
     function promptModalButtonAction(success, cancel) {
-        const succBtn = document.createElement('button')
-        succBtn.classList.add("btnPrompt")
-        succBtn.textContent = "Valider"
+        const succBtn = document.createElement('button');
+        succBtn.classList.add("btnPrompt");
+        succBtn.textContent = "Valider";
         succBtn.addEventListener('click', () => {
             const retour = success(closePromptModal);
             if (retour == null || retour == false || retour == undefined) {
                 closePromptModal();
             }
-        })
-        const cancelBtn = document.createElement('button')
-        cancelBtn.classList.add("btnPrompt")
-        cancelBtn.textContent = "Annuler"
+        });
+
+        const cancelBtn = document.createElement('button');
+        cancelBtn.classList.add("btnPrompt");
+        cancelBtn.textContent = "Annuler";
         cancelBtn.addEventListener('click', () => {
             cancel();
             closePromptModal();
-        })
+        });
 
-        return [succBtn, cancelBtn]
+        return [succBtn, cancelBtn];
     }
 
+    /**
+    * Ferme la fenêtre modale.
+    */
     function closePromptModal() {
-        promptModal.classList.remove("is-active")
+        promptModal.classList.remove("is-active");
         document.body.style.overflow = "auto";
     }
+
+    // Ajoute un écouteur d'événement pour fermer la modale en cliquant sur le bouton de fermeture
     const promptClose = document.querySelector(".promptModal-close");
     promptClose.onclick = function () {
-        closePromptModal()
-    }
+        closePromptModal();
+    };
+
 
 </script>
 {% endblock promptModal %}
\ No newline at end of file
diff --git a/app/templates/assiduites/widgets/tableau.j2 b/app/templates/assiduites/widgets/tableau.j2
index 1517ebcb9b916b060406e026fcc0a55a53308f3e..a392b7f875e23b5f3d8671ceff83bab66323d795 100644
--- a/app/templates/assiduites/widgets/tableau.j2
+++ b/app/templates/assiduites/widgets/tableau.j2
@@ -154,7 +154,7 @@
 
 
 <script>
-
+    // Fonction pour mettre à jour l'url avec les options du tableau
     function updateTableau() {
         const url = new URL(location.href);
         const formValues = document.querySelectorAll(".options-tableau *[name]");
@@ -173,7 +173,7 @@
     }
 
     const total_pages = {{total_pages}};
-
+    // Fonction pour naviguer entre les pages, modifie le champ n_page de l'url
     function navigateToPage(pageNumber){
         if(pageNumber > total_pages || pageNumber < 1) return;
         const url = new URL(location.href);
@@ -186,7 +186,7 @@
         }
 
     }
-
+    // Préparation des opérations de trai sur les colonnes "external-sort"
     window.addEventListener('load', ()=>{
         const table_columns = [...document.querySelectorAll('th.external-sort')];
         table_columns.forEach((e)=>e.addEventListener('click', ()=>{
diff --git a/app/templates/assiduites/widgets/tableau_actions/details.j2 b/app/templates/assiduites/widgets/tableau_actions/details.j2
deleted file mode 100644
index 7665ee03c069315c50b3de55f80fe8d43850a3bf..0000000000000000000000000000000000000000
--- a/app/templates/assiduites/widgets/tableau_actions/details.j2
+++ /dev/null
@@ -1,140 +0,0 @@
-<h2>Détails {{type}} concernant <span class="etudinfo"
-            id="etudid-{{objet.etudid}}">{{etud.html_link_fiche()|safe}}</span></h2>
-
-<style>
-.info-row {
-    margin-top: 12px;
-}
-.info-label {
-    font-weight: bold;
-}
-.info-etat {
-    font-size: 110%;
-    font-weight: bold;
-    background-color: rgb(253, 234, 210);
-    border: 1px solid grey;
-    border-radius: 4px;
-    padding: 4px;
-}
-.info-saisie {
-    margin-top: 12px;
-    margin-bottom: 12px;
-    font-style: italic;
-}
-</style>
-
-<div id="informations">
-
-    <div class="info-saisie">
-        <span>Saisie par {{objet.saisie_par}} le {{objet.entry_date}}</span>
-    </div>
-
-    <div class="info-row">
-        <span class="info-label">Période :</span> du <b>{{objet.date_debut}}</b> au <b>{{objet.date_fin}}</b>
-    </div>
-
-    {% if type == "Assiduité" %}
-    <div class="info-row">
-        <span class="info-label">Module :</span> {{objet.module}}
-    </div>
-    {% else %}
-    {% endif %}
-
-    <div class="info-row">
-        {% if type == "Justificatif" %}
-        <span class="info-label">État du justificatif :</span>
-        {% else %}
-        <span class="info-label">État de l'assiduité :</span>
-        {% endif %}
-        <span class="info-etat">{{objet.etat}}</span>
-
-    </div>
-
-    <div class="info-row">
-        {% if type == "Justificatif" %}
-        <span class="info-label">Raison:</span>
-            {% if can_view_justif_detail %}
-                <span class="text">{{objet.raison or " "}}</span>
-            {% else %}
-                <span class="text unauthorized">(cachée)</span>
-            {% endif %}
-        {% else %}
-        <span class="info-label">Description:</span>
-            {% if objet.description != None %}
-                <span class="text">{{objet.description}}</span>
-            {% else %}
-                <span class="text"></span>
-            {% endif %}
-        {% endif %}
-        </span>
-    </div>
-
-    {# Affichage des justificatifs si assiduité justifiée #}
-    {% if type == "Assiduité" and objet.etat != "Présence" %}
-    <div class="info-row">
-        <span class="info-label">Justifiée: </span>
-        {% if objet.justification.est_just %}
-        <span class="text">Oui</span>
-        <div>
-            {% for justi in objet.justification.justificatifs %}
-            <a href="{{url_for('assiduites.tableau_assiduite_actions',
-                type='justificatif', action='details', obj_id=justi.justif_id, scodoc_dept=g.scodoc_dept)}}"
-                target="_blank" rel="noopener noreferrer">Justificatif du {{justi.date_debut}} au {{justi.date_fin}}</a>
-            {% endfor %}
-        </div>
-        {% else %}
-        <span class="text fontred">Non</span>
-        {% endif %}
-    </div>
-    {% endif %}
-
-    {# Affichage des assiduités justifiées si justificatif valide #}
-    {% if type == "Justificatif" and objet.etat == "Valide" %}
-    <div class="info-row">
-        <span class="info-label">Assiduités concernées: </span>
-        {% if objet.justification.assiduites %}
-        <ul>
-            {% for assi in objet.justification.assiduites %}
-            <li><a href="{{url_for('assiduites.tableau_assiduite_actions',
-                type='assiduite', action='details', obj_id=assi.assiduite_id, scodoc_dept=g.scodoc_dept)
-                }}" target="_blank">Assiduité {{assi.etat}} du {{assi.date_debut}} au
-                {{assi.date_fin}}</a>
-            </li>
-            {% endfor %}
-        </ul>
-        {% else %}
-        <span class="text">Aucune</span>
-        {% endif %}
-    </div>
-    {% endif %}
-
-    {# Affichage des fichiers des justificatifs #}
-    {% if type == "Justificatif"%}
-        <div class="info-row">
-            <span class="info-label">Fichiers enregistrés: </span>
-            {% if objet.justification.fichiers.total != 0 %}
-            <div>Total : {{objet.justification.fichiers.total}} </div>
-            <ul>
-                {% for filename in objet.justification.fichiers.filenames %}
-                <li>
-                    <a
-                        href="{{url_for('apiweb.justif_export',justif_id=objet.justif_id,
-                            filename=filename, scodoc_dept=g.scodoc_dept)}}">{{filename}}</a>
-                </li>
-                {% endfor %}
-                {% if not objet.justification.fichiers.filenames %}
-                <li class="fontred">fichiers non visibles</li>
-                {% endif %}
-            </ul>
-            {% else %}
-            <span class="text">Aucun</span>
-            {% endif %}
-        </div>
-        {% if current_user.has_permission(sco.Permission.AbsChange) %}
-        <div><a class="stdlink" href="{{
-            url_for('assiduites.edit_justificatif_etud', scodoc_dept=g.scodoc_dept, justif_id=obj_id)
-        }}">modifier ce justificatif</a>
-        </div>
-        {% endif %}
-    {% endif %}
-</div>
diff --git a/app/templates/assiduites/widgets/tableau_actions/modifier.j2 b/app/templates/assiduites/widgets/tableau_actions/modifier.j2
deleted file mode 100644
index 4c877fded6ad45f736239dbf305950c8c1ee16cc..0000000000000000000000000000000000000000
--- a/app/templates/assiduites/widgets/tableau_actions/modifier.j2
+++ /dev/null
@@ -1,117 +0,0 @@
-<h2>Modifier  {{objet_name}} de {{ etud.html_link_fiche() | safe }}</h2>
-
-{# XXX cette page ne semble plus utile ! remplacée par edit_justificatif_etud #}
-
-<div>
-Actuellement noté{{etud.e}} en <b>{{objet_name|lower()}}</b> du {{objet.date_debut}} au {{objet.date_fin}}
-</div>
-
-<form action="" method="post" enctype="multipart/form-data">
-    <input type="hidden" name="obj_id" value="{{obj_id}}">
-    <input type="hidden" name="table_url" id="table_url" value="">
-
-    {% if type == "Assiduité" %}
-    <input type="hidden" name="obj_type" value="assiduite">
-    <legend for="etat">État</legend>
-    <select name="etat" id="etat">
-        <option value="absent">Absent</option>
-        <option value="retard">Retard</option>
-        <option value="present">Présent</option>
-    </select>
-
-    <legend for="moduleimpl_select">Module</legend>
-    {{moduleimpl | safe}}
-
-    <legend for="description">Description</legend>
-    <textarea name="description" id="description" cols="50" rows="5">{{objet.description}}</textarea>
-
-    {% else %}
-    <input type="hidden" name="obj_type" value="justificatif">
-
-    <legend for="date_debut">Date de début</legend>
-    <scodoc-datetime name="date_debut" id="date_debut" value="{{objet.real_date_debut}}"></scodoc-datetime>
-    <legend for="date_fin">Date de fin</legend>
-    <scodoc-datetime name="date_fin" id="date_fin" value="{{objet.real_date_fin}}"></scodoc-datetime>
-
-    <legend for="etat">État</legend>
-    <select name="etat" id="etat">
-        <option value="valide">Valide</option>
-        <option value="non_valide">Non Valide</option>
-        <option value="attente">En Attente</option>
-        <option value="modifie">Modifié</option>
-    </select>
-
-    {% if current_user.has_permission(sco.Permission.AbsJustifView) %}
-        <legend for="raison">Raison</legend>
-        <textarea name="raison" id="raison" cols="50" rows="5">{{objet.raison}}</textarea>
-    {% else %}
-        <div class="unauthorized">(raison non visible ni modifiable)</div>
-    {% endif %}
-
-    <legend>Fichiers</legend>
-
-    <div class="info-row">
-        <label class="info-label">Fichiers enregistrés: </label>
-        {% if objet.justification.fichiers.total != 0 %}
-        <div>Total : {{objet.justification.fichiers.total}} </div>
-        <ul>
-            {% for filename in objet.justification.fichiers.filenames %}
-            <li data-id="{{filename}}">
-                <a data-file="{{filename}}">❌</a>
-                <a data-link=""
-                    href="{{url_for('apiweb.justif_export',justif_id=objet.justif_id,filename=filename, scodoc_dept=g.scodoc_dept)}}"><span
-                        data-file="{{filename}}">{{filename}}</span></a>
-            </li>
-            {% endfor %}
-        </ul>
-        {% else %}
-        <span class="text">Aucun</span>
-        {% endif %}
-    </div>
-    <br>
-    <label for="justi_fich">Ajouter des fichiers:</label>
-    <input type="file" name="justi_fich" id="justi_fich" multiple>
-
-
-    {% endif %}
-    <br>
-    <br>
-    <input type="submit" value="Valider">
-</form>
-
-<script>
-    function removeFile(element) {
-        const link = document.querySelector(`*[data-id="${element.getAttribute('data-file')}"] a[data-link] span`);
-        link?.toggleAttribute("data-remove")
-    }
-
-    function deleteFiles(justif_id) {
-
-        const filenames = Array.from(document.querySelectorAll("*[data-remove]")).map((el) => el.getAttribute("data-file"))
-        obj = {
-            "remove": "list",
-            "filenames": filenames
-        }
-        //faire un POST à l'api justificatifs
-    }
-
-    window.addEventListener('load', () => {
-        document.getElementById('etat').value = "{{objet.real_etat}}";
-        document.getElementById('table_url').value = document.referrer;
-        document.querySelectorAll("a[data-file]").forEach((e) => {
-            e.addEventListener('click', () => {
-                removeFile(e);
-            })
-        })
-    })
-</script>
-<style>
-    [data-remove] {
-        text-decoration: line-through;
-    }
-
-    [data-file] {
-        cursor: pointer;
-        user-select: none;
-    }
-</style>
diff --git a/app/templates/assiduites/widgets/timeline.j2 b/app/templates/assiduites/widgets/timeline.j2
index d7acdbe85bf158976421fb7054f9e0085857f307..eaac2b84591dd162f5ddd1fa0ee726e668128c1a 100644
--- a/app/templates/assiduites/widgets/timeline.j2
+++ b/app/templates/assiduites/widgets/timeline.j2
@@ -27,21 +27,25 @@
 
     let handleMoving = false;
 
+    // Création des graduations de la timeline
+    // On créé des grandes graduations pour les heures
+    // On créé des petites graduations pour les "tick"
     function createTicks() {
         let i = t_start;
 
         while (i <= t_end) {
+            // création d'un tick Heure (grand)
             const hourTick = document.createElement("div");
             hourTick.classList.add("tick", "hour");
             hourTick.style.left = `${((i - t_start) / (t_end - t_start)) * 100}%`;
             timelineContainer.appendChild(hourTick);
-
+            // on ajoute un label pour l'heure (ex : 12:00)
             const tickLabel = document.createElement("div");
             tickLabel.classList.add("tick-label");
             tickLabel.style.left = `${((i - t_start) / (t_end - t_start)) * 100}%`;
             tickLabel.textContent = numberToTime(i);
             timelineContainer.appendChild(tickLabel);
-
+            // Si on est pas à la fin, on ajoute les graduations intermédiaires
             if (i < t_end) {
                 let j = Math.floor(i + 1);
 
@@ -49,6 +53,7 @@
                     i += tick_delay;
 
                     if (i <= t_end) {
+                        // création d'un tick (petit)
                         const quarterTick = document.createElement("div");
                         quarterTick.classList.add("tick", "quarter");
                         quarterTick.style.left = `${computePercentage(i, t_start)}%`;
@@ -62,7 +67,8 @@
             }
         }
     }
-
+    // Convertit un nombre en heure
+    // ex : 12.5 => "12:30"
     function numberToTime(num) {
         const integer = Math.floor(num);
         const decimal = Math.round((num % 1) * 60);
@@ -80,13 +86,12 @@
         return int + dec;
 
     }
-
+    // Arrondi un nombre au tick le plus proche
     function snapToQuarter(value) {
-
-
         return Math.round(value * tick_time) / tick_time;
     }
-
+    // Mise à jour des valeurs des timepickers
+    // En fonction des valeurs de la timeline
     function updatePeriodTimeLabel() {
         const values = getPeriodValues();
         const deb = numberToTime(values[0])
@@ -102,96 +107,112 @@
 
     }
 
+    // Gestion des évènements de la timeline
+    // - Déplacement des poignées
+    // - Déplacement de la période
     function timelineMainEvent(event) {
 
+        // Position de départ de l'événement (souris ou tactile)
         const startX = (event.clientX || event.changedTouches[0].clientX);
 
+        // Vérifie si l'événement concerne une poignée de période
         if (event.target.classList.contains("period-handle")) {
+            // Initialisation des valeurs de départ
             const startWidth = parseFloat(periodTimeLine.style.width);
             const startLeft = parseFloat(periodTimeLine.style.left);
             const isLeftHandle = event.target.classList.contains("left");
-            handleMoving = true
+            handleMoving = true;
+
+            // Fonction de déplacement de la poignée
             const onMouseMove = (moveEvent) => {
 
                 if (!handleMoving) return;
 
+                // Calcul du déplacement en pixels
                 const deltaX = (moveEvent.clientX || moveEvent.changedTouches[0].clientX) - startX;
                 const containerWidth = timelineContainer.clientWidth;
-                const newWidth =
-                    startWidth + ((isLeftHandle ? -deltaX : deltaX) / containerWidth) * 100;
+                // Calcul de la nouvelle largeur en pourcentage
+                const newWidth = startWidth + ((isLeftHandle ? -deltaX : deltaX) / containerWidth) * 100;
 
                 if (isLeftHandle) {
+                    // Si la poignée gauche est déplacée, ajuste également la position gauche
                     const newLeft = startLeft + (deltaX / containerWidth) * 100;
                     adjustPeriodPosition(newLeft, newWidth);
                 } else {
                     adjustPeriodPosition(parseFloat(periodTimeLine.style.left), newWidth);
                 }
 
+                // Met à jour l'étiquette de temps de la période
                 updatePeriodTimeLabel();
             };
+
+            // Fonction de relâchement de la souris ou du tactile
+            // - Alignement des poignées sur les ticks
+            // - Appel des callbacks
+            // - Sauvegarde des valeurs dans le local storage
+            // - Réinitialisation de la variable de déplacement des poignées
             const mouseUp = () => {
                 snapHandlesToQuarters();
                 timelineContainer.removeEventListener("mousemove", onMouseMove);
                 handleMoving = false;
                 func_call();
                 savePeriodInLocalStorage();
+            };
 
-            }
+            // Ajoute les écouteurs d'événement pour le déplacement et le relâchement
             timelineContainer.addEventListener("mousemove", onMouseMove);
             timelineContainer.addEventListener("touchmove", onMouseMove);
-            document.addEventListener(
-                "mouseup",
-                mouseUp,
-                { once: true }
-            );
-            document.addEventListener(
-                "touchend",
-                mouseUp,
-                { once: true }
-
-            );
+            document.addEventListener("mouseup", mouseUp, { once: true });
+            document.addEventListener("touchend", mouseUp, { once: true });
+
+        // Vérifie si l'événement concerne la période elle-même
         } else if (event.target === periodTimeLine) {
 
             const startLeft = parseFloat(periodTimeLine.style.left);
 
+            // Fonction de déplacement de la période
             const onMouseMove = (moveEvent) => {
                 if (handleMoving) return;
                 const deltaX = (moveEvent.clientX || moveEvent.changedTouches[0].clientX) - startX;
                 const containerWidth = timelineContainer.clientWidth;
+                // Calcul de la nouvelle position gauche en pourcentage
                 const newLeft = startLeft + (deltaX / containerWidth) * 100;
 
                 adjustPeriodPosition(newLeft, parseFloat(periodTimeLine.style.width));
-
                 updatePeriodTimeLabel();
             };
+
+            // Fonction de relâchement de la souris ou du tactile
+            // - Alignement des poignées sur les ticks
+            // - Appel des callbacks
+            // - Sauvegarde des valeurs dans le local storage
             const mouseUp = () => {
                 snapHandlesToQuarters();
                 timelineContainer.removeEventListener("mousemove", onMouseMove);
                 func_call();
                 savePeriodInLocalStorage();
-            }
+            };
+
+            // Ajoute les écouteurs d'événement pour le déplacement et le relâchement
             timelineContainer.addEventListener("mousemove", onMouseMove);
             timelineContainer.addEventListener("touchmove", onMouseMove);
-            document.addEventListener(
-                "mouseup",
-                mouseUp,
-                { once: true }
-            );
-            document.addEventListener(
-                "touchend",
-                mouseUp,
-                { once: true }
-            );
+            document.addEventListener("mouseup", mouseUp, { once: true });
+            document.addEventListener("touchend", mouseUp, { once: true });
         }
     }
 
+
     let func_call = () => { };
 
+    // Fonction initialisant la timeline
+    // La fonction "callback" est appelée à chaque modification de la période
     function setupTimeLine(callback) {
         func_call = callback;
         timelineContainer.addEventListener("mousedown", (e) => { timelineMainEvent(e) });
         timelineContainer.addEventListener("touchstart", (e) => { timelineMainEvent(e) });
 
+        // Initialisation des timepickers (à gauche de la timeline)
+        // lors d'un changement, cela met à jour la timeline
         const updateFromInputs = ()=>{
             let deb = $('#deb').val();
             let fin = $('#fin').val();
@@ -209,9 +230,11 @@
         $('#deb').data('TimePicker').options.change = updateFromInputs;
         $('#fin').data('TimePicker').options.change = updateFromInputs;
 
+        // actualise l'affichage des inputs avec les valeurs de la timeline
         updatePeriodTimeLabel();
     }
-
+    // Ajuste la position de la période en fonction de la nouvelle position et largeur
+    // Vérifie que la période ne dépasse pas les limites de la timeline
     function adjustPeriodPosition(newLeft, newWidth) {
 
         const snappedLeft = snapToQuarter(newLeft);
@@ -224,30 +247,36 @@
         periodTimeLine.style.left = `${clampedLeft}%`;
         periodTimeLine.style.width = `${snappedWidth}%`;
     }
-
+    // Récupère les valeurs de la période
     function getPeriodValues() {
+        // On prend les pourcentages
         const leftPercentage = parseFloat(periodTimeLine.style.left);
         const widthPercentage = parseFloat(periodTimeLine.style.width);
 
+        // On calcule l'inverse des pourcentages pour obtenir les heures
         const startHour = (leftPercentage / 100) * (t_end - t_start) + t_start;
         const endHour = ((leftPercentage + widthPercentage) / 100) * (t_end - t_start) + t_start;
-
+        // On les arrondit aux ticks les plus proches
         const startValue = snapToQuarter(startHour);
         const endValue = snapToQuarter(endHour);
-
+        
+        // on verifie que les valeurs sont bien dans les bornes
         const computedValues = [Math.max(startValue, t_start), Math.min(t_end, endValue)];
-
+        
+        // si les valeurs sont hors des bornes, on les ajuste
         if (computedValues[0] > t_end || computedValues[1] < t_start) {
             return [t_start, Math.min(t_end, t_start + period_default)];
         }
-
+        // Si la période est trop petite, on l'agrandit artificiellement (il faut au moins 1 tick de largeur)
         if (computedValues[1] - computedValues[0] <= tick_delay && computedValues[1] < t_end - tick_delay) {
             computedValues[1] += tick_delay;
         }
 
         return computedValues;
     }
-
+    // Met à jour les valeurs de la période
+    // Met à jour l'affichage de la timeline
+    // Appelle les callbacks associés
     function setPeriodValues(deb, fin) {
         if (fin < deb) {
             throw new RangeError(`le paramètre 'deb' doit être inférieur au paramètre 'fin' ([${deb};${fin}])`)
@@ -259,8 +288,8 @@
 
         deb = snapToQuarter(deb);
         fin = snapToQuarter(fin);
-        let leftPercentage = (deb - t_start) / (t_end - t_start) * 100;
-        let widthPercentage = (fin - deb) / (t_end - t_start) * 100;
+        let leftPercentage = computePercentage(deb, t_start);
+        let widthPercentage = computePercentage(fin, deb);
         periodTimeLine.style.left = `${leftPercentage}%`;
         periodTimeLine.style.width = `${widthPercentage}%`;
 
@@ -269,7 +298,9 @@
         func_call();
         savePeriodInLocalStorage();
     }
-
+    // Aligne les poignées de la période sur les ticks les plus proches
+    // ex : 12h39 => 12h45 (si les ticks sont à 15min)
+    // evite aussi les dépassements de la timeline (max et min)
     function snapHandlesToQuarters() {
         const periodValues = getPeriodValues();
         let lef = Math.min(computePercentage(Math.abs(periodValues[0]), t_start), computePercentage(Math.abs(t_end), tick_delay));
@@ -288,15 +319,20 @@
 
         updatePeriodTimeLabel()
     }
-
+    // Retourne le pourcentage d'une valeur par rapport à t_start et t_end
+    // ex : 12h par rapport à 8h et 20h => 25%
     function computePercentage(a, b) {
         return ((a - b) / (t_end - t_start)) * 100;
     }
+    // Convertit une heure (string) en nombre
+    // ex : "12:30" => 12.5
     function fromTime(time, separator = ":") {
         const [hours, minutes] = time.split(separator).map((el) => Number(el))
         return hours + minutes / 60
     }
-
+    // Renvoie les valeurs de la période sous forme de date
+    // Les heures sont récupérées depuis la timeline
+    // la date est récupérée depuis un champ "#date" (datepicker)
     function getPeriodAsDate(){
         let [deb, fin] = getPeriodValues();
         deb = numberToTime(deb);
@@ -305,19 +341,21 @@
         const dateStr = $("#date")
         .datepicker("getDate")
         .format("yyyy-mm-dd")
-        .substring(0, 10);
+        .substring(0, 10); // récupération que de la date, pas des heures
 
         return {
             deb: new Date(`${dateStr}T${deb}`),
             fin: new Date(`${dateStr}T${fin}`)
         }
     }
-
+    // Sauvegarde les valeurs de la période dans le local storage
     function savePeriodInLocalStorage(){
         const dates = getPeriodValues();
         localStorage.setItem("sco-timeline-values", JSON.stringify(dates));
     }
 
+    // Récupère les valeurs de la période depuis le local storage
+    // Si elles n'existent pas, on les initialise avec les valeurs par défaut
     function loadPeriodFromLocalStorage(){
         const dates = JSON.parse(localStorage.getItem("sco-timeline-values"));
         if(dates){
@@ -326,11 +364,13 @@
             setPeriodValues(t_start, t_start + period_default);
         }
     }
+    // == Initialisation par défaut de la timeline ==
 
-    createTicks();
+    createTicks(); // création des graduations
 
-    loadPeriodFromLocalStorage();
+    loadPeriodFromLocalStorage(); // chargement des valeurs si disponible
 
+    // Si on donne les heures en appelant le template alors on met à jour la timeline
     {% if heures %}
     let [heure_deb, heure_fin] = [{{ heures | safe }}]
     if (heure_deb != '' && heure_fin != '') {
diff --git a/app/templates/assiduites/widgets/toast.j2 b/app/templates/assiduites/widgets/toast.j2
index 6081d227f4418ef2e8ca3749c96a359a8d1da5a4..b75cc1e481415573310e875a768b9fb5a8dc7f83 100644
--- a/app/templates/assiduites/widgets/toast.j2
+++ b/app/templates/assiduites/widgets/toast.j2
@@ -68,32 +68,49 @@
 </style>
 
 <script>
-
+    /**
+    * Génère une notification (toast) avec les paramètres spécifiés.
+    * @param {HTMLElement} content - Le contenu de la notification.
+    * @param {string} [color="var(--color-present)"] - La couleur de fond de la notification (optionnelle).
+    * @param {number} [ttl=5] - Le temps de vie de la notification en secondes (optionnelle).
+    * @returns {HTMLElement} - L'élément toast créé.
+    */
     function generateToast(content, color = "var(--color-present)", ttl = 5) {
-        const toast = document.createElement('div')
-        toast.classList.add('toast', 'fadeIn')
+        // Crée l'élément de notification et ajoute les classes de style
+        const toast = document.createElement('div');
+        toast.classList.add('toast', 'fadeIn');
 
-        const toastContent = document.createElement('div')
-        toastContent.classList.add('toast-content')
-        toastContent.appendChild(content)
+        // Crée le conteneur de contenu de la notification et y ajoute le contenu
+        const toastContent = document.createElement('div');
+        toastContent.classList.add('toast-content');
+        toastContent.appendChild(content);
 
+        // Définit la couleur de fond de la notification
         toast.style.backgroundColor = color;
 
-        setTimeout(() => { toast.classList.replace('fadeIn', 'fadeOut') }, Math.max(0, ttl * 1000 - 500))
-        setTimeout(() => { toast.remove() }, Math.max(0, ttl * 1000))
-        toast.appendChild(toastContent)
-        return toast
+        // Définit les temporisations pour les animations de disparition et la suppression de la notification
+        setTimeout(() => { toast.classList.replace('fadeIn', 'fadeOut') }, Math.max(0, ttl * 1000 - 500));
+        setTimeout(() => { toast.remove() }, Math.max(0, ttl * 1000));
+
+        // Ajoute le contenu à la notification
+        toast.appendChild(toastContent);
+        
+        return toast;
     }
 
+    /**
+    * Ajoute une notification (toast) à l'élément conteneur des toasts.
+    * @param {HTMLElement} toast - L'élément toast à ajouter.
+    */
     function pushToast(toast) {
-        document
-            .querySelector(".toast-holder")
-            .appendChild(
-                toast
-            );
+        document.querySelector(".toast-holder").appendChild(toast);
     }
 
-
+    /**
+    * Obtient la couleur de fond de la notification en fonction de l'état spécifié.
+    * @param {string} etat - L'état de la notification (PRESENT, ABSENT, RETARD).
+    * @returns {string} - La couleur correspondant à l'état.
+    */
     function getToastColorFromEtat(etat) {
         let color;
         switch (etat.toUpperCase()) {
@@ -107,12 +124,11 @@
                 color = "var(--color-retard)";
                 break;
             default:
-                color = "#AAA";
+                color = "#AAA"; // Couleur par défaut si l'état est inconnu
                 break;
         }
         return color;
     }
 
 
-
 </script>
\ No newline at end of file
diff --git a/app/views/assiduites.py b/app/views/assiduites.py
index 105222b919bb42e7e0c19e789e5b46d10c91abd5..00c4d3171ea3f4c2c3eceec275ed156a8326ed89 100644
--- a/app/views/assiduites.py
+++ b/app/views/assiduites.py
@@ -1537,116 +1537,10 @@ def tableau_assiduite_actions():
         flash(f"{objet_name} justifiée")
         return redirect(request.referrer)
 
-    if request.method == "GET":
-        module: str | int = ""  # moduleimpl_id ou chaine libre
-
-        if obj_type == "assiduite":
-            # Construction du menu module
-            module = _module_selector_multiple(objet.etudiant, objet.moduleimpl_id)
-
-        return render_template(
-            "assiduites/pages/tableau_assiduite_actions.j2",
-            action=action,
-            can_view_justif_detail=current_user.has_permission(Permission.AbsJustifView)
-            or (obj_type == "justificatif" and current_user.id == objet.user_id),
-            etud=objet.etudiant,
-            moduleimpl=module,
-            obj_id=obj_id,
-            objet_name=objet_name,
-            objet=_preparer_objet(obj_type, objet),
-            sco=ScoData(etud=objet.etudiant),
-            title=f"Assiduité {objet.etudiant.nom_short}",
-            # type utilisé dans les actions modifier / détails (modifier.j2, details.j2)
-            type="Justificatif" if obj_type == "justificatif" else "Assiduité",
-        )
-    # ----- Cas POST
-    if obj_type == "assiduite":
-        try:
-            _action_modifier_assiduite(objet)
-        except ScoValueError as error:
-            raise ScoValueError(error.args[0], request.referrer) from error
-        flash("L'assiduité a bien été modifiée.")
-    else:
-        try:
-            _action_modifier_justificatif(objet)
-        except ScoValueError as error:
-            raise ScoValueError(error.args[0], request.referrer) from error
-        flash("Le justificatif a bien été modifié.")
-    return redirect(request.form["table_url"])
-
-
-def _action_modifier_assiduite(assi: Assiduite):
-    form = request.form
-
-    # Gestion de l'état
-    etat = scu.EtatAssiduite.get(form["etat"])
-    if etat is not None:
-        assi.etat = etat
-        if etat == scu.EtatAssiduite.PRESENT:
-            assi.est_just = False
-        else:
-            assi.est_just = len(get_assiduites_justif(assi.assiduite_id, False)) > 0
-
-    # Gestion de la description
-    assi.description = form["description"]
-
-    possible_moduleimpl_id: str = form["moduleimpl_select"]
-
-    # Raise ScoValueError (si None et force module | Etudiant non inscrit | Module non reconnu)
-    assi.set_moduleimpl(possible_moduleimpl_id)
-
-    db.session.add(assi)
-    db.session.commit()
-    scass.simple_invalidate_cache(assi.to_dict(True), assi.etudid)
-
-
-def _action_modifier_justificatif(justi: Justificatif):
-    "Modifie le justificatif avec les valeurs dans le form"
-    form = request.form
-
-    # Gestion des Dates
-    date_debut: datetime = scu.is_iso_formated(form["date_debut"], True)
-    date_fin: datetime = scu.is_iso_formated(form["date_fin"], True)
-    if date_debut is None or date_fin is None or date_fin < date_debut:
-        raise ScoValueError("Dates invalides", request.referrer)
-    justi.date_debut = date_debut
-    justi.date_fin = date_fin
-
-    # Gestion de l'état
-    etat = scu.EtatJustificatif.get(form["etat"])
-    if etat is not None:
-        justi.etat = etat
-    else:
-        raise ScoValueError("État invalide", request.referrer)
-
-    # Gestion de la raison
-    justi.raison = form["raison"]
-
-    # Gestion des fichiers
-    files = request.files.getlist("justi_fich")
-    if len(files) != 0:
-        files = request.files.values()
-
-        archive_name: str = justi.fichier
-        # Utilisation de l'archiver de justificatifs
-        archiver: JustificatifArchiver = JustificatifArchiver()
-
-        for fich in files:
-            archive_name, _ = archiver.save_justificatif(
-                justi.etudiant,
-                filename=fich.filename,
-                data=fich.stream.read(),
-                archive_name=archive_name,
-                user_id=current_user.id,
-            )
-
-        justi.fichier = archive_name
-
-    justi.dejustifier_assiduites()
-    db.session.add(justi)
-    db.session.commit()
-    justi.justifier_assiduites()
-    scass.simple_invalidate_cache(justi.to_dict(True), justi.etudid)
+    # Si on arrive ici, c'est que l'action n'est pas autorisée
+    # cette fonction ne sert plus qu'à supprimer ou justifier
+    flash("Méthode non autorisée", "error")
+    return redirect(request.referrer)
 
 
 def _preparer_objet(