import { useState, useEffect } from 'react' import { Plus } from 'lucide-react' import { DndContext, closestCenter } from '@dnd-kit/core' import type { DragEndEvent } from '@dnd-kit/core' import { SortableContext, verticalListSortingStrategy, arrayMove } from '@dnd-kit/sortable' import { stepCategoriesApi } from '@/api/stepCategories' import { stepsApi } from '@/api/steps' import { CategoryRow } from '@/components/admin/CategoryRow' import { CreateCategoryModal } from '@/components/admin/CreateCategoryModal' import { EditCategoryModal } from '@/components/admin/EditCategoryModal' import type { StepCategoryListItem } from '@/types' import { cn } from '@/lib/utils' import { toast } from '@/lib/toast' export function AdminCategoriesPage() { const [categories, setCategories] = useState([]) const [allSteps, setAllSteps] = useState<{ category_id?: string }[]>([]) const [isLoading, setIsLoading] = useState(true) const [showCreateModal, setShowCreateModal] = useState(false) const [showEditModal, setShowEditModal] = useState(false) const [editingCategory, setEditingCategory] = useState(null) const [isSaving, setIsSaving] = useState(false) const [includeArchived, setIncludeArchived] = useState(false) useEffect(() => { loadData() }, [includeArchived]) const loadData = async () => { setIsLoading(true) try { const [categoriesData, stepsData] = await Promise.all([ stepCategoriesApi.list({ include_inactive: includeArchived }), stepsApi.list({}) ]) setCategories(categoriesData) setAllSteps(stepsData) } catch (err) { console.error('Failed to load categories:', err) toast.error('Failed to load categories') } finally { setIsLoading(false) } } const getStepCount = (categoryId: string) => { return allSteps?.filter(s => s.category_id === categoryId).length || 0 } const handleCreate = async (data: { name: string; description: string }) => { setIsSaving(true) try { await stepCategoriesApi.create({ name: data.name, description: data.description || undefined }) toast.success('Category created successfully') setShowCreateModal(false) await loadData() } catch (err) { console.error('Failed to create category:', err) toast.error('Failed to create category') throw err } finally { setIsSaving(false) } } const handleEdit = async (data: { name: string; description: string }) => { if (!editingCategory) return setIsSaving(true) try { await stepCategoriesApi.update(editingCategory.id, { name: data.name, description: data.description || undefined }) toast.success('Category updated successfully') setShowEditModal(false) setEditingCategory(null) await loadData() } catch (err) { console.error('Failed to update category:', err) toast.error('Failed to update category') throw err } finally { setIsSaving(false) } } const handleArchive = async (id: string) => { try { await stepCategoriesApi.archive(id) toast.success('Category archived') await loadData() } catch (err) { console.error('Failed to archive category:', err) toast.error('Failed to archive category') } } const handleRestore = async (id: string) => { try { await stepCategoriesApi.restore(id) toast.success('Category restored') await loadData() } catch (err) { console.error('Failed to restore category:', err) toast.error('Failed to restore category') } } const handleDragEnd = async (event: DragEndEvent) => { const { active, over } = event if (!over || active.id === over.id) return const oldIndex = categories.findIndex(c => c.id === active.id) const newIndex = categories.findIndex(c => c.id === over.id) const reordered = arrayMove(categories, oldIndex, newIndex) // Optimistic update setCategories(reordered) try { // Update display_order for all affected categories const updates = reordered.map((cat, index) => ({ id: cat.id, display_order: index })) await stepCategoriesApi.updateOrder(updates) toast.success('Categories reordered') } catch (err) { console.error('Failed to reorder categories:', err) toast.error('Failed to save order') // Revert on error await loadData() } } const openEditModal = (category: StepCategoryListItem) => { setEditingCategory(category) setShowEditModal(true) } if (isLoading) { return (
) } return (
{/* Header */}

Step Categories

Manage categories for organizing step library

{/* Filter Toggle */}
{/* Categories List */} {categories.length === 0 ? (

No categories found. Create your first category to get started.

) : ( c.id)} strategy={verticalListSortingStrategy} >
{categories.map(category => ( ))}
)} {/* Create Modal */} setShowCreateModal(false)} onSubmit={handleCreate} isSaving={isSaving} /> {/* Edit Modal */} { setShowEditModal(false) setEditingCategory(null) }} onSubmit={handleEdit} category={editingCategory} isSaving={isSaving} />
) } export default AdminCategoriesPage