diff --git a/assets/opening_hours.js b/assets/opening_hours.js index e781053..1cca745 100644 --- a/assets/opening_hours.js +++ b/assets/opening_hours.js @@ -1,4 +1,3 @@ - /** * Gestion du formulaire d'horaires d'ouverture * @@ -16,11 +15,26 @@ const openingHoursFormManager = { } this.defaultOpeningHours = openingHoursInput.value; + // Créer la div de rendu si elle n'existe pas + let renderDiv = document.getElementById('opening_hours_render'); + if (!renderDiv) { + renderDiv = document.createElement('div'); + renderDiv.id = 'opening_hours_render'; + renderDiv.classList.add('mt-4'); + openingHoursInput.parentNode.insertBefore(renderDiv, openingHoursInput.nextSibling); + } + this.makeForm(inputSelector); if (this.defaultOpeningHours !== '') { this.parseOpeningHoursValue(inputSelector); } + + // Ajouter un écouteur d'événement keyup sur l'input des horaires + openingHoursInput.addEventListener('keyup', () => { + this.defaultOpeningHours = openingHoursInput.value; + this.parseOpeningHoursValue(inputSelector); + }); }, setInputSelector: function (inputSelector) { this.inputSelector = inputSelector; @@ -31,7 +45,7 @@ const openingHoursFormManager = { */ parseOpeningHoursValue: function (inputSelector = 'input[name="custom__opening_hours"]') { // Analyser la chaîne d'horaires d'ouverture - const parsedOpeningHours = {}; + const parsedOpeningHours = []; // Masquer toutes les plages horaires par défaut const allDayContainers = document.querySelectorAll('.jour-container'); @@ -48,7 +62,9 @@ const openingHoursFormManager = { rules.forEach(rule => { // Extraire les jours et les heures - const [days, hours] = rule.split(' ').filter(Boolean); + const parts = rule.split(' ').filter(Boolean); + const days = parts[0]; + const hours = parts.slice(1).join(' '); // Convertir les jours en français const daysMap = { @@ -67,27 +83,94 @@ const openingHoursFormManager = { const startIndex = Object.keys(daysMap).indexOf(start); const endIndex = Object.keys(daysMap).indexOf(end); + const dayRange = []; for (let i = startIndex; i <= endIndex; i++) { - const day = daysMap[Object.keys(daysMap)[i]]; + const day = Object.keys(daysMap)[i]; + dayRange.push(day); // Cocher la case du jour - const checkbox = document.querySelector(`#jour-${day}`); + const checkbox = document.querySelector(`#jour-${daysMap[day]}`); if (checkbox) { checkbox.checked = true; - checkbox.closest('.jour-container').querySelector('.horaires-container').classList.remove('d-none'); + const horairesContainer = checkbox.closest('.jour-container').querySelector('.horaires-container'); + horairesContainer.classList.remove('d-none'); + + // Décocher la deuxième plage si elle n'est pas présente dans l'input + if (hours && !hours.includes(',')) { + const plage2Checkbox = horairesContainer.querySelector(`input[name="${daysMap[day]}-plage2-active"]`); + if (plage2Checkbox) { + plage2Checkbox.checked = false; + } + } + + // Remplir la première plage horaire si spécifiée + if (hours) { + const [startTime, endTime] = hours.split('-'); + if (startTime && endTime) { + const [startHour, startMinute] = startTime.split(':'); + const [endHour, endMinute] = endTime.split(':'); + + const startHourInput = horairesContainer.querySelector(`input[name="${daysMap[day]}-plage1-start-hour"]`); + const startMinuteInput = horairesContainer.querySelector(`input[name="${daysMap[day]}-plage1-start-minute"]`); + const endHourInput = horairesContainer.querySelector(`input[name="${daysMap[day]}-plage1-end-hour"]`); + const endMinuteInput = horairesContainer.querySelector(`input[name="${daysMap[day]}-plage1-end-minute"]`); + + if (startHourInput) startHourInput.value = startHour; + if (startMinuteInput) startMinuteInput.value = startMinute; + if (endHourInput) endHourInput.value = endHour; + if (endMinuteInput) endMinuteInput.value = endMinute; + } + } } } + parsedOpeningHours.push({ + days: dayRange, + hours: hours + }); } 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'); + const horairesContainer = checkbox.closest('.jour-container').querySelector('.horaires-container'); + horairesContainer.classList.remove('d-none'); + + // Décocher la deuxième plage si elle n'est pas présente dans l'input + if (hours && !hours.includes(',')) { + const plage2Checkbox = horairesContainer.querySelector(`input[name="${day}-plage2-active"]`); + if (plage2Checkbox) { + plage2Checkbox.checked = false; + } + } + + // Remplir la première plage horaire si spécifiée + if (hours) { + const [startTime, endTime] = hours.split('-'); + if (startTime && endTime) { + const [startHour, startMinute] = startTime.split(':'); + const [endHour, endMinute] = endTime.split(':'); + + const startHourInput = horairesContainer.querySelector(`input[name="${day}-plage1-start-hour"]`); + const startMinuteInput = horairesContainer.querySelector(`input[name="${day}-plage1-start-minute"]`); + const endHourInput = horairesContainer.querySelector(`input[name="${day}-plage1-end-hour"]`); + const endMinuteInput = horairesContainer.querySelector(`input[name="${day}-plage1-end-minute"]`); + + if (startHourInput) startHourInput.value = startHour; + if (startMinuteInput) startMinuteInput.value = startMinute; + if (endHourInput) endHourInput.value = endHour; + if (endMinuteInput) endMinuteInput.value = endMinute; + } + } } + parsedOpeningHours.push({ + days: [days], + hours: hours + }); } }); } + this.renderOpeningHours(parsedOpeningHours); console.log(parsedOpeningHours); }, makeForm: function (inputSelector = 'input[name="custom__opening_hours"]') { @@ -107,7 +190,7 @@ const openingHoursFormManager = { // 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'); + joursDiv.classList.add('jours-ouverture', 'mb-4', 'row', 'mx-4'); jours.forEach(jour => { const jourContainer = document.createElement('div'); @@ -129,25 +212,17 @@ const openingHoursFormManager = { 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'); + horairesContainer.classList.add('horaires-container', 'ms-4', 'd-none', 'row', 'g-3'); // 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); @@ -204,7 +279,7 @@ const openingHoursFormManager = { createTimeRangeInputs: function (prefix) { const container = document.createElement('div'); - container.classList.add('time-range', 'mb-2'); + container.classList.add('time-range', 'mb-2', 'col-12', 'col-md-6'); // Case à cocher pour activer la plage const checkboxContainer = document.createElement('div'); @@ -365,20 +440,147 @@ const openingHoursFormManager = { } }); + // Optimiser les plages horaires identiques consécutives + let optimizedRules = []; + let currentRule = null; + let currentDays = []; + let currentHours = null; + + joursSelectionnes.forEach((jour, index) => { + const hours = horairesParJour[jour]; + + if (currentHours === null) { + // Première règle + currentHours = hours; + currentDays = [jour]; + } else if (hours === currentHours) { + // Mêmes horaires que la règle en cours + currentDays.push(jour); + } else { + // Horaires différents, on finalise la règle en cours + if (currentDays.length > 0) { + optimizedRules.push({ + days: currentDays, + hours: currentHours + }); + } + // On commence une nouvelle règle + currentDays = [jour]; + currentHours = hours; + } + + // Si c'est le dernier jour, on finalise la règle en cours + if (index === joursSelectionnes.length - 1 && currentDays.length > 0) { + optimizedRules.push({ + days: currentDays, + hours: currentHours + }); + } + }); + // 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('; '); - } + let osmFormat = optimizedRules.map(rule => { + const days = rule.days.length > 1 ? `${rule.days[0]}-${rule.days[rule.days.length - 1]}` : rule.days[0]; + return rule.hours ? `${days} ${rule.hours}` : days; + }).join('; '); // Mettre à jour l'input custom__opening_hours const customOpeningHours = document.querySelector(inputSelector); if (customOpeningHours) { customOpeningHours.value = osmFormat; } + + // Mettre à jour le rendu visuel + this.renderOpeningHours(optimizedRules); + }, + + renderOpeningHours: function (rules) { + const container = document.getElementById('opening_hours_render'); + console.log('renderOpeningHours', rules); + if (!container) return; + + // Vider le conteneur + container.innerHTML = ''; + + // Créer le style pour les sections d'ouverture + const style = document.createElement('style'); + style.textContent = ` + .opening-hours-day { + background-color: #f8f9fa; + border-radius: 4px; + margin-bottom: 8px; + padding: 8px; + position: relative; + height: 40px; + } + .opening-hours-time { + background-color: #d4edda; + border-radius: 4px; + position: absolute; + height: 24px; + top: 8px; + } + .opening-hours-label { + position: absolute; + left: 8px; + top: 50%; + transform: translateY(-50%); + z-index: 1; + } + `; + document.head.appendChild(style); + + // Mapping des jours OSM vers français + const joursMap = { + 'Mo': 'Lundi', + 'Tu': 'Mardi', + 'We': 'Mercredi', + 'Th': 'Jeudi', + 'Fr': 'Vendredi', + 'Sa': 'Samedi', + 'Su': 'Dimanche' + }; + + // Créer les lignes pour chaque jour + Object.entries(joursMap).forEach(([osmDay, frenchDay]) => { + const dayDiv = document.createElement('div'); + dayDiv.classList.add('opening-hours-day'); + + // Ajouter le label du jour + const label = document.createElement('span'); + label.classList.add('opening-hours-label'); + label.textContent = frenchDay; + dayDiv.appendChild(label); + + // Trouver les horaires pour ce jour + const rule = rules.find(r => r.days.includes(osmDay)); + if (rule && rule.hours) { + const timeRanges = rule.hours.split(','); + timeRanges.forEach((timeRange, index) => { + const [start, end] = timeRange.split('-'); + const [startHour, startMinute] = start.split(':'); + const [endHour, endMinute] = end.split(':'); + + // Calculer la position et la largeur + const startMinutes = parseInt(startHour) * 60 + parseInt(startMinute); + const endMinutes = parseInt(endHour) * 60 + parseInt(endMinute); + const totalMinutes = 24 * 60; + + const left = (startMinutes / totalMinutes) * 100; + const width = ((endMinutes - startMinutes) / totalMinutes) * 100; + + const timeDiv = document.createElement('div'); + timeDiv.classList.add('opening-hours-time'); + timeDiv.style.left = `${left}%`; + timeDiv.style.width = `${width}%`; + timeDiv.title = `${start}-${end}`; + + dayDiv.appendChild(timeDiv); + }); + } + + container.appendChild(dayDiv); + }); }, getTimeRange: function (prefix) { diff --git a/assets/styles/app.css b/assets/styles/app.css index 84aa21a..6630f27 100644 --- a/assets/styles/app.css +++ b/assets/styles/app.css @@ -83,4 +83,20 @@ table.js-sort-table th:active { #attribution { font-size: 0.6rem; +} + +#restaurant .form-check-label { + margin-top: 0; + display: block; + cursor: pointer; +} + +#restaurant .form-check-label:hover { + background-color: #f0f0f0; + color: #1e40c6; +} + +#advanced_tags { + border-left: solid 3px #ccc; + padding-left: 2rem; } \ No newline at end of file diff --git a/templates/public/edit.html.twig b/templates/public/edit.html.twig index 8dc99e5..3b2ca58 100644 --- a/templates/public/edit.html.twig +++ b/templates/public/edit.html.twig @@ -165,17 +165,23 @@ -