feat(categories): implement professional category management experience

Categories dashboard (real total/visible/hidden/empty/root/subcategory/missing-image/missing-SEO/last-modified/completion% stats, recommended next action); tree view is now a real expand/collapse hierarchy (state persisted via LocalStorageService) with keyboard navigation (arrow keys, jump-to-parent), search that force-expands and keeps only matching branches + their ancestors/descendants instead of silently dropping deep matches; added Table/Cards views alongside the tree with density and saved column visibility; real bulk actions (show/hide/delete/assign parent/assign image via the Media Library picker/duplicate via the existing createCategory call/CSV export) plus the pre-existing single-item actions; reusable CategoryHealthWidget (image/SEO/description/valid-parent/visibility/products-assigned + completion%); editor reorganized into General/Media/SEO/Visibility/Navigation/Attributes/Advanced tabs, media now uses the shared ImageFieldComponent, SEO explains fields in plain language with a live preview, Navigation tab shows real breadcrumb/children/visibility-based nav status, Attributes uses the shared KeyValueEditorComponent. Filled in the adminCategories i18n namespace (previously only 2 of ~90 referenced keys existed) across en/ru/hy. Also fixed the pre-existing bug where a filtered/searched category list could silently drop a matched descendant whose ancestor's title didn't match, by loading the full catalog once and filtering client-side.
This commit is contained in:
sdarbinyan
2026-07-18 17:04:11 +04:00
parent aeb48504c5
commit ac615837ab
22 changed files with 1433 additions and 117 deletions

View File

@@ -1216,6 +1216,84 @@ export const ru: Translations = {
adminCategories: {
chooseImage: 'Выбрать изображение',
replaceImage: 'Заменить изображение',
search: 'Поиск категорий…',
showDeleted: 'Показать удалённые',
create: 'Создать категорию',
edit: 'Редактировать категорию',
title: 'Название',
slug: 'URL-адрес',
slugTaken: 'Этот адрес уже используется другой категорией.',
parent: 'Родительская категория',
noParent: 'Без родителя (верхний уровень)',
icon: 'Иконка',
image: 'Изображение',
imageHint: 'Показывается в списках категорий и навигации.',
description: 'Описание',
items: 'товаров',
status: { draft: 'Черновик', published: 'Опубликовано' },
restore: 'Восстановить',
saveDraft: 'Сохранить черновик',
publish: 'Опубликовать',
confirmDelete: 'Удалить эту категорию? Это действие нельзя отменить.',
confirmLeaveUnsaved: 'У вас есть несохранённые изменения. Выйти без сохранения?',
deleteBlocked: 'Эту категорию нельзя удалить, пока у неё есть подкатегории или назначенные товары.',
emptyTitle: 'Категорий пока нет',
emptyDescription: 'Создайте первую категорию, чтобы начать организовывать товары.',
emptyGuide: 'Категории помогают покупателям находить товары. Начните с нескольких верхнеуровневых категорий (например, Одежда, Электроника), затем добавляйте подкатегории по мере роста каталога — избегайте вложенности глубже 2-3 уровней.',
viewTree: 'Дерево',
viewCards: 'Карточки',
expandAll: 'Развернуть всё',
collapseAll: 'Свернуть всё',
expandNode: 'Развернуть',
collapseNode: 'Свернуть',
jumpToParent: 'К родителю',
deletedBadge: 'Удалена',
column_slug: 'Адрес',
column_items: 'Товары',
column_status: 'Статус',
column_visibility: 'Видимость',
column_updated: 'Последнее изменение',
bulkAssignParent: 'Назначить родителя',
bulkAssignImage: 'Назначить изображение',
groupGeneral: 'Основное',
groupMedia: 'Медиа',
groupSeo: 'SEO',
groupVisibility: 'Видимость',
groupNavigation: 'Навигация',
groupAttributes: 'Атрибуты',
groupAdvanced: 'Дополнительно',
visibilityExplain: 'Скрытая категория и её товары не отображаются в навигации и поиске магазина, пока вы снова не сделаете её видимой.',
navBreadcrumb: 'Хлебные крошки',
navRoot: 'Это категория верхнего уровня.',
navChildren: 'Подкатегории',
navNoChildren: 'Подкатегорий пока нет.',
navAppearsIn: 'Где это отображается',
navAppearsVisible: 'Видна в навигации каталога и поиске.',
navAppearsHidden: 'Скрыта — не отображается в навигации каталога, пока скрыта.',
itemsCountLabel: 'Назначенные товары',
createdAtLabel: 'Создана',
healthImage: 'Изображение',
healthSeo: 'SEO',
healthDescription: 'Описание',
healthParent: 'Родитель',
healthVisibility: 'Видимость',
healthProducts: 'Назначены товары',
totalCategories: 'Всего категорий',
visibleCount: 'Видимые',
hiddenCount: 'Скрытые',
emptyCount: 'Пустые',
rootCount: 'Корневые категории',
subCount: 'Подкатегории',
missingImagesCount: 'Без изображений',
missingSeoCount: 'Без SEO',
lastModified: 'Последнее изменение',
lastModifiedNever: 'Никогда',
completionLabel: 'Готовность',
recommendedNext: 'Рекомендуемый следующий шаг',
recommendAddImage: 'У категории нет изображения — добавьте его для доверия в листингах.',
recommendAddSeo: 'У категории нет заголовка или описания для поиска — добавьте их.',
recommendFillEmpty: 'В категории нет товаров — добавьте товары или скройте категорию.',
recommendNone: 'Отлично — структура категорий в хорошем состоянии.',
},
adminProducts: {
emptyTitle: 'Товары не найдены',