Каталог — Категории

Роут: /catalog/categories API: GET /api/v1/categories, POST /api/v1/categories, PATCH /api/v1/categories/{id}, DELETE /api/v1/categories/{id}


Что видит пользователь

Страница с деревом категорий каталога. Вверху — заголовок “Категории”. Дерево отображается рекурсивно (неограниченная вложенность). Внизу дерева — кнопка “Добавить корневую категорию” (только Franchise).


Дерево категорий

Отображение узла

Каждый узел дерева содержит:

ЭлементОписание
Стрелка свёртки / — если есть дочерние категории
НазваниеТекст названия категории
Индикатор статусаЗелёная точка (active) / Серая точка (inactive)
Inline-действияИконки действий (только Franchise, видны при hover)

Inline-действия (Franchise)

ДействиеИконкаЧто происходит
Добавить подкатегориюПоявляется inline text input под узлом. Enter — сохранить, Esc — отмена. API: POST /api/v1/categories с parent_id
ПереименоватьНазвание превращается в inline text input. Enter — сохранить, Esc — отмена. API: PATCH /api/v1/categories/{id}
УдалитьМодалка подтверждения (см. ниже). API: DELETE /api/v1/categories/{id}
Деактивировать / АктивироватьToggleПереключение статуса (см. ниже). API: PATCH /api/v1/categories/{id}

Порядок отображения

  • У каждой категории есть числовое поле display_order
  • MVP: ручной ввод порядкового номера при создании/редактировании
  • Phase 2: drag-and-drop для перетаскивания узлов

Кнопки

КнопкаГдеВидимость
”Добавить корневую категорию”Внизу дереваFranchise

При клике — появляется inline text input в конце дерева (корневой уровень). Enter — сохранить (POST /api/v1/categories без parent_id), Esc — отмена.


Модалки подтверждений

Удаление

Триггер: клик ✗ на узле API: DELETE /api/v1/categories/{id}

Сценарий 1 — Категория содержит подкатегории (CATEGORY_HAS_CHILDREN):

  • Заголовок: “Невозможно удалить”
  • Текст: “Категория содержит подкатегории. Сначала удалите или перенесите их.”
  • Кнопка: “Понятно” (закрывает модалку)

Сценарий 2 — В категории есть товары (CATEGORY_HAS_PRODUCTS):

  • Заголовок: “Невозможно удалить”
  • Текст: “В категории есть товары. Сначала перенесите их.”
  • Кнопка: “Понятно” (закрывает модалку)

Сценарий 3 — нет препятствий:

  • Заголовок: “Удаление категории”
  • Текст: “Удалить категорию [название]? Это действие нельзя отменить.”
  • Кнопки: “Отмена” / “Удалить” (красная)
  • После успеха: убрать узел из дерева, toast “Категория удалена”

Каскадная деактивация

Триггер: toggle деактивации на узле, у которого есть дочерние категории

  • Заголовок: “Деактивация категории”
  • Текст: “Деактивировать [название] и все подкатегории? Товары в них тоже будут деактивированы.”
  • Кнопки: “Отмена” / “Деактивировать” (оранжевая)
  • После успеха: обновить статусы всех затронутых узлов в дереве, toast “Категория и подкатегории деактивированы”

Каскадная активация

(Доработано в ADR-013)

Триггер: toggle активации на узле, у которого есть неактивные дочерние категории

  • Заголовок: “Активация категории”
  • Текст: “Активировать [название]?”
  • Кнопки: “Только эту” / “Вместе с подкатегориями” (зелёная) / “Отмена”
  • “Только эту” → PATCH /api/v1/categories/{id} с is_active: true, cascade: false
  • “Вместе с подкатегориями” → PATCH /api/v1/categories/{id} с is_active: true, cascade: true
  • После успеха: обновить статусы в дереве, toast

Если у узла нет дочерних — модалка не показывается, активация мгновенная.


Состояния

СостояниеЧто показываем
ЗагрузкаSkeleton-дерево (3-4 placeholder-строки с отступами)
Пусто (Franchise)“Категории пока не созданы” + кнопка “Добавить корневую категорию”
Пусто (Franchisee/Manager)“Категории пока не созданы”
Ошибка загрузки”Не удалось загрузить данные” + кнопка “Повторить”

Ролевая видимость

Franchise

  • Видит дерево категорий
  • Все действия: добавление, переименование, удаление, деактивация/активация, кнопка “Добавить корневую категорию”

Franchisee

  • Видит дерево категорий в режиме readonly
  • Нет inline-действий
  • Нет кнопки “Добавить корневую категорию”

Manager

  • Видит дерево категорий в режиме readonly
  • Нет inline-действий
  • Нет кнопки “Добавить корневую категорию”

Cashier

  • 403 Forbidden — нет доступа к странице
  • Редирект на дашборд

Ссылки