Fix date carousel position persistence to keep selected date in place

- 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 <noreply@anthropic.com>
This commit is contained in:
2025-11-07 21:59:13 +03:00
parent 2a431e32b1
commit 5198502fa3

View File

@@ -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');
@@ -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