From 6d2c3f8dcc22fb1c5d24287d9ac7c3a8e738dbd4 Mon Sep 17 00:00:00 2001
From: iziram <matthias.hartmann@iziram.fr>
Date: Thu, 15 Jun 2023 17:50:38 +0200
Subject: [PATCH] Assiduites : Page liste - filtrage des tableaux

---
 app/static/css/assiduites.css                |  12 +-
 app/static/icons/filter.svg                  |   1 +
 app/templates/assiduites/liste_assiduites.j2 | 570 +++++++++++++++++--
 3 files changed, 545 insertions(+), 38 deletions(-)
 create mode 100644 app/static/icons/filter.svg

diff --git a/app/static/css/assiduites.css b/app/static/css/assiduites.css
index be4a8842c..56cef447c 100644
--- a/app/static/css/assiduites.css
+++ b/app/static/css/assiduites.css
@@ -510,16 +510,24 @@
 }
 
 .order {
+    background-image: url(../icons/sort.svg);
+}
+
+.filter {
+    background-image: url(../icons/filter.svg);
+}
+
+.icon {
     display: block;
     width: 24px;
     height: 24px;
-    background-image: url(../icons/sort.svg);
     outline: none;
     border: none;
     cursor: pointer;
+    margin: 0 2px;
 }
 
