feat: improve assessments filters
This commit is contained in:
223
static/js/simple-filters.js
Normal file
223
static/js/simple-filters.js
Normal file
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
* Système de Filtres Simplifié pour Notytex
|
||||
* Interface cohérente avec le design system existant
|
||||
*/
|
||||
|
||||
class SimpleFilters {
|
||||
constructor() {
|
||||
this.currentFilters = {};
|
||||
this.totalItems = 0;
|
||||
this.filteredItems = 0;
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
// Charger les filtres depuis l'URL
|
||||
this.loadFiltersFromURL();
|
||||
|
||||
// Attacher les événements
|
||||
this.attachEvents();
|
||||
|
||||
// Initialiser l'état visuel
|
||||
this.updateUI();
|
||||
|
||||
console.log('SimpleFilters initialized');
|
||||
}
|
||||
|
||||
attachEvents() {
|
||||
// Tous les boutons de filtres
|
||||
document.querySelectorAll('.filter-btn').forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
this.handleButtonFilter(btn.dataset.filter, btn.dataset.value);
|
||||
});
|
||||
});
|
||||
|
||||
// Bouton reset
|
||||
const resetBtn = document.getElementById('reset-filters');
|
||||
if (resetBtn) {
|
||||
resetBtn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
this.resetAllFilters();
|
||||
});
|
||||
}
|
||||
|
||||
// Suppression de tags individuels
|
||||
document.addEventListener('click', (e) => {
|
||||
if (e.target.classList.contains('remove-filter-tag')) {
|
||||
e.preventDefault();
|
||||
const filterType = e.target.dataset.filter;
|
||||
this.removeFilter(filterType);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
handleButtonFilter(filterType, value) {
|
||||
// Mettre à jour visuellement tous les boutons de ce type
|
||||
document.querySelectorAll(`[data-filter="${filterType}"]`).forEach(btn => {
|
||||
this.resetButtonStyle(btn, filterType);
|
||||
});
|
||||
|
||||
// Activer le bouton sélectionné
|
||||
const activeBtn = document.querySelector(`[data-filter="${filterType}"][data-value="${value}"]`);
|
||||
if (activeBtn) {
|
||||
this.activateButton(activeBtn, filterType);
|
||||
}
|
||||
|
||||
// Mettre à jour le filtre
|
||||
if (value) {
|
||||
this.currentFilters[filterType] = value;
|
||||
} else {
|
||||
delete this.currentFilters[filterType];
|
||||
}
|
||||
|
||||
this.applyFilters();
|
||||
}
|
||||
|
||||
resetButtonStyle(btn, filterType) {
|
||||
// Supprimer toutes les classes actives
|
||||
btn.classList.remove('bg-blue-600', 'text-white', 'border-blue-600');
|
||||
btn.classList.remove('bg-red-500', 'text-white', 'border-red-500');
|
||||
btn.classList.remove('bg-orange-500', 'text-white', 'border-orange-500');
|
||||
btn.classList.remove('bg-green-500', 'text-white', 'border-green-500');
|
||||
|
||||
// Appliquer le style par défaut selon le type
|
||||
if (filterType === 'correction' && btn.dataset.value === 'not_started') {
|
||||
btn.classList.add('bg-white', 'text-red-600', 'border-red-200', 'hover:bg-red-50');
|
||||
} else if (filterType === 'correction' && btn.dataset.value === 'incomplete') {
|
||||
btn.classList.add('bg-white', 'text-orange-600', 'border-orange-200', 'hover:bg-orange-50');
|
||||
} else if (filterType === 'correction' && btn.dataset.value === 'complete') {
|
||||
btn.classList.add('bg-white', 'text-green-600', 'border-green-200', 'hover:bg-green-50');
|
||||
} else {
|
||||
btn.classList.add('bg-white', 'text-gray-600', 'border-gray-300', 'hover:bg-gray-50');
|
||||
}
|
||||
}
|
||||
|
||||
activateButton(btn, filterType) {
|
||||
// Appliquer le style actif selon le type
|
||||
if (filterType === 'correction' && btn.dataset.value === 'not_started') {
|
||||
btn.classList.add('bg-red-500', 'text-white', 'border-red-500');
|
||||
} else if (filterType === 'correction' && btn.dataset.value === 'incomplete') {
|
||||
btn.classList.add('bg-orange-500', 'text-white', 'border-orange-500');
|
||||
} else if (filterType === 'correction' && btn.dataset.value === 'complete') {
|
||||
btn.classList.add('bg-green-500', 'text-white', 'border-green-500');
|
||||
} else {
|
||||
btn.classList.add('bg-blue-600', 'text-white', 'border-blue-600');
|
||||
}
|
||||
}
|
||||
|
||||
applyFilters() {
|
||||
// Construire les paramètres URL
|
||||
const params = new URLSearchParams();
|
||||
|
||||
Object.keys(this.currentFilters).forEach(key => {
|
||||
params.set(key, this.currentFilters[key]);
|
||||
});
|
||||
|
||||
// Mettre à jour l'URL et recharger
|
||||
const newURL = window.location.pathname + (params.toString() ? '?' + params.toString() : '');
|
||||
window.location.href = newURL;
|
||||
}
|
||||
|
||||
updateUI() {
|
||||
this.updateActiveFilters();
|
||||
}
|
||||
|
||||
updateActiveFilters() {
|
||||
const tagsContainer = document.getElementById('active-filter-tags');
|
||||
const resetBtn = document.getElementById('reset-filters');
|
||||
|
||||
if (!tagsContainer) return;
|
||||
|
||||
// Vider les tags existants
|
||||
tagsContainer.innerHTML = '';
|
||||
|
||||
const hasActiveFilters = Object.keys(this.currentFilters).length > 0;
|
||||
|
||||
if (hasActiveFilters) {
|
||||
// Afficher le bouton reset
|
||||
if (resetBtn) resetBtn.classList.remove('hidden');
|
||||
|
||||
// Créer les tags discrets
|
||||
const filterLabels = {
|
||||
trimester: (value) => `T${value}`,
|
||||
correction: (value) => {
|
||||
const labels = {
|
||||
'not_started': 'Non commencées',
|
||||
'incomplete': 'En cours',
|
||||
'complete': 'Terminées'
|
||||
};
|
||||
return labels[value] || value;
|
||||
},
|
||||
class: (value) => {
|
||||
// Rechercher dans les boutons de classe
|
||||
const classBtn = document.querySelector(`[data-filter="class"][data-value="${value}"]`);
|
||||
return classBtn ? classBtn.textContent : value;
|
||||
}
|
||||
};
|
||||
|
||||
Object.keys(this.currentFilters).forEach(filterType => {
|
||||
const value = this.currentFilters[filterType];
|
||||
const label = filterLabels[filterType] ? filterLabels[filterType](value) : value;
|
||||
|
||||
const tag = document.createElement('span');
|
||||
tag.className = 'px-1 py-0.5 bg-blue-100 text-blue-700 rounded text-xs flex items-center';
|
||||
tag.innerHTML = `
|
||||
${label}
|
||||
<button type="button" class="remove-filter-tag ml-1 text-blue-600 hover:text-blue-800 font-bold" data-filter="${filterType}">×</button>
|
||||
`;
|
||||
tagsContainer.appendChild(tag);
|
||||
});
|
||||
} else {
|
||||
// Masquer le bouton reset
|
||||
if (resetBtn) resetBtn.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
removeFilter(filterType) {
|
||||
delete this.currentFilters[filterType];
|
||||
|
||||
// Réactiver le bouton "Tous/Toutes" pour ce type de filtre
|
||||
this.handleButtonFilter(filterType, '');
|
||||
}
|
||||
|
||||
resetAllFilters() {
|
||||
this.currentFilters = {};
|
||||
|
||||
// Réinitialiser tous les filtres
|
||||
['trimester', 'class', 'correction'].forEach(filterType => {
|
||||
this.handleButtonFilter(filterType, '');
|
||||
});
|
||||
}
|
||||
|
||||
loadFiltersFromURL() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
|
||||
['trimester', 'class', 'correction'].forEach(param => {
|
||||
const value = params.get(param);
|
||||
if (value) {
|
||||
this.currentFilters[param] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Méthode publique pour mettre à jour le nombre d'éléments
|
||||
updateCounts(total, filtered) {
|
||||
this.totalItems = total;
|
||||
this.filteredItems = filtered;
|
||||
|
||||
const countElement = document.getElementById('filtered-count');
|
||||
if (countElement) {
|
||||
countElement.textContent = filtered;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialisation automatique quand le DOM est prêt
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Vérifier si on est sur une page avec des filtres
|
||||
if (document.querySelector('.filter-btn') || document.querySelector('.filter-control')) {
|
||||
window.simpleFilters = new SimpleFilters();
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user