From ed2647e45c08c179f26ba0ec85f8d4c9239d82b6 Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Fri, 7 Nov 2025 20:31:19 +0300 Subject: [PATCH] Fix date selection position preservation in calendar carousel --- .../orders/static/orders/js/date_filter.js | 173 +++++++++++++++++- 1 file changed, 163 insertions(+), 10 deletions(-) diff --git a/myproject/orders/static/orders/js/date_filter.js b/myproject/orders/static/orders/js/date_filter.js index c98cbfc..c8ace57 100644 --- a/myproject/orders/static/orders/js/date_filter.js +++ b/myproject/orders/static/orders/js/date_filter.js @@ -36,10 +36,46 @@ class DateCarousel { this.maxInputId = maxInputId; this.minInput = document.getElementById(minInputId); this.maxInput = document.getElementById(maxInputId); - this.centerDate = new Date(); // Центральная дата (по умолчанию сегодня) this.today = new Date(); this.today.setHours(0, 0, 0, 0); this.daysCount = 0; // Будет рассчитано динамически + + // Загружаем сохранённую дату из 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; + } + } else { + this.centerDate = new Date(); + } } /** @@ -48,6 +84,44 @@ class DateCarousel { init() { 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(); } @@ -56,7 +130,7 @@ class DateCarousel { * Загрузка выбранной даты из скрытых полей фильтра */ loadSelectedDate() { - // Если есть выбранная дата в фильтре, центрируем на ней, чтобы она была видна + // Если есть выбранная дата в фильтре if (this.minInput.value && this.maxInput.value && this.minInput.value === this.maxInput.value) { const parts = this.minInput.value.split('-'); @@ -68,9 +142,17 @@ class DateCarousel { ); selectedDate.setHours(0, 0, 0, 0); - // Центрируем на выбранной дате, чтобы она всегда была видна - this.centerDate = selectedDate; - console.log(`Centering on selected date: ${this.formatDate(selectedDate)}`); + // Устанавливаем центральную дату на выбранную дату только если фильтр отличается от сегодняшней даты + // Это позволяет определить, был ли фильтр установлен до посещения страницы + 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`); + } } } else { // Если фильтра нет, центрируем на сегодняшнем дне @@ -252,18 +334,19 @@ class DateCarousel { this.minInput.value = formattedDate; this.maxInput.value = formattedDate; - // Обновляем центральную дату, чтобы выбранная дата была в центре - this.centerDate = new Date(date); - this.centerDate.setHours(0, 0, 0, 0); + // Вычисляем смещение выбранной даты от центра + const offset = this.calculateDateOffset(date); + // Сохраняем центральную дату и смещение перед отправкой формы + this.saveCenterDate(offset); // Визуальная обратная связь btn.classList.add('clicked'); setTimeout(() => btn.classList.remove('clicked'), 300); - // Обновление визуального состояния + // Обновление визуального состояния (без изменения центральной даты) this.render(); - console.log(`Selected date: ${formattedDate}`); + console.log(`Selected date: ${formattedDate}, offset: ${offset}`); // Автоматическая отправка формы const form = this.minInput.closest('form'); @@ -287,12 +370,82 @@ class DateCarousel { nextBtn.addEventListener('click', () => this.shiftDays(1)); } } + + /** + * Сохранение центральной даты и смещения в localStorage + */ + saveCenterDate(offset = 0) { + const key = `date_carousel_center_${this.minInputId}`; + const centerDateStr = this.centerDate.toISOString().split('T')[0]; // Формат YYYY-MM-DD + const saveData = { + centerDate: centerDateStr, + offset: offset + }; + localStorage.setItem(key, JSON.stringify(saveData)); + } + + /** + * Загрузка центральной даты из localStorage + */ + loadSavedCenterDate() { + const key = `date_carousel_center_${this.minInputId}`; + const savedDataStr = localStorage.getItem(key); + + if (savedDataStr) { + try { + const savedData = JSON.parse(savedDataStr); + const savedDate = new Date(savedData.centerDate); + savedDate.setHours(0, 0, 0, 0); + return { + centerDate: savedDate, + offset: savedData.offset || 0 + }; + } catch (e) { + console.error('Error parsing saved date data', e); + // В случае ошибки возвращаем старый формат для совместимости + const savedDateStr = localStorage.getItem(key); + if (savedDateStr && !savedDateStr.includes('{')) { + const savedDate = new Date(savedDateStr); + savedDate.setHours(0, 0, 0, 0); + return { + centerDate: savedDate, + offset: 0 + }; + } + return null; + } + } + + return null; + } + + /** + * Вычисление смещения выбранной даты от центральной + */ + calculateDateOffset(selectedDate) { + // Генерируем дни с текущей центральной датой + const days = this.generateDays(); + // Находим индекс выбранной даты + const selectedIndex = days.findIndex(day => + day.date.getTime() === selectedDate.getTime() + ); + + if (selectedIndex !== -1) { + // Находим центральный индекс + const centerIndex = Math.floor(this.daysCount / 2); + // Вычисляем смещение от центра + return selectedIndex - centerIndex; + } + + return 0; // Если дата не найдена, возвращаем 0 + } /** * Сдвиг диапазона дней на N дней */ shiftDays(offset) { this.centerDate.setDate(this.centerDate.getDate() + offset); + this.saveCenterDate(); // Сохраняем новую центральную дату (без смещения для прокрутки) this.render(); } }