Feat: Add inline category creation in catalog with clickable product names

Added inline category creation functionality to catalog page with user-friendly interface:
- Inline input fields for creating root and nested categories
- '+' button in category tree header for root categories
- '+' icon on hover for each category node to create subcategories
- Clickable product/kit names in catalog grid and list views
- AJAX API endpoint for category creation with validation
- User-friendly error messages for duplicate names and constraints
- Clean implementation using clearTimeout pattern to prevent duplicate requests

Technical details:
- New API endpoint: POST /products/api/categories/create/
- Auto-generates slug and SKU for new categories
- Validates uniqueness, parent existence, and circular references
- Single-request submission with proper race condition handling
- Removes debug logging for production-ready code

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-25 00:24:05 +03:00
parent 03990292a5
commit d566819367
5 changed files with 344 additions and 7 deletions

View File

@@ -118,8 +118,9 @@
.catalog-list .catalog-item .card-body .mt-1 {
margin-top: 0 !important;
}
/* Кнопка переименования категории */
.category-rename-btn {
/* Кнопки управления категориями (переименование, добавление подкатегории) */
.category-rename-btn,
.category-add-child-btn {
opacity: 0;
cursor: pointer;
color: #6c757d;
@@ -127,13 +128,18 @@
padding: 2px 4px;
transition: opacity 0.2s, color 0.15s;
}
.category-header:hover .category-rename-btn {
.category-header:hover .category-rename-btn,
.category-header:hover .category-add-child-btn {
opacity: 0.5;
}
.category-rename-btn:hover {
opacity: 1 !important;
color: #0d6efd;
}
.category-add-child-btn:hover {
opacity: 1 !important;
color: #198754;
}
</style>
{% endblock %}
@@ -145,9 +151,12 @@
<div class="card shadow-sm border-0 mb-3">
<div class="card-header bg-white py-2 d-flex justify-content-between align-items-center">
<strong><i class="bi bi-folder-tree text-primary"></i> Категории</strong>
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-secondary btn-sm py-0" id="expand-all" title="Развернуть"><i class="bi bi-plus-square"></i></button>
<button class="btn btn-outline-secondary btn-sm py-0" id="collapse-all" title="Свернуть"><i class="bi bi-dash-square"></i></button>
<div class="d-flex gap-2">
<i class="bi bi-plus-circle text-success cursor-pointer" id="add-root-category-btn" title="Добавить категорию" style="font-size: 1.2rem; cursor: pointer;"></i>
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-secondary btn-sm py-0" id="expand-all" title="Развернуть"><i class="bi bi-plus-square"></i></button>
<button class="btn btn-outline-secondary btn-sm py-0" id="collapse-all" title="Свернуть"><i class="bi bi-dash-square"></i></button>
</div>
</div>
</div>
<div class="card-body p-2 category-tree">
@@ -200,7 +209,13 @@
</span>
</div>
<div class="card-body p-2">
<div class="small text-truncate fw-medium">{{ item.name }}</div>
<div class="small text-truncate fw-medium">
{% if item.item_type == 'kit' %}
<a href="{% url 'products:productkit-detail' item.pk %}" class="text-decoration-none">{{ item.name }}</a>
{% else %}
<a href="{% url 'products:product-detail' item.pk %}" class="text-decoration-none">{{ item.name }}</a>
{% endif %}
</div>
<div class="d-flex justify-content-between align-items-center mt-1">
<span class="fw-bold text-primary small">{{ item.actual_price|floatformat:0 }} ₽</span>
<small class="text-muted">{{ item.sku }}</small>

View File

@@ -16,6 +16,7 @@
<span class="badge bg-light text-dark border" style="font-size: 0.7rem;">{{ products_count|add:kits_count }}</span>
{% endif %}
{% endwith %}
<i class="bi bi-plus-circle category-add-child-btn" data-parent-id="{{ node.category.pk }}" title="Добавить подкатегорию"></i>
<i class="bi bi-pencil category-rename-btn" data-category-id="{{ node.category.pk }}" title="Переименовать"></i>
</div>