# ПРАВИЛА UI/UX КАБИНЕТА СЕЛЛЕРА (SELLER)
> ⚠️ **ВАЖНО**: Это файл с UI/UX деталями кабинета селлера.
> Общие бизнес-правила находятся в **[rules-complete.md](./rules-complete.md)**
## Когда использовать этот файл:
- Работа с компонентами `/supplies`, `/my-supplies`
- UI/UX специфика кабинета селлера
- Интерфейсы создания поставок
- Визуальные правила компонентов селлера
## 1. 🛍️ СТРУКТУРА КАБИНЕТА СЕЛЛЕРА
### 1.1 Основные разделы
**СЕЛЛЕР (`SELLER`)** имеет доступ к следующим разделам:
- **Мои поставки** (`/my-supplies`) - управление поставками
- **Маркет** (`/market`) - просмотр глобального каталога
- **Партнеры** (`/partners`) - управление контрагентами
- **Мессенджер** (`/messenger`) - связь с партнерами
- **Настройки** (`/settings`) - профиль и настройки
- **Экономика** (`/economics`) - финансовая аналитика
### 1.2 Навигация и роутинг
#### При входе в систему:
```typescript
switch (user?.organization?.type) {
case 'SELLER':
router.push('/my-supplies') // Направляем на страницу поставок
break
}
```
#### Специальная логика роутинга:
> 📖 **Бизнес-логика роутинга**: См. [rules-complete.md#4-система-ролей-и-доступов](./rules-complete.md#4--система-ролей-и-доступов)
## 2. 🎨 UI/UX КОМПОНЕНТЫ
### 2.1 Dashboard компоненты
#### Основные компоненты кабинета:
- `SellerHomePage` - главный компонент селлера
- `SellerEconomicsPage` - экономическая аналитика
- `MySuppliesDashboard` - управление поставками
#### Wrapper-компоненты:
- `HomePageWrapper` - маршрутизация по типам организаций
- `EconomicsPageWrapper` - адаптивная экономика по кабинетам
### 2.2 Детальные правила горизонтального скролла поставщиков
**СТРУКТУРА И ОТОБРАЖЕНИЕ:**
- **Источник данных**: Партнеры типа `WHOLESALE` из раздела "Партнеры"
- **Контейнер**: Фиксированная высота 176px (h-44) с горизонтальным скроллом
- **Блок поставщиков**: Общая высота 180px, включает заголовок + контейнер скролла
- **Направление**: Слева направо (LTR)
- **Поведение**: Плавный скролл с автоскрытием полосы прокрутки
**РАЗМЕРЫ И АДАПТИВНОСТЬ:**
- **Десктоп**: Карточка 216×92px, отступы 12px между карточками, 16px от краев
- **Планшет**: Карточка 200×92px, отступы 12px между карточками
- **Мобильный**: Карточка 184×92px, отступы 12px между карточками
- **Высота блока**: 180px фиксированная для всего блока поставщиков
**ВЗАИМОДЕЙСТВИЕ:**
- **Навигация**: Колесо мыши (Shift+скролл), стрелки клавиатуры, свайп на тач
- **Выбор**: Клик по карточке → активная рамка + загрузка товаров в блок 2
- **Состояния**: Default, Hover (box-shadow), Active (цветная рамка), Loading (скелетон)
**ГРАНИЧНЫЕ СЛУЧАИ:**
- **1-4 карточки**: Выравнивание по левому краю, скролл неактивен
- **5+ карточек**: Полный горизонтальный скролл
- **Нет партнеров**: Заглушка с ссылкой на раздел "Партнеры"
**ТЕХНИЧЕСКАЯ РЕАЛИЗАЦИЯ:**
**Критическая Flex-архитектура:**
```css
.parent-container {
display: flex;
gap: 16px;
min-height: 0;
}
.left-block {
flex: 1;
min-width: 0; /* КРИТИЧЕСКИ ВАЖНО для overflow */
display: flex;
flex-direction: column;
}
.suppliers-container {
height: 180px; /* Общая высота блока */
flex-shrink: 0;
min-width: 0; /* Предотвращает растяжение */
}
.right-block {
width: 384px; /* w-96 */
flex-shrink: 0; /* Защита от сжатия */
}
```
**Контейнер скролла:**
```css
.suppliers-block {
display: flex;
overflow-x: auto;
scroll-behavior: smooth;
gap: 12px;
padding: 0 16px 8px 16px; /* px-4 pb-2 */
height: 176px; /* h-44 */
scrollbar-width: thin;
scrollbar-color: #64748b33 transparent;
}
.suppliers-block:hover {
scrollbar-color: #cbd5e0 #64748b22;
}
.supplier-card {
flex-shrink: 0;
width: 216px; /* Десктоп */
height: 92px; /* Фиксированная высота */
padding: 8px; /* p-2 */
transition: all 0.2s ease;
}
```
**СОДЕРЖАНИЕ КАРТОЧКИ ПОСТАВЩИКА:**
**Структура (3 строки в 92px высоты):**
- **Строка 1**: Название + рейтинг (справа, если есть)
- **Строка 2**: ИНН (формат "ИНН: 1234567890")
- **Строка 3**: Бейдж рынка (отдельная строка)
**Элементы:**
- **Аватар**: Размер xs, слева с gap-2
- **Текст**: text-xs для компактности
- **Отступы**: mb-1 между строками 1-2, mb-0.5 между строками 2-3
- **Padding карточки**: 8px (p-2)
**ЦВЕТОВАЯ СХЕМА РЫНКОВ:**
- **"Садовод"** (sadovod): Зеленый `bg-green-500/20 text-green-300 border-green-500/30`
- **"ТЯК Москва"** (tyak-moscow): Синий `bg-blue-500/20 text-blue-300 border-blue-500/30`
- **Другие/не указан**: Серый `bg-gray-500/20 text-gray-300 border-gray-500/30`
**ДОСТУПНОСТЬ:**
- `role="tablist"` для контейнера
- `role="tab"` для карточек
- `aria-selected="true/false"` для выбранной карточки
- `tabindex="0"` для активной, `-1` для неактивных
### 2.3 Правила блока "Карточки товаров" (Блок 2)
**НАЗНАЧЕНИЕ И ЛОГИКА:**
- **Источник данных**: Товары выбранного поставщика из Блока 1
- **Триггер отображения**: Клик на карточку поставщика → загрузка карточек товаров
- **Взаимодействие**: Клик на карточку товара → добавление в Блок 3 "Товары поставщика"
- **Поведение**: Горизонтальный скролл при множестве товаров
**АРХИТЕКТУРА И РАЗМЕРЫ:**
- **Внешний контейнер**: bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl flex-shrink-0
- **Внутренний контейнер скролла**: flex gap-3 overflow-x-auto p-4
- **Стилизация скролла**: scrollbarWidth: 'thin' для тонкой полосы прокрутки
- **Отступы**: padding: 16px (p-4) внутри, gap: 12px (gap-3) между карточками
- **Адаптивная высота**: по содержимому карточек (БЕЗ фиксированной высоты)
- **Визуальное единство**: стеклянный эффект как у других блоков системы
- **БЕЗ заголовков/иконок**: только чистые карточки товаров в контейнере
**РАЗМЕРЫ КАРТОЧЕК ТОВАРОВ:**
- **Компактная карточка**: 80×112px (w-20 h-28), соотношение 5:7
- **Адаптивность**: фиксированный размер для всех устройств
**СОДЕРЖАНИЕ КАРТОЧКИ ТОВАРА:**
- **ТОЛЬКО изображение товара**: 80×112px, object-cover
- **Минималистичный дизайн**: БЕЗ текста, названий, цен, иконок
- **Состояния**: Default, Selected, Active (БЕЗ Hover-эффектов)
- **Рамка**: border-white/10, при выборе border-white/30
- **Фон**: bg-white/5 полупрозрачный
**ДЕЙСТВИЕ:**
Клик на карточку → добавление товара в Блок 3 (детальный каталог)
### 2.4 ПРАВИЛА КОРЗИНЫ - ЕДИНЫЙ СТАНДАРТ
**КРИТИЧЕСКИ ВАЖНО**: Все корзины в системе должны следовать единому стандарту дизайна и функциональности.
#### **2.4.1 Размеры и позиционирование**
```tsx
```
**ОБЯЗАТЕЛЬНЫЕ ПАРАМЕТРЫ**:
- **Ширина**: `w-72` (288px) - фиксированная ширина для всех корзин
- **Флекс**: `flex-shrink-0` - корзина не сжимается
- **Позиция**: `sticky top-0` - прилипает к верху при прокрутке
- **Стиль**: Glass morphism эффект с `backdrop-blur` и `bg-white/10`
#### **2.4.2 Автодобавление товаров**
**ПРАВИЛО AUTO-ADD**: При вводе количества товар автоматически добавляется в корзину.
```tsx
// ОБЯЗАТЕЛЬНАЯ РЕАЛИЗАЦИЯ:
const handleQuantityChange = (e: React.ChangeEvent) => {
const inputValue = e.target.value
const newQuantity = inputValue === '' ? 0 : Math.max(0, parseInt(inputValue) || 0)
if (newQuantity > 0) {
// Автоматически добавляем товар в корзину
updateProductQuantity(product.id, newQuantity)
} else {
// Удаляем товар из корзины при количестве 0
removeFromCart(product.id)
}
}
```
**ДЕФОЛТНОЕ ЗНАЧЕНИЕ**: Пустой инпут (`value={''}`) вместо `value={0}`
#### **2.4.3 Структура корзины**
**ОБЯЗАТЕЛЬНЫЕ ЭЛЕМЕНТЫ**:
1. **Заголовок**: "Корзина (X шт)" с иконкой корзины
2. **Список товаров**:
- Название товара (БЕЗ суффикса "(с рецептурой)")
- Цена за единицу × количество
- Кнопка удаления (X справа)
3. **Мета-информация**: Дата поставки, фулфилмент-центр, логистика
4. **Итого**: Общая сумма с выделением зелёным цветом
5. **Кнопка действия**: "Создать поставку" с градиентом
**ЗАПРЕЩЕНО**: Отображать текст "(с рецептурой)" в названиях товаров в корзине
#### **2.4.4 Единая функция расчета стоимости**
**КРИТИЧЕСКИ ВАЖНО**: Использовать единую функцию расчета для избежания расхождений:
```tsx
const getProductTotalWithRecipe = (productId: string, quantity: number) => {
const product = products.find((p) => p.id === productId)
if (!product) return 0
// Базовая цена товара
let total = (product.pricePerUnit || 0) * quantity
// Добавляем услуги
if (product.services && product.services.length > 0) {
const servicesTotal = product.services.reduce((sum, service) => {
return sum + (service.pricePerUnit || 0) * quantity
}, 0)
total += servicesTotal
}
// Добавляем FF расходники (используем .price, НЕ .pricePerUnit!)
if (product.ffConsumables && product.ffConsumables.length > 0) {
const ffConsumablesTotal = product.ffConsumables.reduce((sum, consumable) => {
return sum + (consumable.price || 0) * quantity // ВАЖНО: .price!
}, 0)
total += ffConsumablesTotal
}
// Добавляем расходники продавца
if (product.sellerConsumables && product.sellerConsumables.length > 0) {
const sellerConsumablesTotal = product.sellerConsumables.reduce((sum, consumable) => {
return sum + (consumable.pricePerUnit || 0) * quantity
}, 0)
total += sellerConsumablesTotal
}
return total
}
```
#### **2.4.5 Синхронизация данных между блоками**
**ПРАВИЛО СИНХРОНИЗАЦИИ**: Данные в корзине должны отражать выборы из всех блоков формы:
1. **Дата поставки**: Из Блока 3 (дата пикер)
2. **Фулфилмент-центр**: Название выбранного FF (реальные данные!)
3. **Логистическая компания**: Только партнеры типа `'LOGIST'`
**ПОРЯДОК ОТОБРАЖЕНИЯ В КОРЗИНЕ**:
```
Дата поставки: 08.08.2025
Фулфилмент-центр: ФУЛФИЛМЕНТ РУ
Логистическая компания: [Выпадающий список]
```
#### **2.4.6 Критические требования**
🚨 **БЕЗОПАСНОСТЬ ТИПОВ**:
- Всегда проверять на `null/undefined`: `selectedSupplier?.id || ''`
- Использовать optional chaining для всех вложенных объектов
🚨 **ПРОИЗВОДИТЕЛЬНОСТЬ**:
- Мемоизация расчетов: `useMemo` для дорогих вычислений
- Debounce для инпутов количества
🚨 **UX КОНСИСТЕНТНОСТЬ**:
- Единые стили для всех корзин в системе
- Одинаковое поведение auto-add во всех формах
- Синхронная валидация данных
### 2.5 Трёхблочная архитектура страницы "Мои поставки"
**ПРИНЦИП**: Страница состоит из трёх визуально разделённых блоков
```
┌─────────────────────────────────────────┐
│ 1. БЛОК ТАБОВ (навигация) │
│ - Фиксированная высота │
│ - Glass-эффект │
│ - Иерархическая структура │
├─────────────────────────────────────────┤
│ 2. БЛОК СТАТИСТИКИ (метрики) │
│ - Контекстные данные │
│ - 4 карточки в ряд (desktop) │
│ - Динамическое обновление │
├─────────────────────────────────────────┤
│ 3. ОСНОВНОЙ БЛОК (контент) │
│ - Сохраняет весь функционал │
│ - Таблицы, фильтры, действия │
│ - Высота до низа sidebar │
└─────────────────────────────────────────┘
```
**ПРАВИЛО**: Статистика меняется в зависимости от выбранных табов
**Для путей "Фулфилмент → Товар → Карточки/Поставщики":**
- Всего поставок
- Активных поставок
- Сумма активных поставок
- В пути
**ФОРМУЛА РАСЧЕТА ВЫСОТЫ**:
```css
height: calc(100vh - headerHeight - tabsHeight - statsHeight - margins);
```
**ПРАВИЛО ВЫРАВНИВАНИЯ**:
- Нижняя граница основного блока должна быть на одном уровне с нижней границей sidebar
- При изменении размера окна высота пересчитывается
- Внутренний скролл: `overflow-y-auto`
### 2.6 Четырёхблочная архитектура создания поставки расходников
#### **Структура страницы**:
**БЛОК 1: ПОСТАВЩИКИ** _(обязательный, 180px)_:
- Карточки поставщиков из раздела "Партнеры"
- Горизонтальный скролл при превышении ширины
- Выбор только одного поставщика одновременно
**БЛОК 2: КАРТОЧКИ ТОВАРОВ** _(адаптивная высота - НОВЫЙ БЛОК)_:
- ТОЛЬКО минималистичные карточки товаров 80×112px
- ТОЛЬКО изображение товара, БЕЗ текста/названий/цен
- Горизонтальный скролл при множестве товаров
- Клик добавляет товар в блок 3
**БЛОК 3: ТОВАРЫ ПОСТАВЩИКА** _(flex-1, детальный каталог)_:
- Детальные карточки выбранных товаров
- Управление количеством и параметрами поставки
**БЛОК 4: КОРЗИНА И НАСТРОЙКИ** _(правая панель, 384px)_:
- Корзина поставки с выбранными товарами
- Настройки поставки (фулфилмент-центр, дата, логистика)
- Сортировка: цена, название, категория
- Фильтры: категория, ценовой диапазон
- Карточка с полем ввода количества и кнопками +/-
**БЛОК 3: КОРЗИНА** _(правая часть)_:
- **РАСПОЛОЖЕНИЕ**: Правая часть экрана
- **СОДЕРЖАНИЕ**:
- Счетчик видов расходников
- Детализация по каждому расходнику (название, количество, цена, сумма)
- Общая сумма всех расходников
- **УПРАВЛЕНИЕ**:
- Изменение количества (с валидацией остатков)
- Удаление позиций
- **ОБЯЗАТЕЛЬНЫЕ ПОЛЯ**:
- Выбор фулфилмент-центра (из партнеров)
- Дата поставки (не прошедшая, по умолчанию - текущая)
### 2.7 Многоуровневая таблица поставок
#### **ПЕРВЫЙ УРОВЕНЬ** _(основной список)_:
- **СОРТИРОВКА**: Номер поставки от большего к меньшему
- **ОБЯЗАТЕЛЬНЫЕ КОЛОНКИ**:
- Порядковый номер поставки
- Количество видов расходников
- Стоимость всей поставки
- Количество категорий
- Статус поставки
#### **ВТОРОЙ УРОВЕНЬ** _(детализация по клику)_:
- **АКТИВАЦИЯ**: По клику на строку первого уровня
- **СОДЕРЖАНИЕ**:
- Название расходника
- Количество
- Цена
- Категория
- Поставщик
- **ОГРАНИЧЕНИЯ**: Только просмотр, редактирование запрещено
## 3. 🛠️ ГРАФИЧЕСКИЙ ИНТЕРФЕЙС И КОМПОНЕНТЫ
### 3.1 React компоненты селлера
**Основные компоненты:**
- `SellerHomePage` - главная страница селлера (4 типо-зависимых компонента)
- `SellerEconomicsPage` - экономическая аналитика селлера
### 3.2 Роутинг для селлера
```typescript
switch (user?.organization?.type) {
case 'SELLER':
router.push('/supplies')
break
}
```
### 3.3 Структура разделов кабинета
**🛍️ СЕЛЛЕР (`SELLER`):**
- Мои поставки (`/supplies`) - управление заказами товаров
- WB Интеграция (`/wb-integration`) - связь с Wildberries
## 4. 🛠️ GRAPHQL API
### 4.1 Основные запросы (Queries)
#### Получение карточек селлера:
```graphql
query GetSellerCards {
myMarketplaceCards {
id
title
marketplace
article
linkedProductId # null если свободна
linkedProduct {
# для отображения занятости
id
name
}
}
}
```
---
**Последнее обновление**: Август 2025
**Связанные файлы**:
- [rules-complete.md](./rules-complete.md) - Общие бизнес-правила
- [visual-design-rules.md](./visual-design-rules.md) - Визуальные правила