Docs: sync booking expired (Back#60) + Front#31 UX polish. Fixes EventHub/EventHubSpec#13
This commit is contained in:
+25
-10
@@ -53,10 +53,15 @@ Deep-link на календарь, владельцем которого явл
|
||||
- Главные вкладки: **Календарь** (`/`, `/c/:id`), **Найти** (`/search`), **Записи** (`/bookings`), **Ещё** (`/more`).
|
||||
- **Записи** (`/bookings`) — grouped inbox: «К подтверждению» (owner/specialist pending + Confirm/Decline)
|
||||
и «Мои записи» (participant); пустые группы скрывать. Confirm на карточке события остаётся.
|
||||
- В **Ещё**: пункт входящих specialist invites скрыт при `pending=0` (deep-link `/invites` работает).
|
||||
Past/expired: бейдж `expired` («истекла»), Cancel скрыт; empty-state с CTA Discover / календари.
|
||||
Время на list-карточках — вторичное к title (`.eh-book-list-time`).
|
||||
- В **Ещё**: пункт входящих specialist invites скрыт при `pending=0`; при `pending > 0` —
|
||||
badge со счётчиком (deep-link `/invites` работает).
|
||||
- Контекст виджета: свой календарь (селектор) или чужой (browse после поиска). Чужой `personal` —
|
||||
только просмотр; чужой `commercial` с `booking_open=true` — запись; при `booking_open=false`
|
||||
(restricted / нет подписки владельца) — просмотр + сообщение «Запись временно недоступна».
|
||||
- Agenda rail: empty copy зависит от типа календаря — personal «Нет событий», commercial
|
||||
«Нет слотов».
|
||||
- Выбор события открывает карточку действий: mobile — bottom sheet; desktop — боковая панель. Действия зависят от роли (owner / participant).
|
||||
- Без выбранного события — панель «О календаре» (описание, title/meta, рейтинг, отзывы).
|
||||
Форма отзыва на календарь/событие — только при confirmed booking; жалоба доступна без записи.
|
||||
@@ -69,7 +74,9 @@ Deep-link на календарь, владельцем которого явл
|
||||
- Поиск (`/search`): query/filters в URL params (восстановление при возврате); chip type фильтрует
|
||||
discovery tops без ухода из Popular; в строке результата — id snippet и `calendar_title` для event.
|
||||
- CRUD своих календарей — `/calendars` (из «Ещё»). Legacy `/discover`, `/calendars/:id` → redirects.
|
||||
- На мобиле — bottom tab bar (+ safe-area); на desktop — sticky header + табы.
|
||||
- На мобиле — bottom tab bar (+ safe-area); на desktop — **одна строка** chrome:
|
||||
logo | nav tabs | nickname + logout (не два ряда header+nav). Сырой email в chrome
|
||||
не показывать — primary identity = `nickname` (fallback без `@`).
|
||||
Nav `aria-current` синхронизирован с `useLocation` (без remount `Outlet` по pathname).
|
||||
- Mood themes — см. §3.2.
|
||||
|
||||
@@ -85,7 +92,7 @@ Deep-link на календарь, владельцем которого явл
|
||||
| MOMENTUM | `energetic` | тёмный ink + coral `#FF6A3D` |
|
||||
| CONTROL | `business` | charcoal + steel `#324A5F`, более жёсткие радиусы |
|
||||
|
||||
Переключатели mood и языка: на экранах auth (`/login`, `/register`, `/verify`) и в `/more`. В шапке workspace — wordmark CalenTIQ (Time Arc), email и выход (без mood/lang).
|
||||
Переключатели mood и языка: на экранах auth (`/login`, `/register`, `/verify`) и в `/more`. В шапке workspace — wordmark CalenTIQ (Time Arc), **nickname** (не raw email) и выход (без mood/lang). Desktop chrome — одна строка: logo | nav | logout.
|
||||
|
||||
Язык UI (`ru`/`en`): до логина — `navigator.language`; после входа — поле `language` профиля (`PATCH /v1/user/me`). Если в профиле язык пуст — при логине записывается текущий (браузерный/выбранный на экране входа). Язык также можно сменить в форме `/profile`.
|
||||
|
||||
@@ -103,7 +110,8 @@ Deep-link на календарь, владельцем которого явл
|
||||
(B) мои записи участника; deep-link в `/c/.../e/...`
|
||||
- `/calendars` — управление своими календарями (CRUD)
|
||||
- `/more` — вторичное меню + mood switcher; пункт specialist invites **скрыт**,
|
||||
если входящих pending = 0 (deep-link `/invites?token=` работает)
|
||||
если входящих pending = 0; при pending > 0 — badge со счётчиком
|
||||
(deep-link `/invites?token=` работает)
|
||||
- `/invites` — inbox входящих specialist invites (не смешивать с `/bookings`)
|
||||
- `/following` — отслеживаемые чужие календари (follow; не платная Подписка)
|
||||
- `/reviews`, `/subscription`, `/tickets`, `/profile`
|
||||
@@ -122,7 +130,9 @@ Redirects: `/discover` → `/search`; `/calendars/:id` → `/c/:id`; `/calendars
|
||||
|
||||
### 5.3. Поиск (участник)
|
||||
`GET /v1/search` — фильтры (`type`, `q`, `tags`, даты, `lat`/`lon`/`radius`, sort, order, пагинация). Без `q`/дат/tags/geo/sort — топы календарей и событий; иначе — поиск. В списке бейдж типа — `calendar`|`event` (не `personal`/`commercial`). Даты, теги, geo и сортировка свёрнуты по умолчанию. Переход к `/c/:id` или `/c/:id/e/:eventId`.
|
||||
В результатах calendar (и event, если Back отдаёт) может быть `image_url` — Discover показывает cover; иначе mood wash + initials. **Upload API нет** — поле URL (seed / ручная установка).
|
||||
В результатах calendar (и event, если Back отдаёт) может быть `image_url` — Discover показывает
|
||||
cover (`.eh-discover-media--photo`); иначе mood wash + initials (`.eh-discover-media--fallback`,
|
||||
не fake photo-hero). Битый `image_url` → fallback. **Upload API нет** — поле URL (seed / ручная установка).
|
||||
|
||||
### 5.4. Календари
|
||||
- Список своих: `GET /v1/calendars`
|
||||
@@ -141,8 +151,8 @@ Redirects: `/discover` → `/search`; `/calendars/:id` → `/c/:id`; `/calendars
|
||||
Баннер «подписка истекла / истекает» при `booking_open=false`.
|
||||
- Invitee: inbox входящих `GET /v1/user/specialist-invites` на `/invites` —
|
||||
принять / отклонить; deep-link из email → accept по `token` после логина.
|
||||
В More пункт «Приглашения» показывается **только** при `pending > 0`
|
||||
(не путать с booking-заявками на `/bookings`).
|
||||
В More пункт «Приглашения» показывается **только** при `pending > 0` с badge
|
||||
счётчика (не путать с booking-заявками на `/bookings`).
|
||||
|
||||
### 5.5. События
|
||||
- Список: `GET /v1/calendars/:calendar_id/events`
|
||||
@@ -157,11 +167,16 @@ Redirects: `/discover` → `/search`; `/calendars/:id` → `/c/:id`; `/calendars
|
||||
- Владелец и specialist:
|
||||
- на карточке события: `GET /v1/events/:id/bookings` + Confirm/Decline (**обязательно**)
|
||||
- inbox `/bookings` группа «К подтверждению»: `GET /v1/user/booking-requests`
|
||||
(pending, где user — owner календаря или `event.specialist_id`); те же
|
||||
`PUT /v1/bookings/:id` `{ action: confirm | decline }`
|
||||
(actionable pending, где user — owner календаря или `event.specialist_id`; past-pending
|
||||
Back отдаёт как `expired` и **не** включает в inbox); те же
|
||||
`PUT /v1/bookings/:id` `{ action: confirm | decline }` (на `expired` → `409`)
|
||||
- UI `/bookings`: две группы (пустые скрывать): **К подтверждению** + **Мои записи**
|
||||
(upcoming/past participant). `specialist_invite` сюда **не** попадает.
|
||||
- Статусы: `pending` | `confirmed` | `cancelled`; confirmation: `auto` | `manual` | timeout
|
||||
Empty state: title + hint + CTA Discover / «Мои календари».
|
||||
Время слота на list-карточках — soft (secondary to title).
|
||||
- Статусы: `pending` | `confirmed` | `cancelled` | `expired`; confirmation: `auto` | `manual` | timeout.
|
||||
Past+pending / `expired` в «Мои записи» — бейдж «истекла», Cancel скрыт (в т.ч. на
|
||||
`EventActionCard`). Defensive: если API ещё отдал past `pending` — UI мапит в `expired`.
|
||||
- Pending резервирует capacity (как на бэке)
|
||||
|
||||
### 5.7. Отзывы
|
||||
|
||||
Reference in New Issue
Block a user