From 8bce5fe21c7533f4b57462df8e3f6d019a9112da Mon Sep 17 00:00:00 2001
From: Tykayn
Date: Fri, 6 Jun 2025 13:26:44 +0200
Subject: [PATCH] up
---
assets/app.js | 408 +-------------------
assets/josm.js | 73 ++++
assets/opening_hours.js | 388 +++++++++++++++++++
assets/utils.js | 26 ++
public/js/app.js | 0
templates/admin/edit.html.twig | 21 +
templates/admin/labourage_results.html.twig | 2 +-
templates/admin/stats.html.twig | 318 +++++----------
templates/base.html.twig | 4 +-
templates/public/closed_commerces.html.twig | 2 +-
templates/public/dashboard.html.twig | 6 +-
templates/public/edit.html.twig | 8 +-
templates/public/latest_changes.html.twig | 4 +-
templates/public/places_with_note.html.twig | 2 +-
14 files changed, 628 insertions(+), 634 deletions(-)
create mode 100644 assets/josm.js
create mode 100644 assets/opening_hours.js
create mode 100644 assets/utils.js
create mode 100644 public/js/app.js
create mode 100644 templates/admin/edit.html.twig
diff --git a/assets/app.js b/assets/app.js
index 37b3322a..907dd017 100644
--- a/assets/app.js
+++ b/assets/app.js
@@ -7,8 +7,10 @@
// any CSS you import will output into a single css file (app.css in this case)
import './styles/app.css';
+import './utils.js';
+import './opening_hours.js';
+import './josm.js';
-console.log('Hello World de app.js');
// Attendre le chargement du DOM
@@ -16,17 +18,8 @@ document.addEventListener('DOMContentLoaded', () => {
console.log('DOMContentLoaded');
- function updateMapHeightForLargeScreens() {
- const map = document.querySelector('#map');
- // Vérifier si on est sur une page avec un titre h1 contenant "statistiques"
- const h1Element = document.querySelector('h1');
- if (h1Element && h1Element.textContent.toLowerCase().includes('statistiques')) {
- if (map && window.innerHeight > 800 && window.innerWidth > 800) {
- map.style.height = '80vh';
- }
- }
- }
+
updateMapHeightForLargeScreens()
@@ -78,11 +71,6 @@ document.addEventListener('DOMContentLoaded', () => {
const randombg = genererCouleurPastel();
// Appliquer la couleur au body
document.body.style.backgroundColor = randombg;
- // Appliquer le style pour .body-landing
- const bodyLanding = document.querySelector('.body-landing');
- if (bodyLanding) {
- bodyLanding.style.backgroundColor = randombg;
- }
// Gestion du bouton pour afficher tous les champs
const btnShowAllFields = document.querySelector('#showAllFields');
@@ -110,394 +98,6 @@ document.addEventListener('DOMContentLoaded', () => {
});
}
-
- const openingHoursFormManager = {
- defaultOpeningHours: '',
- init: function () {
- // Rechercher l'élément par son attribut name plutôt que par son id
- const openingHoursInput = document.querySelector('input[name="custom__opening_hours"]');
- if (!openingHoursInput) {
- console.warn('Élément input[name="custom__opening_hours"] non trouvé');
- return;
- }
- this.defaultOpeningHours = openingHoursInput.value;
-
- this.makeForm();
-
- if (this.defaultOpeningHours !== '') {
- this.parseOpeningHoursValue();
- }
- },
- parseOpeningHoursValue: function () {
- // Analyser la chaîne d'horaires d'ouverture
- const parsedOpeningHours = {};
-
- // Masquer toutes les plages horaires par défaut
- const allDayContainers = document.querySelectorAll('.jour-container');
- allDayContainers.forEach(container => {
- const checkbox = container.querySelector('input[type="checkbox"]');
- const horairesContainer = container.querySelector('.horaires-container');
- checkbox.checked = false;
- horairesContainer.classList.add('d-none');
- });
-
- if (this.defaultOpeningHours) {
- // Diviser les différentes règles (séparées par des points-virgules)
- const rules = this.defaultOpeningHours.split(';').map(r => r.trim());
-
- rules.forEach(rule => {
- // Extraire les jours et les heures
- const [days, hours] = rule.split(' ').filter(Boolean);
-
- // Convertir les jours en français
- const daysMap = {
- 'Mo': 'lundi',
- 'Tu': 'mardi',
- 'We': 'mercredi',
- 'Th': 'jeudi',
- 'Fr': 'vendredi',
- 'Sa': 'samedi',
- 'Su': 'dimanche'
- };
-
- // Gérer les plages de jours (ex: Mo-Fr)
- if (days.includes('-')) {
- const [start, end] = days.split('-');
- const startIndex = Object.keys(daysMap).indexOf(start);
- const endIndex = Object.keys(daysMap).indexOf(end);
-
- for (let i = startIndex; i <= endIndex; i++) {
- const day = daysMap[Object.keys(daysMap)[i]];
- // Cocher la case du jour
- const checkbox = document.querySelector(`#jour-${day}`);
- if (checkbox) {
- checkbox.checked = true;
- checkbox.closest('.jour-container').querySelector('.horaires-container').classList.remove('d-none');
- }
- }
- } else {
- // Jour unique
- const day = daysMap[days];
- const checkbox = document.querySelector(`#jour-${day}`);
- if (checkbox) {
- checkbox.checked = true;
- checkbox.closest('.jour-container').querySelector('.horaires-container').classList.remove('d-none');
- }
- }
- });
- }
-
- console.log(parsedOpeningHours);
- },
- makeForm: function () {
- const customOpeningHours = document.querySelector('input[name="custom__opening_hours"]');
- console.log('makeForm customOpeningHours', customOpeningHours);
-
- if (customOpeningHours) {
- // Créer un conteneur flex pour aligner l'input et le formulaire
- const container = document.createElement('div');
- container.classList.add('d-flex', 'flex-column', 'flex-md-row', 'align-items-start', 'gap-3', 'w-100');
-
- // Créer le formulaire
- const form = document.createElement('form');
- form.id = 'app_public_opening_hours';
- form.classList.add('mt-3', 'flex-grow-1');
-
- // Créer les cases à cocher pour chaque jour
- const jours = ['Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche'];
- const joursDiv = document.createElement('div');
- joursDiv.classList.add('jours-ouverture', 'mb-4', 'row', 'g-3', 'mx-4');
-
- jours.forEach(jour => {
- const jourContainer = document.createElement('div');
- jourContainer.classList.add('jour-container', 'col-12');
-
- // Checkbox pour le jour
- const divCheck = document.createElement('div');
- divCheck.classList.add('form-check', 'mb-2');
-
- const input = document.createElement('input');
- input.type = 'checkbox';
- input.id = `jour-${jour.toLowerCase()}`;
- input.name = `jour-${jour.toLowerCase()}`;
- input.classList.add('form-check-input');
-
- const label = document.createElement('label');
- label.htmlFor = `jour-${jour.toLowerCase()}`;
- label.classList.add('form-check-label');
- label.textContent = jour;
-
- divCheck.appendChild(input);
-
- divCheck.appendChild(label);
- jourContainer.appendChild(divCheck);
-
- // Conteneur pour les plages horaires
- const horairesContainer = document.createElement('div');
- horairesContainer.classList.add('horaires-container', 'ms-4', 'd-none');
-
- // Première plage horaire
- const plage1 = this.createTimeRangeInputs(`${jour.toLowerCase()}-plage1`);
- horairesContainer.appendChild(plage1);
-
- // Séparateur
- const separator = document.createElement('div');
- separator.classList.add('text-center', 'my-2');
- separator.textContent = 'et';
- horairesContainer.appendChild(separator);
-
-
- // Deuxième plage horaire
- const plage2 = this.createTimeRangeInputs(`${jour.toLowerCase()}-plage2`);
- horairesContainer.appendChild(plage2);
-
- jourContainer.appendChild(horairesContainer);
- joursDiv.appendChild(jourContainer);
-
- // Ajouter l'événement pour afficher/masquer les plages horaires
- input.addEventListener('change', (e) => {
- horairesContainer.classList.toggle('d-none', !e.target.checked);
- this.convertToOSMOpeningHours();
- });
- });
-
- form.appendChild(joursDiv);
-
- // Ajouter le formulaire au conteneur
- container.appendChild(form);
-
- // Insérer le conteneur après l'input original
- const parent = customOpeningHours.parentNode;
- if (parent) {
- parent.insertBefore(container, customOpeningHours.nextSibling);
- }
-
- // Ajouter un debounce pour limiter les appels lors des modifications
- const debounce = (func, wait) => {
- let timeout;
- return function executedFunction(...args) {
- const later = () => {
- clearTimeout(timeout);
- func(...args);
- };
- clearTimeout(timeout);
- timeout = setTimeout(later, wait);
- };
- };
-
- // Appliquer le debounce à la fonction de conversion
- const debouncedConvert = debounce(() => {
- this.convertToOSMOpeningHours();
- }, 300);
-
- // Ajouter les listeners sur tous les inputs
- const allInputs = form.querySelectorAll('input');
- allInputs.forEach(input => {
- input.addEventListener('change', debouncedConvert);
- input.addEventListener('input', debouncedConvert);
- });
- } else {
- console.log('pas d input opening hours détecté')
- }
- },
-
- createTimeRangeInputs: function (prefix) {
- const container = document.createElement('div');
- container.classList.add('time-range', 'mb-2');
-
- // Case à cocher pour activer la plage
- const checkboxContainer = document.createElement('div');
- checkboxContainer.classList.add('form-check', 'mb-2');
-
- const checkbox = document.createElement('input');
- checkbox.type = 'checkbox';
- checkbox.id = `${prefix}-active`;
- checkbox.name = `${prefix}-active`;
- checkbox.classList.add('form-check-input');
- checkbox.checked = true;
-
- const checkboxLabel = document.createElement('label');
- checkboxLabel.htmlFor = `${prefix}-active`;
- checkboxLabel.classList.add('form-check-label');
- checkboxLabel.textContent = '';
-
- checkboxContainer.appendChild(checkbox);
- checkboxContainer.appendChild(checkboxLabel);
- container.appendChild(checkboxContainer);
-
- // Conteneur pour les inputs d'horaires
- const timeContainer = document.createElement('div');
- timeContainer.classList.add('ms-4', 'row', 'g-2');
-
- // Heure de début
- const startContainer = document.createElement('div');
- startContainer.classList.add('col-6', 'd-flex', 'align-items-center', 'gap-2');
-
- const startHour = document.createElement('input');
- startHour.type = 'number';
- startHour.min = '0';
- startHour.max = '23';
- startHour.classList.add('form-control', 'form-control-sm');
- startHour.style.width = '60px';
- startHour.placeholder = 'HH';
- startHour.name = `${prefix}-start-hour`;
- // Définir les horaires par défaut selon la plage
- startHour.value = prefix.includes('plage1') ? '08' : '14';
-
- const startMinute = document.createElement('input');
- startMinute.type = 'number';
- startMinute.min = '0';
- startMinute.max = '59';
- startMinute.classList.add('form-control', 'form-control-sm');
- startMinute.style.width = '60px';
- startMinute.placeholder = 'MM';
- startMinute.name = `${prefix}-start-minute`;
- startMinute.value = '00';
-
- // Heure de fin
- const endContainer = document.createElement('div');
- endContainer.classList.add('col-6', 'd-flex', 'align-items-center', 'gap-2');
-
- const endHour = document.createElement('input');
- endHour.type = 'number';
- endHour.min = '0';
- endHour.max = '23';
- endHour.classList.add('form-control', 'form-control-sm');
- endHour.style.width = '60px';
- endHour.placeholder = 'HH';
- endHour.name = `${prefix}-end-hour`;
- // Définir les horaires par défaut selon la plage
- endHour.value = prefix.includes('plage1') ? '12' : '18';
-
- const endMinute = document.createElement('input');
- endMinute.type = 'number';
- endMinute.min = '0';
- endMinute.max = '59';
- endMinute.classList.add('form-control', 'form-control-sm');
- endMinute.style.width = '60px';
- endMinute.placeholder = 'MM';
- endMinute.name = `${prefix}-end-minute`;
- endMinute.value = '00';
-
- // Créer le texte avec les horaires
- const timeText = document.createElement('div');
- timeText.classList.add('d-flex', 'align-items-center', 'gap-2', 'flex-wrap');
-
- // Texte de début
- const startText = document.createElement('span');
- startText.textContent = 'de';
- timeText.appendChild(startText);
- timeText.appendChild(startHour);
- timeText.appendChild(document.createTextNode(':'));
- timeText.appendChild(startMinute);
-
- // Texte du milieu
- const middleText = document.createElement('span');
- middleText.textContent = 'à';
- timeText.appendChild(middleText);
-
- // Texte de fin
- timeText.appendChild(endHour);
- timeText.appendChild(document.createTextNode(':'));
- timeText.appendChild(endMinute);
-
- timeContainer.appendChild(timeText);
- container.appendChild(timeContainer);
-
- // Fonction pour mettre à jour le style des inputs
- const updateInputsStyle = (isActive) => {
- const inputs = timeContainer.querySelectorAll('input');
- inputs.forEach(input => {
- if (isActive) {
- input.classList.remove('bg-light', 'text-muted');
- input.disabled = false;
- } else {
- input.classList.add('bg-light', 'text-muted');
- input.disabled = true;
- }
- });
- };
-
- // Ajouter l'événement sur la checkbox
- checkbox.addEventListener('change', (e) => {
- updateInputsStyle(e.target.checked);
- });
-
- // Appliquer le style initial
- updateInputsStyle(checkbox.checked);
-
- return container;
- },
-
- convertToOSMOpeningHours: function () {
- const jours = {
- 'Lundi': 'Mo',
- 'Mardi': 'Tu',
- 'Mercredi': 'We',
- 'Jeudi': 'Th',
- 'Vendredi': 'Fr',
- 'Samedi': 'Sa',
- 'Dimanche': 'Su'
- };
-
- let joursSelectionnes = [];
- let horairesParJour = {};
-
- // Parcourir les checkboxes des jours
- Object.keys(jours).forEach(jour => {
- const checkbox = document.getElementById(`jour-${jour.toLowerCase()}`);
- if (checkbox && checkbox.checked) {
- joursSelectionnes.push(jours[jour]);
-
- // Récupérer les horaires pour ce jour
- const prefix = jour.toLowerCase();
- const plage1 = this.getTimeRange(`${prefix}-plage1`);
- const plage2 = this.getTimeRange(`${prefix}-plage2`);
-
- let horaires = [];
- if (plage1) horaires.push(plage1);
- if (plage2) horaires.push(plage2);
-
- if (horaires.length > 0) {
- horairesParJour[jours[jour]] = horaires.join(',');
- }
- }
- });
-
- // Construire la chaîne au format OSM
- let osmFormat = '';
- if (joursSelectionnes.length > 0) {
- const horairesStrings = joursSelectionnes.map(jour => {
- return horairesParJour[jour] ? `${jour} ${horairesParJour[jour]}` : jour;
- });
- osmFormat = horairesStrings.join('; ');
- }
-
- // Mettre à jour l'input custom__opening_hours
- const customOpeningHours = document.querySelector('input[name="custom__opening_hours"]');
- if (customOpeningHours) {
- customOpeningHours.value = osmFormat;
- }
- },
-
- getTimeRange: function (prefix) {
- const isActive = document.querySelector(`input[name="${prefix}-active"]`).checked;
- if (!isActive) return null;
-
- const startHour = document.querySelector(`input[name="${prefix}-start-hour"]`).value;
- const startMinute = document.querySelector(`input[name="${prefix}-start-minute"]`).value;
- const endHour = document.querySelector(`input[name="${prefix}-end-hour"]`).value;
- const endMinute = document.querySelector(`input[name="${prefix}-end-minute"]`).value;
-
- if (startHour && startMinute && endHour && endMinute) {
- const start = `${startHour.padStart(2, '0')}:${startMinute.padStart(2, '0')}`;
- const end = `${endHour.padStart(2, '0')}:${endMinute.padStart(2, '0')}`;
- return `${start}-${end}`;
- }
- return null;
- }
- }
-
openingHoursFormManager.init();
diff --git a/assets/josm.js b/assets/josm.js
new file mode 100644
index 00000000..aca7da1c
--- /dev/null
+++ b/assets/josm.js
@@ -0,0 +1,73 @@
+
+
+/**
+ * Ouvre les éléments sélectionnés dans JOSM
+ * @param {Object} map - L'instance de la carte MapLibre
+ * @param {boolean} map_is_loaded - État de chargement de la carte
+ * @param {Array|Object} osmElements - Élément(s) OSM à ouvrir (peut être un tableau d'objets ou un objet unique)
+ * @returns {void}
+ */
+function openInJOSM(map, map_is_loaded, osmElements) {
+ if (!map_is_loaded) {
+ alert('Veuillez attendre que la carte soit chargée');
+ return;
+ }
+
+ if (!osmElements || (Array.isArray(osmElements) && osmElements.length === 0)) {
+ alert('Aucun élément à ouvrir dans JOSM');
+ return;
+ }
+
+ const bounds = map.getBounds();
+
+ // Convertir en tableau si c'est un seul élément
+ const elements = Array.isArray(osmElements) ? osmElements : [osmElements];
+
+ // Séparer les éléments par type
+ const nodeIds = [];
+ const wayIds = [];
+ const relationIds = [];
+
+ elements.forEach(element => {
+ if (typeof element === 'string') {
+ // Si c'est juste un ID, on le traite comme un node par défaut
+ nodeIds.push(element);
+ } else {
+ // Sinon on utilise le type spécifié
+ switch (element.osm_type) {
+ case 'node':
+ nodeIds.push(element.osm_id);
+ break;
+ case 'way':
+ wayIds.push(element.osm_id);
+ break;
+ case 'relation':
+ relationIds.push(element.osm_id);
+ break;
+ }
+ }
+ });
+
+ // Construire les paramètres de sélection
+ const selectParams = [];
+ if (nodeIds.length > 0) selectParams.push(`node${nodeIds.join(',')}`);
+ if (wayIds.length > 0) selectParams.push(`way${wayIds.join(',')}`);
+ if (relationIds.length > 0) selectParams.push(`relation${relationIds.join(',')}`);
+
+ // Construire l'URL JOSM avec les paramètres de la boîte englobante
+ const josmUrl = `http://localhost:8111/load_and_zoom?` +
+ `left=${bounds.getWest()}&` +
+ `right=${bounds.getEast()}&` +
+ `top=${bounds.getNorth()}&` +
+ `bottom=${bounds.getSouth()}&` +
+ `select=${selectParams.join(',')}`;
+
+ // Utiliser le bouton caché pour ouvrir JOSM
+ const josmButton = document.getElementById('josmButton');
+ if (!josmButton) {
+ console.error('Le bouton JOSM n\'existe pas dans le DOM');
+ return;
+ }
+ josmButton.href = josmUrl;
+ josmButton.click();
+}
\ No newline at end of file
diff --git a/assets/opening_hours.js b/assets/opening_hours.js
new file mode 100644
index 00000000..6c838696
--- /dev/null
+++ b/assets/opening_hours.js
@@ -0,0 +1,388 @@
+
+
+const openingHoursFormManager = {
+ defaultOpeningHours: '',
+ init: function () {
+ // Rechercher l'élément par son attribut name plutôt que par son id
+ const openingHoursInput = document.querySelector('input[name="custom__opening_hours"]');
+ if (!openingHoursInput) {
+ console.warn('Élément input[name="custom__opening_hours"] non trouvé');
+ return;
+ }
+ this.defaultOpeningHours = openingHoursInput.value;
+
+ this.makeForm();
+
+ if (this.defaultOpeningHours !== '') {
+ this.parseOpeningHoursValue();
+ }
+ },
+ parseOpeningHoursValue: function () {
+ // Analyser la chaîne d'horaires d'ouverture
+ const parsedOpeningHours = {};
+
+ // Masquer toutes les plages horaires par défaut
+ const allDayContainers = document.querySelectorAll('.jour-container');
+ allDayContainers.forEach(container => {
+ const checkbox = container.querySelector('input[type="checkbox"]');
+ const horairesContainer = container.querySelector('.horaires-container');
+ checkbox.checked = false;
+ horairesContainer.classList.add('d-none');
+ });
+
+ if (this.defaultOpeningHours) {
+ // Diviser les différentes règles (séparées par des points-virgules)
+ const rules = this.defaultOpeningHours.split(';').map(r => r.trim());
+
+ rules.forEach(rule => {
+ // Extraire les jours et les heures
+ const [days, hours] = rule.split(' ').filter(Boolean);
+
+ // Convertir les jours en français
+ const daysMap = {
+ 'Mo': 'lundi',
+ 'Tu': 'mardi',
+ 'We': 'mercredi',
+ 'Th': 'jeudi',
+ 'Fr': 'vendredi',
+ 'Sa': 'samedi',
+ 'Su': 'dimanche'
+ };
+
+ // Gérer les plages de jours (ex: Mo-Fr)
+ if (days.includes('-')) {
+ const [start, end] = days.split('-');
+ const startIndex = Object.keys(daysMap).indexOf(start);
+ const endIndex = Object.keys(daysMap).indexOf(end);
+
+ for (let i = startIndex; i <= endIndex; i++) {
+ const day = daysMap[Object.keys(daysMap)[i]];
+ // Cocher la case du jour
+ const checkbox = document.querySelector(`#jour-${day}`);
+ if (checkbox) {
+ checkbox.checked = true;
+ checkbox.closest('.jour-container').querySelector('.horaires-container').classList.remove('d-none');
+ }
+ }
+ } else {
+ // Jour unique
+ const day = daysMap[days];
+ const checkbox = document.querySelector(`#jour-${day}`);
+ if (checkbox) {
+ checkbox.checked = true;
+ checkbox.closest('.jour-container').querySelector('.horaires-container').classList.remove('d-none');
+ }
+ }
+ });
+ }
+
+ console.log(parsedOpeningHours);
+ },
+ makeForm: function () {
+ const customOpeningHours = document.querySelector('input[name="custom__opening_hours"]');
+ console.log('makeForm customOpeningHours', customOpeningHours);
+
+ if (customOpeningHours) {
+ // Créer un conteneur flex pour aligner l'input et le formulaire
+ const container = document.createElement('div');
+ container.classList.add('d-flex', 'flex-column', 'flex-md-row', 'align-items-start', 'gap-3', 'w-100');
+
+ // Créer le formulaire
+ const form = document.createElement('form');
+ form.id = 'app_public_opening_hours';
+ form.classList.add('mt-3', 'flex-grow-1');
+
+ // Créer les cases à cocher pour chaque jour
+ const jours = ['Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche'];
+ const joursDiv = document.createElement('div');
+ joursDiv.classList.add('jours-ouverture', 'mb-4', 'row', 'g-3', 'mx-4');
+
+ jours.forEach(jour => {
+ const jourContainer = document.createElement('div');
+ jourContainer.classList.add('jour-container', 'col-12');
+
+ // Checkbox pour le jour
+ const divCheck = document.createElement('div');
+ divCheck.classList.add('form-check', 'mb-2');
+
+ const input = document.createElement('input');
+ input.type = 'checkbox';
+ input.id = `jour-${jour.toLowerCase()}`;
+ input.name = `jour-${jour.toLowerCase()}`;
+ input.classList.add('form-check-input');
+
+ const label = document.createElement('label');
+ label.htmlFor = `jour-${jour.toLowerCase()}`;
+ label.classList.add('form-check-label');
+ label.textContent = jour;
+
+ divCheck.appendChild(input);
+
+ divCheck.appendChild(label);
+ jourContainer.appendChild(divCheck);
+
+ // Conteneur pour les plages horaires
+ const horairesContainer = document.createElement('div');
+ horairesContainer.classList.add('horaires-container', 'ms-4', 'd-none');
+
+ // Première plage horaire
+ const plage1 = this.createTimeRangeInputs(`${jour.toLowerCase()}-plage1`);
+ horairesContainer.appendChild(plage1);
+
+ // Séparateur
+ const separator = document.createElement('div');
+ separator.classList.add('text-center', 'my-2');
+ separator.textContent = 'et';
+ horairesContainer.appendChild(separator);
+
+
+ // Deuxième plage horaire
+ const plage2 = this.createTimeRangeInputs(`${jour.toLowerCase()}-plage2`);
+ horairesContainer.appendChild(plage2);
+
+ jourContainer.appendChild(horairesContainer);
+ joursDiv.appendChild(jourContainer);
+
+ // Ajouter l'événement pour afficher/masquer les plages horaires
+ input.addEventListener('change', (e) => {
+ horairesContainer.classList.toggle('d-none', !e.target.checked);
+ this.convertToOSMOpeningHours();
+ });
+ });
+
+ form.appendChild(joursDiv);
+
+ // Ajouter le formulaire au conteneur
+ container.appendChild(form);
+
+ // Insérer le conteneur après l'input original
+ const parent = customOpeningHours.parentNode;
+ if (parent) {
+ parent.insertBefore(container, customOpeningHours.nextSibling);
+ }
+
+ // Ajouter un debounce pour limiter les appels lors des modifications
+ const debounce = (func, wait) => {
+ let timeout;
+ return function executedFunction(...args) {
+ const later = () => {
+ clearTimeout(timeout);
+ func(...args);
+ };
+ clearTimeout(timeout);
+ timeout = setTimeout(later, wait);
+ };
+ };
+
+ // Appliquer le debounce à la fonction de conversion
+ const debouncedConvert = debounce(() => {
+ this.convertToOSMOpeningHours();
+ }, 300);
+
+ // Ajouter les listeners sur tous les inputs
+ const allInputs = form.querySelectorAll('input');
+ allInputs.forEach(input => {
+ input.addEventListener('change', debouncedConvert);
+ input.addEventListener('input', debouncedConvert);
+ });
+ } else {
+ console.log('pas d input opening hours détecté')
+ }
+ },
+
+ createTimeRangeInputs: function (prefix) {
+ const container = document.createElement('div');
+ container.classList.add('time-range', 'mb-2');
+
+ // Case à cocher pour activer la plage
+ const checkboxContainer = document.createElement('div');
+ checkboxContainer.classList.add('form-check', 'mb-2');
+
+ const checkbox = document.createElement('input');
+ checkbox.type = 'checkbox';
+ checkbox.id = `${prefix}-active`;
+ checkbox.name = `${prefix}-active`;
+ checkbox.classList.add('form-check-input');
+ checkbox.checked = true;
+
+ const checkboxLabel = document.createElement('label');
+ checkboxLabel.htmlFor = `${prefix}-active`;
+ checkboxLabel.classList.add('form-check-label');
+ checkboxLabel.textContent = '';
+
+ checkboxContainer.appendChild(checkbox);
+ checkboxContainer.appendChild(checkboxLabel);
+ container.appendChild(checkboxContainer);
+
+ // Conteneur pour les inputs d'horaires
+ const timeContainer = document.createElement('div');
+ timeContainer.classList.add('ms-4', 'row', 'g-2');
+
+ // Heure de début
+ const startContainer = document.createElement('div');
+ startContainer.classList.add('col-6', 'd-flex', 'align-items-center', 'gap-2');
+
+ const startHour = document.createElement('input');
+ startHour.type = 'number';
+ startHour.min = '0';
+ startHour.max = '23';
+ startHour.classList.add('form-control', 'form-control-sm');
+ startHour.style.width = '60px';
+ startHour.placeholder = 'HH';
+ startHour.name = `${prefix}-start-hour`;
+ // Définir les horaires par défaut selon la plage
+ startHour.value = prefix.includes('plage1') ? '08' : '14';
+
+ const startMinute = document.createElement('input');
+ startMinute.type = 'number';
+ startMinute.min = '0';
+ startMinute.max = '59';
+ startMinute.classList.add('form-control', 'form-control-sm');
+ startMinute.style.width = '60px';
+ startMinute.placeholder = 'MM';
+ startMinute.name = `${prefix}-start-minute`;
+ startMinute.value = '00';
+
+ // Heure de fin
+ const endContainer = document.createElement('div');
+ endContainer.classList.add('col-6', 'd-flex', 'align-items-center', 'gap-2');
+
+ const endHour = document.createElement('input');
+ endHour.type = 'number';
+ endHour.min = '0';
+ endHour.max = '23';
+ endHour.classList.add('form-control', 'form-control-sm');
+ endHour.style.width = '60px';
+ endHour.placeholder = 'HH';
+ endHour.name = `${prefix}-end-hour`;
+ // Définir les horaires par défaut selon la plage
+ endHour.value = prefix.includes('plage1') ? '12' : '18';
+
+ const endMinute = document.createElement('input');
+ endMinute.type = 'number';
+ endMinute.min = '0';
+ endMinute.max = '59';
+ endMinute.classList.add('form-control', 'form-control-sm');
+ endMinute.style.width = '60px';
+ endMinute.placeholder = 'MM';
+ endMinute.name = `${prefix}-end-minute`;
+ endMinute.value = '00';
+
+ // Créer le texte avec les horaires
+ const timeText = document.createElement('div');
+ timeText.classList.add('d-flex', 'align-items-center', 'gap-2', 'flex-wrap');
+
+ // Texte de début
+ const startText = document.createElement('span');
+ startText.textContent = 'de';
+ timeText.appendChild(startText);
+ timeText.appendChild(startHour);
+ timeText.appendChild(document.createTextNode(':'));
+ timeText.appendChild(startMinute);
+
+ // Texte du milieu
+ const middleText = document.createElement('span');
+ middleText.textContent = 'à';
+ timeText.appendChild(middleText);
+
+ // Texte de fin
+ timeText.appendChild(endHour);
+ timeText.appendChild(document.createTextNode(':'));
+ timeText.appendChild(endMinute);
+
+ timeContainer.appendChild(timeText);
+ container.appendChild(timeContainer);
+
+ // Fonction pour mettre à jour le style des inputs
+ const updateInputsStyle = (isActive) => {
+ const inputs = timeContainer.querySelectorAll('input');
+ inputs.forEach(input => {
+ if (isActive) {
+ input.classList.remove('bg-light', 'text-muted');
+ input.disabled = false;
+ } else {
+ input.classList.add('bg-light', 'text-muted');
+ input.disabled = true;
+ }
+ });
+ };
+
+ // Ajouter l'événement sur la checkbox
+ checkbox.addEventListener('change', (e) => {
+ updateInputsStyle(e.target.checked);
+ });
+
+ // Appliquer le style initial
+ updateInputsStyle(checkbox.checked);
+
+ return container;
+ },
+
+ convertToOSMOpeningHours: function () {
+ const jours = {
+ 'Lundi': 'Mo',
+ 'Mardi': 'Tu',
+ 'Mercredi': 'We',
+ 'Jeudi': 'Th',
+ 'Vendredi': 'Fr',
+ 'Samedi': 'Sa',
+ 'Dimanche': 'Su'
+ };
+
+ let joursSelectionnes = [];
+ let horairesParJour = {};
+
+ // Parcourir les checkboxes des jours
+ Object.keys(jours).forEach(jour => {
+ const checkbox = document.getElementById(`jour-${jour.toLowerCase()}`);
+ if (checkbox && checkbox.checked) {
+ joursSelectionnes.push(jours[jour]);
+
+ // Récupérer les horaires pour ce jour
+ const prefix = jour.toLowerCase();
+ const plage1 = this.getTimeRange(`${prefix}-plage1`);
+ const plage2 = this.getTimeRange(`${prefix}-plage2`);
+
+ let horaires = [];
+ if (plage1) horaires.push(plage1);
+ if (plage2) horaires.push(plage2);
+
+ if (horaires.length > 0) {
+ horairesParJour[jours[jour]] = horaires.join(',');
+ }
+ }
+ });
+
+ // Construire la chaîne au format OSM
+ let osmFormat = '';
+ if (joursSelectionnes.length > 0) {
+ const horairesStrings = joursSelectionnes.map(jour => {
+ return horairesParJour[jour] ? `${jour} ${horairesParJour[jour]}` : jour;
+ });
+ osmFormat = horairesStrings.join('; ');
+ }
+
+ // Mettre à jour l'input custom__opening_hours
+ const customOpeningHours = document.querySelector('input[name="custom__opening_hours"]');
+ if (customOpeningHours) {
+ customOpeningHours.value = osmFormat;
+ }
+ },
+
+ getTimeRange: function (prefix) {
+ const isActive = document.querySelector(`input[name="${prefix}-active"]`).checked;
+ if (!isActive) return null;
+
+ const startHour = document.querySelector(`input[name="${prefix}-start-hour"]`).value;
+ const startMinute = document.querySelector(`input[name="${prefix}-start-minute"]`).value;
+ const endHour = document.querySelector(`input[name="${prefix}-end-hour"]`).value;
+ const endMinute = document.querySelector(`input[name="${prefix}-end-minute"]`).value;
+
+ if (startHour && startMinute && endHour && endMinute) {
+ const start = `${startHour.padStart(2, '0')}:${startMinute.padStart(2, '0')}`;
+ const end = `${endHour.padStart(2, '0')}:${endMinute.padStart(2, '0')}`;
+ return `${start}-${end}`;
+ }
+ return null;
+ }
+}
diff --git a/assets/utils.js b/assets/utils.js
new file mode 100644
index 00000000..6dc4b627
--- /dev/null
+++ b/assets/utils.js
@@ -0,0 +1,26 @@
+
+function colorHeadingTable() {
+
+ const headers = document.querySelectorAll('th');
+ headers.forEach(header => {
+ const text = header.textContent;
+ const match = text.match(/\((\d+)\s*\/\s*(\d+)\)/);
+ if (match) {
+ const [_, completed, total] = match;
+ const ratio = completed / total;
+ const alpha = ratio.toFixed(2);
+ header.style.backgroundColor = `rgba(154, 205, 50, ${alpha})`;
+ }
+ });
+}
+
+
+function updateMapHeightForLargeScreens() {
+
+ const mapFound = document.querySelector('#map');
+ if (mapFound && window.innerHeight > 800 && window.innerWidth > 800) {
+ mapFound.style.height = '80vh';
+ } else {
+ console.log('window.innerHeight', window.innerHeight);
+ }
+}
\ No newline at end of file
diff --git a/public/js/app.js b/public/js/app.js
new file mode 100644
index 00000000..e69de29b
diff --git a/templates/admin/edit.html.twig b/templates/admin/edit.html.twig
new file mode 100644
index 00000000..df562caa
--- /dev/null
+++ b/templates/admin/edit.html.twig
@@ -0,0 +1,21 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/admin/labourage_results.html.twig b/templates/admin/labourage_results.html.twig
index 9ca3d029..97948899 100644
--- a/templates/admin/labourage_results.html.twig
+++ b/templates/admin/labourage_results.html.twig
@@ -25,7 +25,7 @@ commerces existants déjà en base: {{ commerces|length }}
{# {{ dump(commerces[0]) }} #}
-
+
{% include 'admin/stats/table-head.html.twig' %}
diff --git a/templates/admin/stats.html.twig b/templates/admin/stats.html.twig
index 4f8cee3d..e00c81a6 100644
--- a/templates/admin/stats.html.twig
+++ b/templates/admin/stats.html.twig
@@ -86,7 +86,7 @@
-
+
{% include 'admin/stats/table-head.html.twig' %}
{% for commerce in stats.places %}
@@ -103,21 +103,20 @@
+
+
+
+
{% endblock %}
\ No newline at end of file
diff --git a/templates/base.html.twig b/templates/base.html.twig
index 0a983677..57255dc9 100644
--- a/templates/base.html.twig
+++ b/templates/base.html.twig
@@ -107,11 +107,11 @@
{% block javascripts %}
{{ encore_entry_script_tags('app') }}
-
+
-
+ {# #}