From 5198502fa33faa9b4041c8227cb839d678b62f7e Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Fri, 7 Nov 2025 21:59:13 +0300 Subject: [PATCH] Fix date carousel position persistence to keep selected date in place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Selected date now stays at its clicked position instead of jumping to center - Fixed timezone issue in localStorage causing dates to shift by one day - Carousel position is preserved across page reloads - Simplified date selection logic by removing complex offset calculations - Added updateSelectedState() method to update selection without re-rendering 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../orders/static/orders/js/date_filter.js | 162 ++++++------------ 1 file changed, 55 insertions(+), 107 deletions(-) diff --git a/myproject/orders/static/orders/js/date_filter.js b/myproject/orders/static/orders/js/date_filter.js index ab0999c..ebab4b3 100644 --- a/myproject/orders/static/orders/js/date_filter.js +++ b/myproject/orders/static/orders/js/date_filter.js @@ -43,38 +43,11 @@ class DateCarousel { // Загружаем сохранённую дату из localStorage или устанавливаем сегодня const savedData = this.loadSavedCenterDate(); if (savedData) { - // Если есть смещение, это означает, что дата была выбрана пользователем - if (savedData.offset !== 0) { - // Проверяем, есть ли выбранная дата в фильтрах - if (this.minInput && this.minInput.value && this.maxInput.value && - this.minInput.value === this.maxInput.value) { - // Получаем выбранную дату из фильтра - const parts = this.minInput.value.split('-'); - if (parts.length === 3) { - const selectedDate = new Date( - parseInt(parts[0]), - parseInt(parts[1]) - 1, - parseInt(parts[2]) - ); - selectedDate.setHours(0, 0, 0, 0); - - // Вычисляем центральную дату: выбранная дата минус смещение - this.centerDate = new Date(selectedDate); - this.centerDate.setDate(this.centerDate.getDate() - savedData.offset); - } else { - // Если дата в фильтре некорректна, используем сохранённую центральную дату - this.centerDate = savedData.centerDate; - } - } else { - // Если нет фильтра с одной датой, используем сохранённую центральную дату - this.centerDate = savedData.centerDate; - } - } else { - // Если смещения нет, используем сохранённую центральную дату - this.centerDate = savedData.centerDate; - } + // Восстанавливаем центральную дату как есть + this.centerDate = savedData.centerDate; } else { this.centerDate = new Date(); + this.centerDate.setHours(0, 0, 0, 0); // Сбрасываем время! } } @@ -85,43 +58,6 @@ class DateCarousel { this.calculateDaysCount(); this.loadSelectedDate(); // Загрузить выбранную дату из фильтра - // Если в localStorage есть сохраненные данные - const savedData = this.loadSavedCenterDate(); - if (savedData) { - // Если есть смещение, это означает, что дата была выбрана пользователем - if (savedData.offset !== 0) { - // Проверяем, есть ли выбранная дата в фильтрах - if (this.minInput.value && this.maxInput.value && - this.minInput.value === this.maxInput.value) { - // Получаем выбранную дату из фильтра - const parts = this.minInput.value.split('-'); - if (parts.length === 3) { - const selectedDate = new Date( - parseInt(parts[0]), - parseInt(parts[1]) - 1, - parseInt(parts[2]) - ); - selectedDate.setHours(0, 0, 0, 0); - - // Вычисляем центральную дату: выбранная дата минус смещение - // (т.к. смещение показывает, на сколько дней выбранная дата - // смещена вправо от центра) - this.centerDate = new Date(selectedDate); - this.centerDate.setDate(this.centerDate.getDate() - savedData.offset); - } else { - // Если дата в фильтре некорректна, используем сохранённую центральную дату - this.centerDate = savedData.centerDate; - } - } else { - // Если нет фильтра с одной датой, используем сохранённую центральную дату - this.centerDate = savedData.centerDate; - } - } else { - // Если смещения нет, используем сохранённую центральную дату - this.centerDate = savedData.centerDate; - } - } - this.render(); this.attachNavHandlers(); this.attachTodayHandler(); @@ -131,33 +67,13 @@ class DateCarousel { * Загрузка выбранной даты из скрытых полей фильтра */ loadSelectedDate() { - // Если есть выбранная дата в фильтре + // Просто логируем выбранную дату, но НЕ меняем centerDate + // Карусель остается там, где была (centerDate из localStorage или today) if (this.minInput.value && this.maxInput.value && this.minInput.value === this.maxInput.value) { - const parts = this.minInput.value.split('-'); - if (parts.length === 3) { - const selectedDate = new Date( - parseInt(parts[0]), - parseInt(parts[1]) - 1, - parseInt(parts[2]) - ); - selectedDate.setHours(0, 0, 0, 0); - - // Устанавливаем центральную дату на выбранную дату только если фильтр отличается от сегодняшней даты - // Это позволяет определить, был ли фильтр установлен до посещения страницы - const todayFormatted = this.formatDate(this.today); - if (this.minInput.value !== todayFormatted) { - // Возможно, фильтр уже был установлен, но мы всё равно не хотим центрировать - // для согласованности с поведением после выбора даты - console.log(`Selected date in filter: ${this.formatDate(selectedDate)}, keeping current view`); - } else { - // Если фильтр равен сегодняшней дате, можно центрировать на сегодня - console.log(`Filter is today: ${this.formatDate(selectedDate)}, keeping current view`); - } - } + console.log(`Selected date in filter: ${this.minInput.value}, but keeping current center`); } else { - // Если фильтра нет, центрируем на сегодняшнем дне - console.log('No filter active - centering on today'); + console.log('No filter active - keeping current center'); } } @@ -327,6 +243,35 @@ class DateCarousel { return this.minInput.value === formattedDate && this.maxInput.value === formattedDate; } + /** + * Обновление состояния selected для всех кнопок без перерисовки + */ + updateSelectedState() { + const buttons = this.container.querySelectorAll('.date-btn'); + buttons.forEach(btn => { + // Получаем дату из кнопки (день месяца) + const dayElement = btn.querySelector('.date-btn-day'); + const monthElement = btn.querySelector('.date-btn-month'); + if (dayElement && monthElement) { + const day = parseInt(dayElement.textContent); + const monthShort = monthElement.textContent; + + // Находим дату кнопки, сравнивая с датами в generateDays + const days = this.generateDays(); + const matchingDay = days.find(d => + d.date.getDate() === day && + this.getMonthShort(d.date) === monthShort + ); + + if (matchingDay && this.isDateSelected(matchingDay.date)) { + btn.classList.add('selected'); + } else { + btn.classList.remove('selected'); + } + } + }); + } + /** * Выбор даты (установка в оба поля фильтра) */ @@ -336,19 +281,21 @@ class DateCarousel { this.minInput.value = formattedDate; this.maxInput.value = formattedDate; - // Вычисляем смещение выбранной даты от центра - const offset = this.calculateDateOffset(date); - // Сохраняем центральную дату и смещение перед отправкой формы - this.saveCenterDate(offset); + // НЕ меняем centerDate - оставляем карусель на месте + // Только обновляем визуальное выделение // Визуальная обратная связь btn.classList.add('clicked'); setTimeout(() => btn.classList.remove('clicked'), 300); - // Обновление визуального состояния (без изменения центральной даты) - this.render(); + // Обновление визуального состояния (только класс selected) + this.updateSelectedState(); - console.log(`Selected date: ${formattedDate}, offset: ${offset}`); + console.log(`Selected date: ${formattedDate}, center stays at: ${this.formatDate(this.centerDate)}`); + + // ВАЖНО: Сохраняем текущую позицию карусели перед отправкой формы + // чтобы после перезагрузки страницы карусель осталась на том же месте + this.saveCenterDate(); // Автоматическая отправка формы const form = this.minInput.closest('form'); @@ -396,36 +343,36 @@ class DateCarousel { */ goToToday() { console.log('Today button clicked'); - + // Проверяем существование элементов if (!this.minInput || !this.maxInput) { console.error('minInput or maxInput not found!'); return; } - + const today = new Date(); today.setHours(0, 0, 0, 0); - + // Устанавливаем сегодняшнюю дату в фильтр const formattedDate = this.formatDate(today); this.minInput.value = formattedDate; this.maxInput.value = formattedDate; - + console.log(`Set values - Min: ${this.minInput.value}, Max: ${this.maxInput.value}`); // Устанавливаем сегодняшнюю дату как центральную this.centerDate = today; - + // При нажатии на "Сегодня" устанавливаем центральную дату на сегодня без смещения // и сохраняем без смещения, чтобы календарь центрировался на сегодня this.saveCenterDate(0); - + // Очищаем выделение с других кнопок и обновляем визуальное состояние this.render(); - + // Обновляем обработчик после перерисовки this.attachTodayHandler(); - + console.log(`Navigated to today: ${formattedDate}`); // Автоматическая отправка формы @@ -443,7 +390,8 @@ class DateCarousel { */ saveCenterDate(offset = 0) { const key = `date_carousel_center_${this.minInputId}`; - const centerDateStr = this.centerDate.toISOString().split('T')[0]; // Формат YYYY-MM-DD + // Используем formatDate вместо toISOString для избежания проблем с часовыми поясами + const centerDateStr = this.formatDate(this.centerDate); const saveData = { centerDate: centerDateStr, offset: offset