|
|
@@ -23,8 +23,10 @@ export default function AdminTagsPage() {
|
|
|
|
|
|
const [editingTagId, setEditingTagId] = useState<string | null>(null)
|
|
|
const [editTagName, setEditTagName] = useState('')
|
|
|
+ const [deletingTagId, setDeletingTagId] = useState<string | null>(null)
|
|
|
const [editingFeatureId, setEditingFeatureId] = useState<string | null>(null)
|
|
|
const [editFeatureName, setEditFeatureName] = useState('')
|
|
|
+ const [deletingFeatureId, setDeletingFeatureId] = useState<string | null>(null)
|
|
|
|
|
|
const fetchData = async () => {
|
|
|
try {
|
|
|
@@ -89,10 +91,10 @@ export default function AdminTagsPage() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- const deleteTag = async (id: string) => {
|
|
|
- if (!confirm('Удалить тег «' + id + '»?')) return
|
|
|
+ const confirmDeleteTag = async (id: string) => {
|
|
|
try {
|
|
|
await api.delete('/admin/tags?id=' + encodeURIComponent(id))
|
|
|
+ setDeletingTagId(null)
|
|
|
setError('')
|
|
|
fetchData()
|
|
|
} catch (err) {
|
|
|
@@ -122,10 +124,10 @@ export default function AdminTagsPage() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- const deleteFeature = async (id: string) => {
|
|
|
- if (!confirm('Удалить характеристику «' + id + '»?')) return
|
|
|
+ const confirmDeleteFeature = async (id: string) => {
|
|
|
try {
|
|
|
await api.delete('/admin/features?id=' + encodeURIComponent(id))
|
|
|
+ setDeletingFeatureId(null)
|
|
|
setError('')
|
|
|
fetchData()
|
|
|
} catch (err) {
|
|
|
@@ -184,16 +186,40 @@ export default function AdminTagsPage() {
|
|
|
<span className="text-sm text-white">{tag.name}</span>
|
|
|
<div className="flex items-center gap-2">
|
|
|
<span className="text-xs text-white/40">{tag.id}</span>
|
|
|
- <button onClick={() => startEditTag(tag)}
|
|
|
- className="text-xs text-white/40 hover:text-white"
|
|
|
- title="Редактировать">
|
|
|
- ✏️
|
|
|
- </button>
|
|
|
- <button onClick={() => deleteTag(tag.id)}
|
|
|
- className="text-xs text-white/40 hover:text-red-400"
|
|
|
- title="Удалить">
|
|
|
- 🗑️
|
|
|
- </button>
|
|
|
+ <div className="relative h-5 w-12 overflow-hidden">
|
|
|
+ <div className={`absolute inset-0 flex items-center gap-2 transition-all duration-200 ${
|
|
|
+ deletingTagId === tag.id
|
|
|
+ ? '-translate-y-full opacity-0'
|
|
|
+ : 'translate-y-0 opacity-100'
|
|
|
+ }`}>
|
|
|
+ <button onClick={() => startEditTag(tag)}
|
|
|
+ className="text-xs text-white/40 hover:text-white"
|
|
|
+ title="Редактировать">
|
|
|
+ ✏️
|
|
|
+ </button>
|
|
|
+ <button onClick={() => setDeletingTagId(tag.id)}
|
|
|
+ className="text-xs text-white/40 hover:text-red-400"
|
|
|
+ title="Удалить">
|
|
|
+ 🗑️
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ <div className={`absolute inset-0 flex items-center gap-2 transition-all duration-200 ${
|
|
|
+ deletingTagId === tag.id
|
|
|
+ ? 'translate-y-0 opacity-100'
|
|
|
+ : 'translate-y-full opacity-0'
|
|
|
+ }`}>
|
|
|
+ <button onClick={() => confirmDeleteTag(tag.id)}
|
|
|
+ className="text-xs text-green-400 hover:text-green-300"
|
|
|
+ title="Подтвердить удаление">
|
|
|
+ ✓
|
|
|
+ </button>
|
|
|
+ <button onClick={() => setDeletingTagId(null)}
|
|
|
+ className="text-xs text-white/40 hover:text-white"
|
|
|
+ title="Отмена">
|
|
|
+ ✕
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</>
|
|
|
)}
|
|
|
@@ -244,16 +270,40 @@ export default function AdminTagsPage() {
|
|
|
<span className="text-sm text-white">{feat.name}</span>
|
|
|
<div className="flex items-center gap-2">
|
|
|
<span className="text-xs text-white/40">{feat.id}</span>
|
|
|
- <button onClick={() => startEditFeature(feat)}
|
|
|
- className="text-xs text-white/40 hover:text-white"
|
|
|
- title="Редактировать">
|
|
|
- ✏️
|
|
|
- </button>
|
|
|
- <button onClick={() => deleteFeature(feat.id)}
|
|
|
- className="text-xs text-white/40 hover:text-red-400"
|
|
|
- title="Удалить">
|
|
|
- 🗑️
|
|
|
- </button>
|
|
|
+ <div className="relative h-5 w-12 overflow-hidden">
|
|
|
+ <div className={`absolute inset-0 flex items-center gap-2 transition-all duration-200 ${
|
|
|
+ deletingFeatureId === feat.id
|
|
|
+ ? '-translate-y-full opacity-0'
|
|
|
+ : 'translate-y-0 opacity-100'
|
|
|
+ }`}>
|
|
|
+ <button onClick={() => startEditFeature(feat)}
|
|
|
+ className="text-xs text-white/40 hover:text-white"
|
|
|
+ title="Редактировать">
|
|
|
+ ✏️
|
|
|
+ </button>
|
|
|
+ <button onClick={() => setDeletingFeatureId(feat.id)}
|
|
|
+ className="text-xs text-white/40 hover:text-red-400"
|
|
|
+ title="Удалить">
|
|
|
+ 🗑️
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ <div className={`absolute inset-0 flex items-center gap-2 transition-all duration-200 ${
|
|
|
+ deletingFeatureId === feat.id
|
|
|
+ ? 'translate-y-0 opacity-100'
|
|
|
+ : 'translate-y-full opacity-0'
|
|
|
+ }`}>
|
|
|
+ <button onClick={() => confirmDeleteFeature(feat.id)}
|
|
|
+ className="text-xs text-green-400 hover:text-green-300"
|
|
|
+ title="Подтвердить удаление">
|
|
|
+ ✓
|
|
|
+ </button>
|
|
|
+ <button onClick={() => setDeletingFeatureId(null)}
|
|
|
+ className="text-xs text-white/40 hover:text-white"
|
|
|
+ title="Отмена">
|
|
|
+ ✕
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</>
|
|
|
)}
|