diff --git a/loko/interventions/locale/en/LC_MESSAGES/django.mo b/loko/interventions/locale/en/LC_MESSAGES/django.mo index 0b01a19..f52a5cf 100644 Binary files a/loko/interventions/locale/en/LC_MESSAGES/django.mo and b/loko/interventions/locale/en/LC_MESSAGES/django.mo differ diff --git a/loko/interventions/locale/en/LC_MESSAGES/django.po b/loko/interventions/locale/en/LC_MESSAGES/django.po index 60739d0..5f26f5a 100644 --- a/loko/interventions/locale/en/LC_MESSAGES/django.po +++ b/loko/interventions/locale/en/LC_MESSAGES/django.po @@ -8407,5 +8407,29 @@ msgstr "Cannot modify material from a canceled preparation order." msgid "Bon annulé" msgstr "Canceled order" +msgid "Rôle et personne assignée" +msgstr "Role and assigned person" + +msgid "Rôle" +msgstr "Role" + +msgid "Personne" +msgstr "Person" + +msgid "Gestionnaire" +msgstr "Manager" + +msgid "Contrôleur" +msgstr "Controller" + +msgid "Inspecteur" +msgstr "Inspector" + +msgid "-- Sélectionner un rôle… --" +msgstr "-- Select a role… --" + +msgid "-- Choisir une personne… --" +msgstr "-- Choose a person… --" + diff --git a/loko/interventions/locale/fr/LC_MESSAGES/django.mo b/loko/interventions/locale/fr/LC_MESSAGES/django.mo index fa58b7e..c399862 100644 Binary files a/loko/interventions/locale/fr/LC_MESSAGES/django.mo and b/loko/interventions/locale/fr/LC_MESSAGES/django.mo differ diff --git a/loko/interventions/locale/fr/LC_MESSAGES/django.po b/loko/interventions/locale/fr/LC_MESSAGES/django.po index de19591..afd6c54 100644 --- a/loko/interventions/locale/fr/LC_MESSAGES/django.po +++ b/loko/interventions/locale/fr/LC_MESSAGES/django.po @@ -8514,5 +8514,29 @@ msgstr "Impossible de modifier le matériel d'un bon de préparation annulé." msgid "Bon annulé" msgstr "Bon annulé" +msgid "Rôle et personne assignée" +msgstr "Rôle et personne assignée" + +msgid "Rôle" +msgstr "Rôle" + +msgid "Personne" +msgstr "Personne" + +msgid "Gestionnaire" +msgstr "Gestionnaire" + +msgid "Contrôleur" +msgstr "Contrôleur" + +msgid "Inspecteur" +msgstr "Inspecteur" + +msgid "-- Sélectionner un rôle… --" +msgstr "-- Sélectionner un rôle… --" + +msgid "-- Choisir une personne… --" +msgstr "-- Choisir une personne… --" + diff --git a/loko/interventions/locale/nl/LC_MESSAGES/django.mo b/loko/interventions/locale/nl/LC_MESSAGES/django.mo index e7bf0ab..30f0851 100644 Binary files a/loko/interventions/locale/nl/LC_MESSAGES/django.mo and b/loko/interventions/locale/nl/LC_MESSAGES/django.mo differ diff --git a/loko/interventions/locale/nl/LC_MESSAGES/django.po b/loko/interventions/locale/nl/LC_MESSAGES/django.po index bb35d8d..fb4b5b1 100644 --- a/loko/interventions/locale/nl/LC_MESSAGES/django.po +++ b/loko/interventions/locale/nl/LC_MESSAGES/django.po @@ -8448,4 +8448,28 @@ msgstr "Kan materiaal van een geannuleerde voorbereidingsbon niet wijzigen." msgid "Bon annulé" msgstr "Geannuleerde bon" +msgid "Rôle et personne assignée" +msgstr "Rol en toegewezen persoon" + +msgid "Rôle" +msgstr "Rol" + +msgid "Personne" +msgstr "Persoon" + +msgid "Gestionnaire" +msgstr "Beheerder" + +msgid "Contrôleur" +msgstr "Controleur" + +msgid "Inspecteur" +msgstr "Inspecteur" + +msgid "-- Sélectionner un rôle… --" +msgstr "-- Selecteer een rol… --" + +msgid "-- Choisir une personne… --" +msgstr "-- Kies een persoon… --" + diff --git a/loko/interventions/static/interventions/interventions_index.js b/loko/interventions/static/interventions/interventions_index.js index 8f8c25c..d9656e4 100644 --- a/loko/interventions/static/interventions/interventions_index.js +++ b/loko/interventions/static/interventions/interventions_index.js @@ -330,6 +330,7 @@ document.getElementById('reset-filters').addEventListener('click', async functio togglePauseReasonFilter(); filterCategoriesByThematics(); filterProvidersAndContracts(); + resetRolePersonFilter(); // Explicitly clear date fields document.getElementById('begin_date_min').value = ''; @@ -2185,8 +2186,8 @@ function filterProvidersAndContracts() { } }); } - if (typeof updateInterventionManagers === 'function') { - updateInterventionManagers(); + if (typeof updateRolePersonManagers === 'function') { + updateRolePersonManagers(); } } @@ -2278,7 +2279,9 @@ function countActiveFilters() { 'contract': false, 'assigned_team': false, 'assigned_member': false, + 'assigned_controller': false, 'intervention_manager': false, + 'inspector': false, 'pause_reason': false, 'begin_date_min': false, 'begin_date_max': false, @@ -2330,7 +2333,8 @@ function getCurrentFilters() { // Get all filter parameters const filterKeys = [ 'thematic', 'status', 'priority', 'maintain_type', 'category', - 'type', 'provider', 'contract', 'assigned_team', 'assigned_member', 'intervention_manager', + 'type', 'provider', 'contract', 'assigned_team', 'assigned_member', + 'assigned_controller', 'intervention_manager', 'inspector', 'pause_reason', 'locations', 'overdue', 'to_be_planned_soon' ]; @@ -2407,7 +2411,8 @@ function countActiveFilters() { // Define filter parameters used in the global filter modal const filterParams = [ 'thematic', 'status', 'priority', 'maintain_type', 'category', 'type', - 'provider', 'contract', 'assigned_team', 'assigned_member', 'intervention_manager', 'pause_reason', + 'provider', 'contract', 'assigned_team', 'assigned_member', + 'assigned_controller', 'intervention_manager', 'inspector', 'pause_reason', 'begin_date_min', 'begin_date_max', 'end_date_min', 'end_date_max', 'locations', 'overdue', 'to_be_planned_soon' ]; @@ -2451,7 +2456,8 @@ function savePreferencesFromUrl() { // Collect all filter parameters const filterParams = [ 'thematic', 'status', 'priority', 'maintain_type', 'category', 'type', - 'provider', 'contract', 'assigned_team', 'assigned_member', 'intervention_manager', 'pause_reason', + 'provider', 'contract', 'assigned_team', 'assigned_member', + 'assigned_controller', 'intervention_manager', 'inspector', 'pause_reason', 'begin_date_min', 'begin_date_max', 'end_date_min', 'end_date_max', 'locations', 'overdue', 'to_be_planned_soon' ]; @@ -2504,7 +2510,8 @@ async function savePreferencesFromForm(urlParams) { // Collect all filter parameters from URLSearchParams const filterParams = [ 'thematic', 'status', 'priority', 'maintain_type', 'category', 'type', - 'provider', 'contract', 'assigned_team', 'assigned_member', 'intervention_manager', 'pause_reason', + 'provider', 'contract', 'assigned_team', 'assigned_member', + 'assigned_controller', 'intervention_manager', 'inspector', 'pause_reason', 'begin_date_min', 'begin_date_max', 'end_date_min', 'end_date_max', 'locations', 'overdue', 'to_be_planned_soon' ]; @@ -2558,6 +2565,7 @@ async function savePreferencesFromForm(urlParams) { document.addEventListener('DOMContentLoaded', function() { updateFilterBadge(); initDateFilterPresets(); + initRolePersonFilter(); // Save preferences when table sort changes (user action only) const $table = $('#interventions-table'); @@ -2637,62 +2645,153 @@ if (filterModal) { }); } -function updateInterventionManagers() { - const checkedContracts = document.querySelectorAll('.filter-options[data-field="contract"] input[type="checkbox"]:checked'); - const container = document.getElementById('intervention-manager-options-container'); - const row = document.getElementById('intervention-manager-filter-row'); - if (!container || !row) return; +// ==================== Role & Person Filter (Gestionnaire / Contrôleur / Inspecteur) ==================== - // Get currently selected managers from URL or from checkboxes if they already exist - const urlParams = new URLSearchParams(window.location.search); - const selectedManagers = new Set(urlParams.getAll('intervention_manager')); - - // Also check if any are currently checked in the UI before re-drawing - const existingChecked = container.querySelectorAll('input[type="checkbox"]:checked'); - existingChecked.forEach(cb => selectedManagers.add(cb.value)); +function getRolePersonsData() { + const scriptEl = document.getElementById('role-persons-data'); + if (!scriptEl) return { manager: [], controller: [], inspector: [] }; + try { + return JSON.parse(scriptEl.textContent) || { manager: [], controller: [], inspector: [] }; + } catch (e) { + console.error("Error parsing role-persons data", e); + return { manager: [], controller: [], inspector: [] }; + } +} - // Gather unique managers - const managersMap = new Map(); - let anyUsesManager = false; +function syncRolePersonHiddenInputs() { + const roleSelect = document.getElementById('filter-person-role'); + const personSelect = document.getElementById('filter-person-select'); + const hiddenMgr = document.getElementById('hidden-filter-intervention-manager'); + const hiddenCtrl = document.getElementById('hidden-filter-assigned-controller'); + const hiddenInsp = document.getElementById('hidden-filter-inspector'); - checkedContracts.forEach(cb => { - const optionDiv = cb.closest('.filter-option'); - if (optionDiv) { - const usesManager = optionDiv.getAttribute('data-uses-manager') === 'true'; - if (usesManager) { - anyUsesManager = true; - const managersStr = optionDiv.getAttribute('data-managers'); - if (managersStr) { - try { - const managers = JSON.parse(managersStr); - managers.forEach(mgr => { - managersMap.set(String(mgr.id), mgr.name); - }); - } catch (e) { - console.error("Error parsing managers JSON", e); - } + if (!roleSelect || !personSelect) return; + + const role = roleSelect.value; + const personId = personSelect.value; + + if (hiddenMgr) hiddenMgr.value = (role === 'manager' && personId) ? personId : ''; + if (hiddenCtrl) hiddenCtrl.value = (role === 'controller' && personId) ? personId : ''; + if (hiddenInsp) hiddenInsp.value = (role === 'inspector' && personId) ? personId : ''; +} + +function populatePersonSelect(role, preselectedId) { + const personSelect = document.getElementById('filter-person-select'); + if (!personSelect) return; + + const chooseLabel = typeof gettext === 'function' ? gettext("-- Choisir une personne… --") : "-- Choisir une personne… --"; + personSelect.innerHTML = ``; + + if (!role) { + personSelect.disabled = true; + syncRolePersonHiddenInputs(); + return; + } + + const data = getRolePersonsData(); + let persons = data[role] || []; + + // If role is manager, filter by checked contracts if any are checked + if (role === 'manager') { + const checkedContractBoxes = document.querySelectorAll('.filter-options[data-field="contract"] input[type="checkbox"]:checked'); + if (checkedContractBoxes.length > 0) { + const checkedContractIds = Array.from(checkedContractBoxes).map(cb => parseInt(cb.value, 10)).filter(Boolean); + if (checkedContractIds.length > 0) { + const filtered = persons.filter(p => { + const pContracts = (p.contracts || []).map(cid => parseInt(cid, 10)); + return pContracts.some(cid => checkedContractIds.includes(cid)); + }); + if (filtered.length > 0) { + persons = filtered; } } } + } + + persons.forEach(p => { + const opt = document.createElement('option'); + opt.value = p.id; + opt.textContent = p.name; + if (preselectedId && String(p.id) === String(preselectedId)) { + opt.selected = true; + } + personSelect.appendChild(opt); }); - if (anyUsesManager && managersMap.size > 0) { - // Build the HTML for options - let html = ''; - managersMap.forEach((name, id) => { - const isChecked = selectedManagers.has(id) ? 'checked' : ''; - html += ` -