mirror of
https://forge.chapril.org/tykayn/osm-commerces
synced 2025-06-20 01:44:42 +02:00
render hours
This commit is contained in:
parent
9b09b0d59d
commit
56ec8ba4f0
3 changed files with 252 additions and 28 deletions
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -165,17 +165,23 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="completion_progress" class="">
|
||||
<div class="container">
|
||||
|
||||
</div>
|
||||
<div id="completion_progress" class="">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<div id="completion_display" class="mb-2"></div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="progress" role="progressbar" aria-label="Progression de complétion" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
|
||||
<div class="progress-bar" style="width: 0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
{% block javascripts %}
|
||||
{{ parent() }}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue