Repository navigation
Doc Frontend
src/Frontend/travel-agency-frontend/. Одностраничное приложение: каталог туров для гостей, личный кабинет клиента и кабинет менеджера. В контейнере собирается Vite и раздаётся nginx, тот же nginx проксирует /api/ в Gateway.
Гость открывает /tours?country=Турция:
- Роутер показывает
TourCatalogPage. - Страница через React Query вызывает
getToursизsrc/api/catalog.ts, axios отправляетGET /api/v1/catalog/tours?country=Турция. - Карточки рисуют обложку по адресу
/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 и в сервисах.
src/api/client.ts:
-
baseURL=VITE_API_URLили/api/v1; -
withCredentials: true: браузер сам отправляет cookie сессии, токены в JavaScript не попадают; - при 401 перехватчик один раз вызывает
POST /auth/refresh(параллельные запросы ждут одно обновление) и повторяет запрос; если обновить не удалось, переход на/?auth=login. ДляgetMe401 считается нормой (гость) и переход не делается.
Модули: 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и другие, см. Конструктор и публикация тура); тест следит, чтобы у каждого кода был текст.
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 lintDev-сервер Vite убирает из cookie атрибуты Secure и Domain, чтобы вход работал по http://localhost. Подробно: Локальная разработка.
| Переменная | Что |
|---|---|
VITE_API_URL |
адрес API, по умолчанию /api/v1
|
VITE_CHAT_HUB_URL |
адрес хаба чата, по умолчанию ${origin}/api/v1/chat/hubs/chat
|
Система
API
Сервисы
Как реализовано
Справочное
- Видение продукта
- Дорожная карта
- Этап 1: что осталось
- Этап 2: расширение
- Этап 3: масштабирование
- Концепция сайта и интерфейса
- Шаблон ТЗ