-.order:focus {
+.icon:focus {
     outline: none;
     border: none;
 }
\ No newline at end of file
diff --git a/app/static/icons/filter.svg b/app/static/icons/filter.svg
new file mode 100644
index 000000000..8259c6401
--- /dev/null
+++ b/app/static/icons/filter.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#000000"><path d="M4 3h16a1 1 0 011 1v1.586a1 1 0 01-.293.707l-6.415 6.414a1 1 0 00-.292.707v6.305a1 1 0 01-1.243.97l-2-.5a1 1 0 01-.757-.97v-5.805a1 1 0 00-.293-.707L3.292 6.293A1 1 0 013 5.586V4a1 1 0 011-1z" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>
\ No newline at end of file
diff --git a/app/templates/assiduites/liste_assiduites.j2 b/app/templates/assiduites/liste_assiduites.j2
index 685e191e5..2fd4daf6c 100644
--- a/app/templates/assiduites/liste_assiduites.j2
+++ b/app/templates/assiduites/liste_assiduites.j2
@@ -7,37 +7,38 @@
     <h2>Liste de l'assiduité et des justificatifs de <span class="rouge">{{sco.etud.nomprenom}}</span></h2>
 
     <h3>Assiduités :</h3>
+    <a class="icon filter" onclick="filter()"></a>
     <table id="assiduiteTable">
         <thead>
             <tr>
                 <th>
                     <div>
                         <span>Début</span>
-                        <a class="order" onclick="order('date_debut', assiduiteCallBack, this)"></a>
+                        <a class="icon order" onclick="order('date_debut', assiduiteCallBack, this)"></a>
                     </div>
                 </th>
                 <th>
                     <div>
                         <span>Fin</span>
-                        <a class="order" onclick="order('date_fin', assiduiteCallBack, this)"></a>
+                        <a class="icon order" onclick="order('date_fin', assiduiteCallBack, this)"></a>
                     </div>
                 </th>
                 <th>
                     <div>
                         <span>État</span>
-                        <a class="order" onclick="order('etat', assiduiteCallBack, this)"></a>
+                        <a class="icon order" onclick="order('etat', assiduiteCallBack, this)"></a>
                     </div>
                 </th>
                 <th>
                     <div>
                         <span>Module</span>
-                        <a class="order" onclick="order('moduleimpl_id', assiduiteCallBack, this)"></a>
+                        <a class="icon order" onclick="order('moduleimpl_id', assiduiteCallBack, this)"></a>
                     </div>
                 </th>
                 <th>
                     <div>
                         <span>Justifiée</span>
-                        <a class="order" onclick="order('est_just', assiduiteCallBack, this)"></a>
+                        <a class="icon order" onclick="order('est_just', assiduiteCallBack, this)"></a>
                     </div>
                 </th>
             </tr>
@@ -48,31 +49,32 @@
     <div id="paginationContainerAssiduites" class="pagination-container">
     </div>
     <h3>Justificatifs :</h3>
+    <a class="icon filter" onclick="filter(false)"></a>
     <table id="justificatifTable">
         <thead>
             <tr>
                 <th>
                     <div>
                         <span>Début</span>
-                        <a class="order" onclick="order('date_debut', justificatifCallBack, this, false)"></a>
+                        <a class="icon order" onclick="order('date_debut', justificatifCallBack, this, false)"></a>
                     </div>
                 </th>
                 <th>
                     <div>
                         <span>Fin</span>
-                        <a class="order" onclick="order('date_fin', justificatifCallBack, this, false)"></a>
+                        <a class="icon order" onclick="order('date_fin', justificatifCallBack, this, false)"></a>
                     </div>
                 </th>
                 <th>
                     <div>
                         <span>État</span>
-                        <a class="order" onclick="order('etat', justificatifCallBack, this, false)"></a>
+                        <a class="icon order" onclick="order('etat', justificatifCallBack, this, false)"></a>
                     </div>
                 </th>
                 <th>
                     <div>
                         <span>Raison</span>
-                        <a class="order" onclick="order('raison', justificatifCallBack, this, false)"></a>
+                        <a class="icon order" onclick="order('raison', justificatifCallBack, this, false)"></a>
                     </div>
                 </th>
             </tr>
@@ -94,7 +96,7 @@
 <style>
     .pageContent {
         width: 100%;
-        max-width: 800px;
+        max-width: var(--sco-content-max-width);
         display: flex;
         flex-direction: column;
         flex-wrap: wrap;
@@ -141,20 +143,20 @@
         background-color: #ddd;
     }
 
-    .present {
+    .l-present {
         background-color: #9CF1AF;
     }
 
-    .absent,
-    .invalid {
+    .l-absent,
+    .l-invalid {
         background-color: #F1A69C;
     }
 
-    .valid {
+    .l-valid {
         background-color: #8f7eff;
     }
 
-    .retard {
+    .l-retard {
         background-color: #F1D99C;
     }
 
@@ -190,6 +192,47 @@
         justify-content: space-between;
         align-items: center;
     }
+
+    .filter-head {
+        display: flex;
+        flex-wrap: wrap;
+        gap: 5px;
+    }
+
+    .filter-line {
+        display: flex;
+        justify-content: start;
+        align-items: center;
+        margin: 15px;
+    }
+
+    .filter-line>* {
+        margin-right: 5px;
+    }
+
+
+
+    .rbtn {
+        width: 35px;
+        height: 35px;
+        margin: 0 5px !important;
+    }
+
+    .f-label {
+        margin: 0 5px;
+    }
+
+    .chk {
+        margin-left: 2px !important;
+    }
+
+    label {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        padding: 0;
+        margin: 0;
+    }
 </style>
 
 <script>
@@ -202,6 +245,19 @@
     let orderAssiduites = true;
     let orderJustificatifs = true;
 
+    let filterAssiduites = {
+        columns: [
+            "entry_date", "date_debut", "date_fin", "etat", "moduleimpl_id", "est_just"
+        ],
+        filters: {}
+    }
+    let filterJustificatifs = {
+        columns: [
+            "entry_date", "date_debut", "date_fin", "etat", "raison"
+        ],
+        filters: {}
+    }
+
     const tableBodyAssiduites = document.getElementById("tableBodyAssiduites");
     const tableBodyJustificatifs = document.getElementById("tableBodyJustificatifs");
 
@@ -239,10 +295,53 @@
     });
 
     function assiduiteCallBack(assi) {
+        assi = filterArray(assi, filterAssiduites.filters)
         renderTableAssiduites(currentPageAssiduites, assi);
         renderPaginationButtons(assi);
     }
+
+    function filterArray(array, f) {
+        return array.filter((el) => {
+            let t = Object.keys(f).every((k) => {
+                if (k == "etat") {
+                    return f.etat.includes(el.etat.toLowerCase())
+                };
+                if (k == "est_just") {
+                    if (f.est_just != "") {
+                        return `${el.est_just}` == f.est_just;
+                    }
+                }
+                if (k.indexOf('date') != -1) {
+                    const assi_time = moment.tz(el[k], TIMEZONE);
+                    const filter_time = f[k].time;
+                    switch (f[k].pref) {
+
+                        case "0":
+                            return assi_time.isSame(filter_time, 'minute');
+                        case "-1":
+                            return assi_time.isBefore(filter_time, 'minutes');
+                        case "1":
+                            return assi_time.isAfter(filter_time, 'minutes');
+                    }
+                }
+
+                if (k == "moduleimpl_id") {
+                    const m = el[k] == undefined || el[k] == null ? "null" : el[k];
+                    if (f.moduleimpl_id != '') {
+                        return m == f.moduleimpl_id;
+                    }
+                }
+
+                return true;
+            })
+
+            return t;
+
+        })
+    }
+
     function justificatifCallBack(justi) {
+        justi = filterArray(justi, filterJustificatifs.filters)
         renderTableJustificatifs(currentPageJustificatifs, justi);
         renderPaginationButtons(justi, false);
     }
@@ -265,7 +364,37 @@
 
     }
 
+    function generateTableHead(columns, assi = true) {
+        const table = assi ? "#assiduiteTable" : "#justificatifTable"
+        const call = assi ? [assiduiteCallBack, true] : [justificatifCallBack, false]
+        const tr = document.querySelector(`${table} thead tr`);
+
+        tr.innerHTML = ""
+
+        columns.forEach((c) => {
+            const th = document.createElement('th');
+            const div = document.createElement('div');
+
+            const span = document.createElement('span');
+            span.textContent = columnTranslator(c);
+
+            const a = document.createElement('a');
+            a.classList.add('icon', "order");
+            a.onclick = () => { order(c, call[0], a, call[1]) }
+
+            div.appendChild(span)
+            div.appendChild(a)
+
+            th.appendChild(div);
+
+            tr.appendChild(th);
+        })
+    }
+
     function renderTableAssiduites(page, assiduités) {
+
+        generateTableHead(filterAssiduites.columns, true)
+
         tableBodyAssiduites.innerHTML = "";
         const start = (page - 1) * itemsPerPage;
         const end = start + itemsPerPage;
@@ -276,15 +405,21 @@
             row.setAttribute('obj_id', assiduite.assiduite_id);
 
             const etat = assiduite.etat.toLowerCase();
-            row.classList.add(etat);
+            row.classList.add(`l-${etat}`);
+            filterAssiduites.columns.forEach((k) => {
+                const td = document.createElement('td');
+                if (k.indexOf('date') != -1) {
+                    td.textContent = moment.tz(assiduite[k], TIMEZONE).format(`DD/MM/Y HH:mm`)
+                } else if (k.indexOf("module") != -1) {
+                    td.textContent = getModuleImpl(assiduite.moduleimpl_id);
+                } else if (k.indexOf('est_just') != -1) {
+                    td.textContent = assiduite[k] ? "Oui" : "Non"
+                } else {
+                    td.textContent = assiduite[k].capitalize()
+                }
 
-            row.innerHTML = `
-            <td>${moment.tz(assiduite.date_debut, TIMEZONE).format(`DD/MM/Y HH:mm`)}</td>
-            <td>${moment.tz(assiduite.date_fin, TIMEZONE).format(`DD/MM/Y HH:mm`)}</td>
-            <td>${etat}</td>
-            <td>${getModuleImpl(assiduite.moduleimpl_id)}</td>    <td>${assiduite.est_just ? "Oui" : "Non"
-                }</td>
-            `;
+                row.appendChild(td)
+            })
 
             row.addEventListener("contextmenu", (e) => {
                 e.preventDefault();
@@ -301,6 +436,8 @@
     }
 
     function renderTableJustificatifs(page, justificatifs) {
+        generateTableHead(filterJustificatifs.columns, false)
+
         tableBodyJustificatifs.innerHTML = "";
         const start = (page - 1) * itemsPerPage;
         const end = start + itemsPerPage;
@@ -313,17 +450,23 @@
             const etat = justificatif.etat.toLowerCase();
 
             if (etat == "valide") {
-                row.classList.add('valid');
+                row.classList.add(`l-valid`);
+
             } else {
-                row.classList.add('invalid')
+                row.classList.add(`l-invalid`);
+
             }
 
-            row.innerHTML = `
-            <td>${new Date(justificatif.date_debut).toLocaleString()}</td>
-            <td>${new Date(justificatif.date_fin).toLocaleString()}</td>
-            <td>${etat}</td>
-            <td>${justificatif.raison}</td>
-            `;
+            filterJustificatifs.columns.forEach((k) => {
+                const td = document.createElement('td');
+                if (k.indexOf('date') != -1) {
+                    td.textContent = moment.tz(justificatif[k], TIMEZONE).format(`DD/MM/Y HH:mm`)
+                } else {
+                    td.textContent = justificatif[k].capitalize()
+                }
+
+                row.appendChild(td)
+            })
 
             row.addEventListener("contextmenu", (e) => {
                 e.preventDefault();
@@ -403,7 +546,7 @@
     }
 
     function order(keyword, callback = () => { }, el, assi = true) {
-        const call = (array) => {
+        const call = (array, ordered) => {
             const sorted = array.sort((a, b) => {
                 let keyValueA = a[keyword];
                 let keyValueB = b[keyword];
@@ -420,26 +563,381 @@
 
                 let orderDertermined = keyValueA > keyValueB;
 
-                if (el.classList.contains("desc")) {
+                if (!ordered) {
                     orderDertermined = keyValueA < keyValueB;
                 }
                 return orderDertermined
             });
 
-            el.classList.toggle("desc");
+
 
             callback(sorted);
 
         };
 
         if (assi) {
-            getAllAssiduitesFromEtud(etudid, call)
+            orderAssiduites = !orderAssiduites;
+            getAllAssiduitesFromEtud(etudid, (a) => { call(a, orderAssiduites) })
         } else {
-            getAllJustificatifsFromEtud(etudid, call)
+            orderJustificatifs = !orderJustificatifs;
+            getAllJustificatifsFromEtud(etudid, (a) => { call(a, orderJustificatifs) })
         }
 
     }
 
+    function filter(assi = true) {
+        if (assi) {
+            let html = `
+                    <div class="filter-body">
+                        <h3>Affichage des colonnes:</h3>
+                        <div class="filter-head">
+                            <label>
+                                Date de saisie
+                                <input class="chk" type="checkbox" name="entry_date" id="entry_date">
+                            </label>
+                            <label>
+                                Date de Début
+                                <input class="chk" type="checkbox" name="date_debut" id="date_debut" checked>
+                            </label>
+                            <label>
+                                Date de Fin
+                                <input class="chk" type="checkbox" name="date_fin" id="date_fin" checked>
+                            </label>
+                            <label>
+                                Etat
+                                <input class="chk" type="checkbox" name="etat" id="etat" checked>
+                            </label>
+                            <label>
+                                Module
+                                <input class="chk" type="checkbox" name="moduleimpl_id" id="moduleimpl_id" checked>
+                            </label>
+                            <label>
+                                Justifiée
+                                <input class="chk" type="checkbox" name="est_just" id="est_just" checked>
+                            </label>
+                        </div>
+                        <hr>
+                        <h3>Filtrage des colonnes:</h3>
+                        <span class="filter-line">
+                            <span class="filter-title" for="entry_date">Date de saisie</span>
+                            <select name="entry_date_pref" id="entry_date_pref">
+                                <option value="-1">Avant</option>
+                                <option value="0">Égal</option>
+                                <option value="1">Après</option>
+                            </select>
+                            <input type="datetime-local" name="entry_date_time" id="entry_date_time">
+                        </span>
+                        <span class="filter-line">
+                            <span class="filter-title" for="date_debut">Date de début</span>
+                            <select name="date_debut_pref" id="date_debut_pref">
+                                <option value="-1">Avant</option>
+                                <option value="0">Égal</option>
+                                <option value="1">Après</option>
+                            </select>
+                            <input type="datetime-local" name="date_debut_time" id="date_debut_time">
+                        </span>
+                        <span class="filter-line">
+                            <span class="filter-title" for="date_fin">Date de fin</span>
+                            <select name="date_fin_pref" id="date_fin_pref">
+                                <option value="-1">Avant</option>
+                                <option value="0">Égal</option>
+                                <option value="1">Après</option>
+                            </select>
+                            <input type="datetime-local" name="date_fin_time" id="date_fin_time">
+                        </span>
+                        <span class="filter-line">
+                            <span class="filter-title" for="etat">Etat</span>
+                            <input checked type="checkbox" name="etat_present" id="etat_present" class="rbtn present" value="present">
+                            <input checked type="checkbox" name="etat_retard" id="etat_retard" class="rbtn retard" value="retard">
+                            <input checked type="checkbox" name="etat_absent" id="etat_absent" class="rbtn absent" value="absent">
+                        </span>
+                        <span class="filter-line">
+                            <span class="filter-title" for="moduleimpl_id">Module</span>
+                            <select id="moduleimpl_id">
+                                <option value="">Pas de filtre</option>
+                            </select>
+                        </span>
+                        <span class="filter-line">
+                            <span class="filter-title" for="est_just">Est Justifiée</span>
+                            <select id="est_just">
+                                <option value="">Pas de filtre</option>
+                                <option value="true">Oui</option>
+                                <option value="false">Non</option>
+                            </select>
+                        </span>
+                    </div>
+            `;
+            const span = document.createElement('span');
+            span.innerHTML = html
+            html = span.firstElementChild
+
+            const filterHead = html.querySelector('.filter-head');
+            filterHead.innerHTML = ""
+            let cols = ["entry_date", "date_debut", "date_fin", "etat", "moduleimpl_id", "est_just"];
+
+            cols.forEach((k) => {
+                const label = document.createElement('label')
+                label.classList.add('f-label')
+                const s = document.createElement('span');
+                s.textContent = columnTranslator(k);
+
+
+                const input = document.createElement('input');
+                input.classList.add('chk')
+                input.type = "checkbox"
+                input.name = k
+                input.id = k;
+                input.checked = filterAssiduites.columns.includes(k)
+
+                label.appendChild(s)
+                label.appendChild(input)
+                filterHead.appendChild(label)
+            })
+
+            const sl = html.querySelector('.filter-line #moduleimpl_id');
+            let opts = []
+            Object.keys(moduleimpls).forEach((k) => {
+                const opt = document.createElement('option');
+                opt.value = k == null ? "null" : k;
+                opt.textContent = moduleimpls[k];
+                opts.push(opt);
+            })
+
+            opts = opts.sort((a, b) => {
+                return a.value < b.value
+            })
+
+            sl.append(...opts);
+
+            // Mise à jour des filtres
+
+            Object.keys(filterAssiduites.filters).forEach((key) => {
+                const l = html.querySelector(`.filter-title[for="${key}"]`).parentElement;
+                if (key.indexOf('date') != -1) {
+                    l.querySelector(`#${key}_pref`).value = filterAssiduites.filters[key].pref;
+                    l.querySelector(`#${key}_time`).value = filterAssiduites.filters[key].time.format("YYYY-MM-DDTHH:mm");
+
+                } else if (key.indexOf('etat') != -1) {
+                    l.querySelectorAll('input').forEach((e) => {
+                        e.checked = filterAssiduites.filters[key].includes(e.value)
+                    })
+                } else if (key.indexOf("module") != -1) {
+                    l.querySelector('#moduleimpl_id').value = filterAssiduites.filters[key];
+                } else if (key.indexOf("est_just") != -1) {
+                    l.querySelector('#est_just').value = filterAssiduites.filters[key];
+                }
+            })
+
+            openPromptModal("Filtrage des assiduités", html, () => {
+
+                const columns = [...document.querySelectorAll('.chk')]
+                    .map((el) => { if (el.checked) return el.id })
+                    .filter((el) => el)
+
+                filterAssiduites.columns = columns
+                filterAssiduites.filters = {}
+                //reste des filtres
+
+                const lines = [...document.querySelectorAll('.filter-line')];
+
+                lines.forEach((l) => {
+                    const key = l.querySelector('.filter-title').getAttribute('for');
+
+                    if (key.indexOf('date') != -1) {
+                        const pref = l.querySelector(`#${key}_pref`).value;
+                        const time = l.querySelector(`#${key}_time`).value;
+                        if (l.querySelector(`#${key}_time`).value != "") {
+                            filterAssiduites.filters[key] = {
+                                pref: pref,
+                                time: new moment.tz(time, TIMEZONE)
+                            }
+                        }
+                    } else if (key.indexOf('etat') != -1) {
+                        filterAssiduites.filters[key] = [...l.querySelectorAll("input:checked")].map((e) => e.value);
+                    } else if (key.indexOf("module") != -1) {
+                        filterAssiduites.filters[key] = l.querySelector('#moduleimpl_id').value;
+                    } else if (key.indexOf("est_just") != -1) {
+                        filterAssiduites.filters[key] = l.querySelector('#est_just').value;
+                    }
+                })
+
+
+                getAllAssiduitesFromEtud(etudid, assiduiteCallBack)
+
+            }, () => { }, "#7059FF");
+        } else {
+            let html = `
+                    <div class="filter-body">
+                        <h3>Affichage des colonnes:</h3>
+                        <div class="filter-head">
+                            <label>
+                                Date de saisie
+                                <input class="chk" type="checkbox" name="entry_date" id="entry_date">
+                            </label>
+                            <label>
+                                Date de Début
+                                <input class="chk" type="checkbox" name="date_debut" id="date_debut" checked>
+                            </label>
+                            <label>
+                                Date de Fin
+                                <input class="chk" type="checkbox" name="date_fin" id="date_fin" checked>
+                            </label>
+                            <label>
+                                Etat
+                                <input class="chk" type="checkbox" name="etat" id="etat" checked>
+                            </label>
+                            <label>
+                                Raison
+                                <input class="chk" type="checkbox" name="raison" id="raison" checked>
+                            </label>
+                        </div>
+                        <hr>
+                        <h3>Filtrage des colonnes:</h3>
+                        <span class="filter-line">
+                            <span class="filter-title" for="entry_date">Date de saisie</span>
+                            <select name="entry_date_pref" id="entry_date_pref">
+                                <option value="-1">Avant</option>
+                                <option value="0">Égal</option>
+                                <option value="1">Après</option>
+                            </select>
+                            <input type="datetime-local" name="entry_date_time" id="entry_date_time">
+                        </span>
+                        <span class="filter-line">
+                            <span class="filter-title" for="date_debut">Date de début</span>
+                            <select name="date_debut_pref" id="date_debut_pref">
+                                <option value="-1">Avant</option>
+                                <option value="0">Égal</option>
+                                <option value="1">Après</option>
+                            </select>
+                            <input type="datetime-local" name="date_debut_time" id="date_debut_time">
+                        </span>
+                        <span class="filter-line">
+                            <span class="filter-title" for="date_fin">Date de fin</span>
+                            <select name="date_fin_pref" id="date_fin_pref">
+                                <option value="-1">Avant</option>
+                                <option value="0">Égal</option>
+                                <option value="1">Après</option>
+                            </select>
+                            <input type="datetime-local" name="date_fin_time" id="date_fin_time">
+                        </span>
+                        <span class="filter-line">
+                            <span class="filter-title" for="etat">Etat</span>
+                            <label>
+                                Valide
+                                <input checked type="checkbox" name="etat_valide" id="etat_valide" class="" value="valide">
+                            </label>
+                            <label>
+                                Non Valide
+                                <input checked type="checkbox" name="etat_valide" id="etat_valide" class="" value="non_valide">
+                            </label>
+                            <label>
+                                En Attente
+                                <input checked type="checkbox" name="etat_valide" id="etat_valide" class="" value="attente">
+                            </label>
+                            <label>
+                                Modifié
+                                <input checked type="checkbox" name="etat_valide" id="etat_valide" class="" value="modifie">
+                            </label>
+                        </span>
+                    </div>
+            `;
+            const span = document.createElement('span');
+            span.innerHTML = html
+            html = span.firstElementChild
+
+            const filterHead = html.querySelector('.filter-head');
+            filterHead.innerHTML = ""
+            let cols = ["entry_date", "date_debut", "date_fin", "etat", "raison"];
+
+            cols.forEach((k) => {
+                const label = document.createElement('label')
+                label.classList.add('f-label')
+                const s = document.createElement('span');
+                s.textContent = columnTranslator(k);
+
+
+                const input = document.createElement('input');
+                input.classList.add('chk')
+                input.type = "checkbox"
+                input.name = k
+                input.id = k;
+                input.checked = filterJustificatifs.columns.includes(k)
+
+                label.appendChild(s)
+                label.appendChild(input)
+                filterHead.appendChild(label)
+            })
+
+            // Mise à jour des filtres
+
+            Object.keys(filterJustificatifs.filters).forEach((key) => {
+                const l = html.querySelector(`.filter-title[for="${key}"]`).parentElement;
+                if (key.indexOf('date') != -1) {
+                    l.querySelector(`#${key}_pref`).value = filterJustificatifs.filters[key].pref;
+                    l.querySelector(`#${key}_time`).value = filterJustificatifs.filters[key].time.format("YYYY-MM-DDTHH:mm");
+
+                } else if (key.indexOf('etat') != -1) {
+                    l.querySelectorAll('input').forEach((e) => {
+                        e.checked = filterJustificatifs.filters[key].includes(e.value)
+                    })
+                }
+            })
+
+            openPromptModal("Filtrage des Justificatifs", html, () => {
+
+                const columns = [...document.querySelectorAll('.chk')]
+                    .map((el) => { if (el.checked) return el.id })
+                    .filter((el) => el)
+
+                filterJustificatifs.columns = columns
+                filterJustificatifs.filters = {}
+                //reste des filtres
+
+                const lines = [...document.querySelectorAll('.filter-line')];
+
+                lines.forEach((l) => {
+                    const key = l.querySelector('.filter-title').getAttribute('for');
+
+                    if (key.indexOf('date') != -1) {
+                        const pref = l.querySelector(`#${key}_pref`).value;
+                        const time = l.querySelector(`#${key}_time`).value;
+                        if (l.querySelector(`#${key}_time`).value != "") {
+                            filterJustificatifs.filters[key] = {
+                                pref: pref,
+                                time: new moment.tz(time, TIMEZONE)
+                            }
+                        }
+                    } else if (key.indexOf('etat') != -1) {
+                        filterJustificatifs.filters[key] = [...l.querySelectorAll("input:checked")].map((e) => e.value);
+                    }
+                })
+
+
+                getAllJustificatifsFromEtud(etudid, justificatifCallBack)
+
+            }, () => { }, "#7059FF");
+        }
+    }
+
+    function columnTranslator(colName) {
+        switch (colName) {
+            case "date_debut":
+                return "Début";
+            case "entry_date":
+                return "Saisie le";
+            case "date_fin":
+                return "Fin";
+            case "etat":
+                return "État";
+            case "moduleimpl_id":
+                return "Module";
+            case "est_just":
+                return "Justifiée";
+            case "raison":
+                return "Raison";
+        }
+    }
+
     window.onload = () => {
         loadAll();
     }