|
|
@@ -0,0 +1,120 @@
|
|
|
+# Редактирование и удаление тегов/характеристик через админку
|
|
|
+
|
|
|
+**Контекст**: В админке на странице `/admin/tags` отсутствовала возможность редактировать и удалять существующие теги и характеристики. Только создание новых.
|
|
|
+
|
|
|
+## Решение
|
|
|
+
|
|
|
+Добавлен полный CRUD с inline-редактированием и анимированным подтверждением удаления.
|
|
|
+
|
|
|
+### Бэкенд
|
|
|
+
|
|
|
+```go
|
|
|
+// repository/tags.go — методы Update
|
|
|
+func (r *TagRepo) Update(ctx context.Context, id string, tag *models.Tag) error {
|
|
|
+ _, err := r.pool.Exec(ctx,
|
|
|
+ `UPDATE tags SET name = $1, category = $2, sort_order = $3 WHERE id = $4`,
|
|
|
+ tag.Name, tag.Category, tag.SortOrder, id)
|
|
|
+ return err
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+Аналогично для `FeatureRepo`.
|
|
|
+
|
|
|
+Роуты:
|
|
|
+```
|
|
|
+PUT /admin/tags → tagHandler.UpdateTag
|
|
|
+PUT /admin/features → tagHandler.UpdateFeature
|
|
|
+```
|
|
|
+
|
|
|
+Редактируется только `name` (ID/slug не меняется во избежание поломки связей).
|
|
|
+
|
|
|
+### Фронтенд — компонент `/admin/tags`
|
|
|
+
|
|
|
+```mermaid
|
|
|
+graph LR
|
|
|
+ A[Строка] --> B{showConfirm?}
|
|
|
+ B -->|нет| C[✏️🗑️]
|
|
|
+ B -->|да| D[✓✕]
|
|
|
+ C -->|✏️| E[input + ✓✕]
|
|
|
+ C -->|🗑️| F[text + ✓✕]
|
|
|
+ D -->|✓| G[saveTag / confirmDeleteTag]
|
|
|
+ D -->|✕| H[отмена]
|
|
|
+```
|
|
|
+
|
|
|
+### Анимация кнопок
|
|
|
+
|
|
|
+Используется паттерн с `absolute inset-0 overflow-hidden` контейнером и `translate-y` + `opacity`:
|
|
|
+
|
|
|
+```tsx
|
|
|
+<div className="relative h-5 w-12 overflow-hidden">
|
|
|
+ {/* ✏️🗑️ — уезжают вверх */}
|
|
|
+ <div className={`absolute inset-0 flex items-center gap-2 [&>button]:w-5 transition-all duration-200 ${
|
|
|
+ showConfirm ? '-translate-y-full opacity-0' : 'translate-y-0 opacity-100'
|
|
|
+ }`}>
|
|
|
+ <button>✏️</button>
|
|
|
+ <button>🗑️</button>
|
|
|
+ </div>
|
|
|
+ {/* ✓✕ — выезжают снизу */}
|
|
|
+ <div className={`absolute inset-0 flex items-center gap-2 [&>button]:w-5 transition-all duration-200 ${
|
|
|
+ showConfirm ? 'translate-y-0 opacity-100' : 'translate-y-full opacity-0'
|
|
|
+ }`}>
|
|
|
+ <button>✓</button>
|
|
|
+ <button>✕</button>
|
|
|
+ </div>
|
|
|
+</div>
|
|
|
+```
|
|
|
+
|
|
|
+`[&>button]:w-5` гарантирует идентичную ширину всех кнопок — значки ✓✕ встают точно на места ✏️🗑️.
|
|
|
+
|
|
|
+- ✓ зелёный при редактировании, красный при удалении
|
|
|
+- Escape / Enter работают при редактировании (input autoFocus)
|
|
|
+- `confirm()` браузера заменён на inline-анимацию
|
|
|
+
|
|
|
+### Единая строка
|
|
|
+
|
|
|
+Редактирование и удаление используют общий layout:
|
|
|
+```
|
|
|
+[имя (span → input) | id | кнопки]
|
|
|
+```
|
|
|
+При редактировании `span` заменяется на `input`. При удалении имя не меняется. Блок кнопок анимируется одинаково в обоих случаях.
|
|
|
+
|
|
|
+## Обнаруженные проблемы
|
|
|
+
|
|
|
+### 1. CORS: PUT не был в AllowedMethods
|
|
|
+
|
|
|
+```go
|
|
|
+// Было:
|
|
|
+AllowedMethods: []string{"GET", "POST", "PATCH", "DELETE", "OPTIONS"}
|
|
|
+// Стало:
|
|
|
+AllowedMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"}
|
|
|
+```
|
|
|
+
|
|
|
+Без PUT браузер блокировал preflight OPTIONS — фронтенд получал «Failed to fetch».
|
|
|
+
|
|
|
+### 2. 204 No Content при DELETE — ошибка парсинга JSON
|
|
|
+
|
|
|
+Бэкенд возвращает `w.WriteHeader(http.StatusNoContent)` (204) — тело пустое. `res.json()` на пустом теле бросал `"Unexpected end of JSON input"`.
|
|
|
+
|
|
|
+```typescript
|
|
|
+// api.ts — добавлена проверка
|
|
|
+if (res.status === 204) return undefined as T
|
|
|
+return res.json()
|
|
|
+```
|
|
|
+
|
|
|
+### 3. `api.put()` отсутствовал в клиенте
|
|
|
+
|
|
|
+Добавлен метод `put` в объект `api` (рядом с `patch`).
|
|
|
+
|
|
|
+## Связанные заметки
|
|
|
+
|
|
|
+- [[atomic-api-contract-deleted-fulldelete]] — удаление через query-параметр
|
|
|
+- [[MOC-frontend-patterns]] — фронтенд-паттерны
|
|
|
+- [[frontend-api-client]] — API client
|
|
|
+
|
|
|
+## Источник
|
|
|
+
|
|
|
+Задача: «Добавь возможность редактировать и удалять теги через админку». Коммиты: `86b0c22`, `603a3d4`, `5a4f50f`, `f137544`, `bf098a7`, `7b97fd1`, `679cdd7`.
|
|
|
+
|
|
|
+## Теги
|
|
|
+
|
|
|
+#frontend #backend #golang #nextjs #admin #animation #cors #api
|