diff --git a/frontend/src/components/common/ConfirmDialog.tsx b/frontend/src/components/common/ConfirmDialog.tsx
new file mode 100644
index 00000000..2d44e451
--- /dev/null
+++ b/frontend/src/components/common/ConfirmDialog.tsx
@@ -0,0 +1,65 @@
+import { Modal } from './Modal'
+import { cn } from '@/lib/utils'
+
+interface ConfirmDialogProps {
+ isOpen: boolean
+ onClose: () => void
+ onConfirm: () => void
+ title: string
+ message: string
+ confirmLabel?: string
+ confirmVariant?: 'destructive' | 'default'
+ isLoading?: boolean
+}
+
+export function ConfirmDialog({
+ isOpen,
+ onClose,
+ onConfirm,
+ title,
+ message,
+ confirmLabel = 'Delete',
+ confirmVariant = 'destructive',
+ isLoading = false,
+}: ConfirmDialogProps) {
+ return (
+
+
+
+
+ }
+ >
+ {message}
+
+ )
+}
+
+export default ConfirmDialog
diff --git a/frontend/src/pages/TreeLibraryPage.tsx b/frontend/src/pages/TreeLibraryPage.tsx
index 33b393c5..65dbbb75 100644
--- a/frontend/src/pages/TreeLibraryPage.tsx
+++ b/frontend/src/pages/TreeLibraryPage.tsx
@@ -1,17 +1,18 @@
import { useEffect, useState, useCallback } from 'react'
import { useNavigate, Link } from 'react-router-dom'
-import { Plus, Pencil, Globe, Lock, X } from 'lucide-react'
+import { Plus, Pencil, Globe, Lock, X, Trash2 } from 'lucide-react'
import { treesApi, categoriesApi, foldersApi } from '@/api'
import type { TreeListItem, CategoryListItem, FolderListItem } from '@/types'
import { TagBadges } from '@/components/common/TagBadges'
import { FolderSidebar } from '@/components/library/FolderSidebar'
import { FolderEditModal } from '@/components/library/FolderEditModal'
import { AddToFolderMenu } from '@/components/library/AddToFolderMenu'
+import { ConfirmDialog } from '@/components/common/ConfirmDialog'
import { cn } from '@/lib/utils'
import { usePermissions } from '@/hooks/usePermissions'
export function TreeLibraryPage() {
- const { canCreateTrees, canEditTree } = usePermissions()
+ const { canCreateTrees, canEditTree, canDeleteTree } = usePermissions()
const navigate = useNavigate()
const [trees, setTrees] = useState([])
const [categories, setCategories] = useState([])
@@ -28,6 +29,11 @@ export function TreeLibraryPage() {
const [editingFolder, setEditingFolder] = useState(null)
const [newFolderParentId, setNewFolderParentId] = useState(null)
+ // Delete confirmation state
+ const [treeToDelete, setTreeToDelete] = useState(null)
+ const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
+ const [isDeleting, setIsDeleting] = useState(false)
+
const loadFolders = useCallback(async () => {
try {
const foldersData = await foldersApi.list()
@@ -122,6 +128,22 @@ export function TreeLibraryPage() {
setFolderModalOpen(true)
}
+ const handleDeleteTree = async () => {
+ if (!treeToDelete) return
+ setIsDeleting(true)
+ try {
+ await treesApi.delete(treeToDelete.id)
+ setTrees(trees.filter((t) => t.id !== treeToDelete.id))
+ } catch (err) {
+ console.error('Failed to delete tree:', err)
+ setError('Failed to delete tree')
+ } finally {
+ setIsDeleting(false)
+ setShowDeleteConfirm(false)
+ setTreeToDelete(null)
+ }
+ }
+
const hasActiveFilters =
selectedCategoryId || selectedTags.length > 0 || searchQuery || selectedFolderId
@@ -322,6 +344,22 @@ export function TreeLibraryPage() {
)}
+ {canDeleteTree({ author_id: tree.author_id }) && (
+
+ )}