From 760e4d4f78805b2e952135281e094482a1049493 Mon Sep 17 00:00:00 2001 From: theShlavuk Date: Wed, 21 Jan 2026 23:24:07 +0100 Subject: [PATCH] =?UTF-8?q?am=C3=A9lioration=20capacit=C3=A9=20traductions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/Event_Controller.php | 25 ++++ app/models/Event_Model.php | 64 ++++++++++ assets/js/modules/agenda-api.js | 9 ++ assets/js/modules/agenda-visual-filters.js | 136 ++++++++++++++++++++- 4 files changed, 232 insertions(+), 2 deletions(-) diff --git a/app/controllers/Event_Controller.php b/app/controllers/Event_Controller.php index bee3147..5f20726 100644 --- a/app/controllers/Event_Controller.php +++ b/app/controllers/Event_Controller.php @@ -93,6 +93,11 @@ class CRVI_Event_Controller { 'callback' => [self::class, 'get_statuts'], 'permission_callback' => '__return_true', ]); + \register_rest_route('crvi/v1', '/filters/traductions-capacites', [ + 'methods' => 'GET', + 'callback' => [self::class, 'get_traductions_capacites'], + 'permission_callback' => '__return_true', + ]); // --- Historique bénéficiaire --- \register_rest_route('crvi/v1', '/beneficiaires/(?P\\d+)/historique', [ @@ -1920,6 +1925,26 @@ class CRVI_Event_Controller { return Api_Helper::json_success($statuts); } + /** + * Récupère les capacités de traduction avec une plage de dates + * GET /crvi/v1/filters/traductions-capacites?date_debut=2025-01-01&date_fin=2025-01-31 + */ + public static function get_traductions_capacites($request) { + $params = $request->get_params(); + $date_debut = $params['date_debut'] ?? null; + $date_fin = $params['date_fin'] ?? null; + + // Vérifier que la classe du modèle existe + if (!class_exists('\ESI_CRVI_AGENDA\models\CRVI_TraductionLangue_Model')) { + return Api_Helper::json_error('Modèle de traduction non disponible', 500); + } + + // Utiliser la méthode du modèle qui gère le cache avec la plage de dates + $capacites = \ESI_CRVI_AGENDA\models\CRVI_TraductionLangue_Model::getAllLanguesCapacitesForACF($date_debut, $date_fin, true); + + return Api_Helper::json_success($capacites); + } + /** * Vérifie si l'utilisateur peut modifier un événement * @param \WP_REST_Request $request diff --git a/app/models/Event_Model.php b/app/models/Event_Model.php index b2760f8..facb92d 100644 --- a/app/models/Event_Model.php +++ b/app/models/Event_Model.php @@ -1172,6 +1172,25 @@ class CRVI_Event_Model extends Main_Model { $where = []; $values = []; + // Traitement spécial pour le filtre langue (inclure les permanences avec langues_disponibles) + $langue_filter_value = null; + $langue_slug = null; + if (!empty($params['langue']) || (isset($params['langue']) && $params['langue'] === '0')) { + $langue_filter_value = $params['langue']; + + // Essayer d'obtenir le slug de la langue à partir de l'ID + $langue_term = get_term((int)$langue_filter_value, 'langue'); + if ($langue_term && !is_wp_error($langue_term)) { + $langue_slug = $langue_term->slug; + } else { + // Si ce n'est pas un ID, essayer comme slug directement + $langue_term = get_term_by('slug', $langue_filter_value, 'langue'); + if ($langue_term && !is_wp_error($langue_term)) { + $langue_slug = $langue_term->slug; + } + } + } + // Traitement des filtres foreach ($map as $api => $col) { if (!empty($params[$api]) || (isset($params[$api]) && $params[$api] === '0')) { @@ -1185,6 +1204,19 @@ class CRVI_Event_Model extends Main_Model { // Support du filtre assign (0 ou 1) $where[] = "$col = %d"; $values[] = (int)$params[$api]; + } elseif ($api === 'langue') { + // Filtre langue spécial : inclure les rendez-vous avec cette langue + // ET les permanences avec cette langue dans langues_disponibles + if ($langue_slug) { + // Inclure les événements avec langue = ID OU les permanences avec langues_disponibles contenant le slug + $where[] = "($col = %s OR (type = 'permanence' AND langues_disponibles LIKE %s))"; + $values[] = $langue_filter_value; + $values[] = '%' . $wpdb->esc_like($langue_slug) . '%'; + } else { + // Fallback : comportement normal si on ne trouve pas le slug + $where[] = "$col = %s"; + $values[] = $langue_filter_value; + } } else { $where[] = "$col = %s"; $values[] = $params[$api]; @@ -1471,6 +1503,25 @@ class CRVI_Event_Model extends Main_Model { $where = []; $values = []; + // Traitement spécial pour le filtre langue (inclure les permanences avec langues_disponibles) + $langue_filter_value = null; + $langue_slug = null; + if (!empty($params['langue']) || (isset($params['langue']) && $params['langue'] === '0')) { + $langue_filter_value = $params['langue']; + + // Essayer d'obtenir le slug de la langue à partir de l'ID + $langue_term = get_term((int)$langue_filter_value, 'langue'); + if ($langue_term && !is_wp_error($langue_term)) { + $langue_slug = $langue_term->slug; + } else { + // Si ce n'est pas un ID, essayer comme slug directement + $langue_term = get_term_by('slug', $langue_filter_value, 'langue'); + if ($langue_term && !is_wp_error($langue_term)) { + $langue_slug = $langue_term->slug; + } + } + } + // Traitement des filtres foreach ($map as $api => $col) { if (!empty($params[$api]) || (isset($params[$api]) && $params[$api] === '0')) { @@ -1483,6 +1534,19 @@ class CRVI_Event_Model extends Main_Model { } elseif ($api === 'assign') { $where[] = "$col = %d"; $values[] = (int)$params[$api]; + } elseif ($api === 'langue') { + // Filtre langue spécial : inclure les rendez-vous avec cette langue + // ET les permanences avec cette langue dans langues_disponibles + if ($langue_slug) { + // Inclure les événements avec langue = ID OU les permanences avec langues_disponibles contenant le slug + $where[] = "($col = %s OR (type = 'permanence' AND langues_disponibles LIKE %s))"; + $values[] = $langue_filter_value; + $values[] = '%' . $wpdb->esc_like($langue_slug) . '%'; + } else { + // Fallback : comportement normal si on ne trouve pas le slug + $where[] = "$col = %s"; + $values[] = $langue_filter_value; + } } else { $where[] = "$col = %s"; $values[] = $params[$api]; diff --git a/assets/js/modules/agenda-api.js b/assets/js/modules/agenda-api.js index d249062..15afed6 100644 --- a/assets/js/modules/agenda-api.js +++ b/assets/js/modules/agenda-api.js @@ -97,4 +97,13 @@ export async function getFilters(type, params = {}) { return apiFetch(endpoint); } return apiFetch(`filters/${type}`); +} + +export async function getTraductionsCapacites(date_debut, date_fin) { + const params = {}; + if (date_debut) params.date_debut = date_debut; + if (date_fin) params.date_fin = date_fin; + const query = new URLSearchParams(params).toString(); + const endpoint = `filters/traductions-capacites${query ? '?' + query : ''}`; + return apiFetch(endpoint); } \ No newline at end of file diff --git a/assets/js/modules/agenda-visual-filters.js b/assets/js/modules/agenda-visual-filters.js index acfbf96..e64c615 100644 --- a/assets/js/modules/agenda-visual-filters.js +++ b/assets/js/modules/agenda-visual-filters.js @@ -3,12 +3,17 @@ * Filtres par département et capacités de traduction */ +import { getTraductionsCapacites } from './agenda-api.js'; + class AgendaVisualFilters { constructor() { this.departements = window.crviACFData?.departements || {}; this.traductions = window.crviACFData?.traductions_capacites || {}; this.selectedDepartement = null; this.selectedTraduction = null; + this.currentDateDebut = null; + this.currentDateFin = null; + this.calendarInstance = null; this.departementsContainer = document.getElementById('departements-filter-buttons'); this.traductionsContainer = document.getElementById('traductions-filter-buttons'); @@ -22,6 +27,41 @@ class AgendaVisualFilters { this.renderDepartementsButtons(); this.renderTraductionsButtons(); this.setupEventListeners(); + + // Initialiser les dates depuis le calendrier si disponible + this.initializeDatesFromCalendar(); + } + + /** + * Initialise les dates depuis le calendrier au chargement + */ + initializeDatesFromCalendar() { + // Attendre que le calendrier soit disponible + const checkCalendar = () => { + if (window.currentCalendar) { + try { + const view = window.currentCalendar.view; + if (view && view.activeStart && view.activeEnd) { + const startStr = view.activeStart.toISOString().split('T')[0]; + const endStr = view.activeEnd.toISOString().split('T')[0]; + this.currentDateDebut = startStr; + this.currentDateFin = endStr; + console.log('📅 Dates initiales du calendrier:', { start: startStr, end: endStr }); + + // Recharger les capacités pour cette période initiale + this.reloadTraductionsCapacites(startStr, endStr); + } + } catch (error) { + console.warn('⚠️ Impossible de récupérer les dates initiales du calendrier:', error); + } + } else { + // Réessayer après un court délai + setTimeout(checkCalendar, 200); + } + }; + + // Attendre un peu plus longtemps pour que le calendrier soit complètement initialisé + setTimeout(checkCalendar, 500); } /** @@ -220,8 +260,15 @@ class AgendaVisualFilters { if (filters.traduction) { const langueSelect = document.getElementById('langue_filtre'); if (langueSelect) { - // La valeur doit correspondre au slug de la langue - langueSelect.value = filters.traduction; + // Récupérer l'ID de la langue depuis les données de traduction + const traductionData = this.traductions[filters.traduction]; + if (traductionData && traductionData.id) { + // Utiliser l'ID de la langue pour le filtre + langueSelect.value = traductionData.id; + } else { + // Fallback : utiliser le slug si l'ID n'est pas disponible + langueSelect.value = filters.traduction; + } } } else { const langueSelect = document.getElementById('langue_filtre'); @@ -265,6 +312,91 @@ class AgendaVisualFilters { this.renderTraductionsButtons(); }); } + + // Écouter les changements de vue/dates de FullCalendar + this.setupCalendarListeners(); + } + + /** + * Configure les écouteurs pour les changements de vue/dates du calendrier + */ + setupCalendarListeners() { + // Attendre que le calendrier soit disponible + const checkCalendar = () => { + if (window.currentCalendar) { + this.calendarInstance = window.currentCalendar; + + // Écouter l'événement datesSet de FullCalendar (déclenché lors des changements de dates/vue) + this.calendarInstance.on('datesSet', (arg) => { + this.handleCalendarDatesChange(arg); + }); + + console.log('✅ Écouteur datesSet configuré pour les filtres visuels'); + } else { + // Réessayer après un court délai + setTimeout(checkCalendar, 100); + } + }; + + checkCalendar(); + } + + /** + * Gère les changements de dates/vue du calendrier + */ + async handleCalendarDatesChange(arg) { + const startStr = arg.startStr.split('T')[0]; + const endStr = arg.endStr.split('T')[0]; + + // Vérifier si les dates ont vraiment changé + if (this.currentDateDebut === startStr && this.currentDateFin === endStr) { + return; // Pas de changement, ne rien faire + } + + this.currentDateDebut = startStr; + this.currentDateFin = endStr; + + console.log('📅 Changement de dates/vue détecté:', { start: startStr, end: endStr, view: arg.view.type }); + + // Recharger les capacités de traduction pour la nouvelle période + await this.reloadTraductionsCapacites(startStr, endStr); + } + + /** + * Recharge les capacités de traduction pour une période donnée + */ + async reloadTraductionsCapacites(date_debut, date_fin) { + try { + console.log('🔄 Rechargement des capacités de traduction pour:', { date_debut, date_fin }); + + const capacites = await getTraductionsCapacites(date_debut, date_fin); + + if (capacites && typeof capacites === 'object') { + this.traductions = capacites; + + // Sauvegarder la sélection actuelle + const currentSelection = this.selectedTraduction; + + // Re-rendre les boutons avec les nouvelles données + this.renderTraductionsButtons(); + + // Restaurer la sélection si elle existe toujours + if (currentSelection && this.traductions[currentSelection]) { + this.selectedTraduction = currentSelection; + const btnId = `trad-${currentSelection}`; + const activeBtn = document.getElementById(btnId); + if (activeBtn) { + activeBtn.classList.add('active'); + } + } + + console.log('✅ Capacités de traduction mises à jour'); + } else { + console.warn('⚠️ Aucune donnée de capacité reçue'); + } + } catch (error) { + console.error('❌ Erreur lors du rechargement des capacités:', error); + } } /**