Skip to content

Doc Frontend

TravelAgency Team Bot edited this page Oct 17, 2026 · 2 revisions

Фронтенд

src/Frontend/travel-agency-frontend/. Одностраничное приложение: каталог туров для гостей, личный кабинет клиента и кабинет менеджера. В контейнере собирается Vite и раздаётся nginx, тот же nginx проксирует /api/ в Gateway.

Простой пример

Гость открывает /tours?country=Турция:

  1. Роутер показывает TourCatalogPage.
  2. Страница через React Query вызывает getTours из src/api/catalog.ts, axios отправляет GET /api/v1/catalog/tours?country=Турция.
  3. Карточки рисуют обложку по адресу /api/v1/media/files/{id}/w800, который фронтенд строит сам (src/utils/media.ts).

Гость нажимает «Оставить заявку» на странице тура, но не вошёл: открывается окно входа, а после входа окно заявки открывается само. Подробно: Действие после входа.

Стек

React 19, TypeScript, Vite 7, Tailwind CSS 4, React Router 7, React Query 5, zustand, axios, @microsoft/signalr, framer-motion, react-hot-toast, lucide-react. Тесты: vitest и Testing Library.

Страницы

Адрес Страница Доступ
/ HomePage все
/tours TourCatalogPage все
/tours/:id TourDetailPage все
/dashboard DashboardPage client, manager, admin
/dashboard/bookings, /dashboard/bookings/:id MyBookingsPage, BookingDetailPage (с чатом) client, manager, admin
/dashboard/profile ProfilePage client, manager, admin
/dashboard/favorites FavoritesPage client, manager, admin
/manager ManagerDashboardPage manager, admin
/manager/bookings, /manager/bookings/:id ManagerBookingsPage, ManagerBookingDetailPage manager, admin
/manager/tours ManagerToursPage manager, admin
/manager/tours/new, /manager/tours/:tourId TourWizardPage (мастер из 7 шагов) manager, admin
/manager/clients ManagerClientsPage (список клиентов собирается из всех заявок) manager, admin
прочее NotFoundPage все

Доступ проверяет ProtectedRoute по списку ролей. Это только удобство интерфейса: настоящая проверка на Gateway и в сервисах.

Обращение к API

src/api/client.ts:

  • baseURL = VITE_API_URL или /api/v1;
  • withCredentials: true: браузер сам отправляет cookie сессии, токены в JavaScript не попадают;
  • при 401 перехватчик один раз вызывает POST /auth/refresh (параллельные запросы ждут одно обновление) и повторяет запрос; если обновить не удалось, переход на /?auth=login. Для getMe 401 считается нормой (гость) и переход не делается.

Модули: auth, catalog, tourManage (шлёт If-Match), bookings (переводит числовой статус в название), favorites (карточки через /catalog/tours/cards), chat (SignalR), mediaUpload.

Состояние

Где Что
React Query данные с сервера: туры, заявки, избранное
authStore (zustand) текущий пользователь и роль
favoritesStore id туров в избранном для быстрых сердечек
uiStore окно входа, отложенное действие после входа (authIntent) и мобильное меню

Действие после входа

Если гость нажимает кнопку, которой нужен вход, фронтенд запоминает намерение (authIntent в uiStore) и открывает окно входа. После входа действие выполняется само. Намерение живёт только в памяти вкладки; если закрыть окно входа, оно стирается.

Где нажали Намерение Что после входа
«Оставить заявку» на странице тура (TourDetailPage) request: тур и выбранное предложение страница тура открывает окно заявки с тем же предложением
сердечко на карточке тура (TourCard, HotDealsCarousel) favorite: тур тур добавляется в избранное

Избранное. После входа App.tsx загружает список избранного и вызывает resumeFavoriteIntent (src/store/authIntent.ts). Намерение стирается сразу. Если тур уже в списке, ничего не меняется. Если список не загрузился, избранное не трогается и показывается тост «Не удалось добавить тур в избранное. Попробуйте ещё раз». Повтора в фоне нет.

Заявка. Если тур не загрузился, намерение стирается и показывается тост «Не удалось открыть тур, заявка не отправлена. Обновите страницу и попробуйте снова».

Тесты: src/store/authIntent.test.ts, src/pages/TourDetailPage.test.tsx.

Доменная логика на клиенте

src/domain/:

  • tourWizard.ts: шаги мастера и перевод формы в запросы;
  • tourManageErrors.ts: тексты для кодов проверки публикации (title, images.cover и другие, см. Конструктор и публикация тура); тест следит, чтобы у каждого кода был текст.

Сборка и nginx

Dockerfile: сборка npm ci и npm run build в node:24-alpine, результат копируется в nginx:alpine. Конфигурация nginx (nginx.conf, nginx-domain.conf.template, nginx-entrypoint.sh) выбирает режим по смонтированным файлам: HTTP, HTTPS с доменом, basic auth. Подробно: Где и как работает.

Локально

cd src/Frontend/travel-agency-frontend
npm ci
npm run dev        # http://localhost:5173, /api проксируется на http://localhost:5001
npm run test:run   # тесты
npm run lint

Dev-сервер Vite убирает из cookie атрибуты Secure и Domain, чтобы вход работал по http://localhost. Подробно: Локальная разработка.

Настройки сборки

Переменная Что
VITE_API_URL адрес API, по умолчанию /api/v1
VITE_CHAT_HUB_URL адрес хаба чата, по умолчанию ${origin}/api/v1/chat/hubs/chat

Clone this wiki locally