Repository navigation
Feature Home Search Calendar
Статус: сделано. Эпик: UX/UI аудит сайта. Документация: Фронтенд. Задача: #248. PR: #257. Критерии: комментарий к #248.
Гость на главной видит одинаковые поля «Куда?» и «Когда?», выбирает место из подсказок направлений и диапазон дат в календаре в цветах сайта, нажимает «Найти» и попадает в каталог с уже знакомыми параметрами адреса. Пустой поиск открывает страницу «Туры» без query. Набор ключей каталога и поведение фильтров на странице каталога не меняются.
Простой пример: в «Куда?» выбрано «Бали», в календаре отмечено 1 ноября 2026, нажато «Найти». Адрес становится /tours?direction=dir-bali&dateFrom=2026-11-01. Диапазон 12-20 ноября 2026 добавляет dateTo=2026-11-20. Повтор того же дня пишет равные dateFrom и dateTo.
- Сценарии: пустые поля →
/tours; только место →directionилиcountry; только даты →dateFrom/dateTo; место и один день →dateFromбезdateTo; место и диапазон → обе границы; незнакомый текст места уходит вcountry; ошибка загрузки направлений оставляет свободный ввод. - Входит: единая вёрстка полей на главной, подсказки из
GET /catalog/directions, календарь диапазона, правила query для главной, тесты vitest. - Не входит: форма операторского поиска из #138, замена нативных «С» и «По» на странице каталога, отдельный справочник городов, параметр «± N дней».
- Критерии приёмки: полный список в комментарии к #248 (поля и кнопка, «Куда?», «Когда?», отправка, клавиатура и доступность, телефон, что не меняется, тесты).
- Модель данных: без изменений. Направления уже отдаёт Catalog (
DirectionDto:Id,Name,Country,Description). Фильтр туров уже принимаетDateFromиDateTo(включительно). - API: используется существующий
GET /catalog/directions. Новых эндпоинтов нет. Адрес каталога с главной:direction,country,dateFrom,dateToпо правилам ниже;priceMin,priceMax,category,sortглавная не задаёт. - Контракты между сервисами: не затрагиваются.
- Интерфейс:
SearchBarна главной (HeroSection). Поля одной высоты: подпись 12px, значение 16px Inter, цвет значенияdark. До 768px колонка и нижняя панель для подсказок и календаря, с 768px ряд и два месяца. «Когда?» не<input type="date">, а кнопка с диалогомDateRangeCalendarв цветахsand,cream,primary,dark. Прошедшие дни относительно календарной датыEurope/Moscowна главной недоступны; сегодня доступен; верхняя граница2100-12-31. Текст даты:12 ноя,с 12 по 20 ноя,с 28 окт по 3 ноя,с 28 дек 2026 по 3 янв 2027(месяцы из фиксированного списка без точки). - Правила query (
resolveHomeSearch/catalogPathвcatalogQuery.ts):- один выбранный день: только
dateFrom(yyyy-MM-dd); - диапазон или повтор того же дня:
dateFromиdateTo; - пустые поля:
/toursбез query; - сопоставление места:
normalizePlace/matchPlace(точное имя →direction, точная страна или свободный текст →country, оба ключа сразу не ставятся).
- один выбранный день: только
- Ключевые файлы:
SearchBar.tsx,DateRangeCalendar.tsx,homeCalendar.ts,catalogQuery.ts(resolveHomeSearch),HeroSection.tsx. Пакетdate-fnsуже в зависимостях, новый календарный пакет не добавляется. - Влияние на существующий код: страница каталога по-прежнему читает
dateFrom/dateToи показывает нативные «С»/«По»; карточки направлений и остальные секции главной без изменений вёрстки.
| Вопрос | Варианты | Выбрано | Почему | Дата |
|---|---|---|---|---|
| Выбор даты на главной | нативный input type="date"; свой календарь одного дня; календарь диапазона |
календарь диапазона | API уже фильтрует обе включительные границы; один день сохраняет прежнее поведение (только dateFrom) |
2026-10-19 |
| Источник подсказок «Куда?» | отдельный справочник городов; только GET /catalog/directions
|
только направления (name и country) |
отдельного справочника нет; Description в список не выводится |
2026-10-19 |
| Подпись даты | маска dd.mm.yyyy; d MMM из date-fns; фиксированный список коротких месяцев |
фиксированный список янв фев мар апр мая июн июл авг сен окт ноя дек
|
d MMM с локалью ru даёт «нояб.» и «окт.»; год только если годы границ разные; дефиса и тире нет |
2026-10-19 |
| Календарь на фильтре каталога | подключить сразу; отложить | отложить (#138 на удержании) | в этом изменении только строка главной; тот же компонент можно взять позже | 2026-10-19 |
| «Сегодня» и прошедшие дни | локальная полночь машины; Europe/Moscow
|
календарная дата Europe/Moscow
|
иначе граница суток зависит от пояса CI и браузера; правило только для главной | 2026-10-19 |
| Подзадача | Раздел страницы | Задача | Статус |
|---|---|---|---|
| Единая строка поиска, подсказки, календарь диапазона, query и тесты | Архитектура, Тест-кейсы | #248 / #257 | сделано |
| Календарь на фильтрах каталога | вне скоупа | #138 (удержание) | не в этой фиче |
| Форма операторского поиска | вне скоупа | #138 | не в этой фиче |
| № | Предусловие | Шаги | Ожидаемый результат | Уровень |
|---|---|---|---|---|
| ТК-1 | главная, направления загружены | пустые «Куда?» и «Когда?», «Найти» | переход на /tours без query |
unit |
| ТК-2 | точное имя направления «Бали» | место «Бали», день 2026-11-01, «Найти» | /tours?direction=dir-bali&dateFrom=2026-11-01 |
unit |
| ТК-3 | выбран начало диапазона | дни 12 и 20 ноября 2026 | в адресе dateFrom=2026-11-12 и dateTo=2026-11-20
|
unit |
| ТК-4 | выбран один день дважды | повтор 1 ноября 2026 |
dateFrom и dateTo равны 2026-11-01
|
unit |
| ТК-5 | в поле места есть текст | «Очистить» | текст сброшен, список закрыт, переход не выполняется; direction/country не пишутся |
unit |
| ТК-6 | подсказки открыты | ввод с ё/е, разным регистром, крайними пробелами |
совпадения находятся; не больше 8 строк; пустой результат: «Ничего не найдено» | unit |
| ТК-7 | календарь открыт, сегодня по Москве | клик по вчерашнему дню | день недоступен и не выбирается; сегодня доступен | unit |
| ТК-8 | календарь или подсказки открыты | Enter на выделенной строке/дне; Esc | значение выбирается без отправки формы; Esc закрывает и возвращает фокус в поле | unit |
| ТК-9 | форматы подписи | один день; тот же месяц; разные месяцы; разные годы |
12 ноя; с 12 по 20 ноя; с 28 окт по 3 ноя; с 28 дек 2026 по 3 янв 2027
|
unit |
| ТК-10 | страница каталога | адреса с dateFrom/dateTo, перевёрнутый диапазон |
чипы и нативные «С»/«По» как раньше; перевёрнутый диапазон не запускает загрузку | unit (без смены смысла) |
Тесты: HomePage.test.tsx, SearchBar.test.tsx, catalogQuery.test.ts. TourCatalogPage.test.tsx по смыслу не меняется.
Система
API
Сервисы
Как реализовано
Справочное
- Эпик: модель туров под импорт
- Разбор Tourvisor (к импорту)
- ТЗ агрегации туров (к импорту)
- Эпик: подключение туроператоров
- Эпик: полный цикл бронирования
- Эпик: мелкие доработки и заметки
- Эпик: профили и настройки
- Эпик: UX/UI аудит сайта
- Эпик: отзывы клиентов
- Эпик: визуальный редизайн
- Эпик: ИИ-агенты на сайте
- Фича: почему выбирают нас
- Фича: витрина туров на главной
- Фича: раздел администрирования
- Фича: карточки собеседника в чате
- Фича: профиль клиента
- Фича: поиск и календарь на главной
- Фича: профиль менеджера
- Фича: аккаунт и сервер профиля
- Фича: видимость полей группами
- Фича: явные неготовые элементы
- Фича: галерея на странице тура
- Фича: единые поля дат
- Шаблон эпика
- Шаблон фичи