import { Edit2, Pipette, Plus, Trash2 } from 'lucide-react'; import { useEffect, useRef, useState } from 'react'; import { categoriesApi } from '../../api/client'; import { useTranslation } from '../../i18n'; import { getApiErrorMessage } from '../../types'; import { CATEGORY_ICON_MAP, ICON_LABELS, getCategoryIcon } from '../shared/categoryIcons'; import { useToast } from '../shared/Toast'; const PRESET_COLORS = [ '#6366f1', '#8b5cf6', '#ec4899', '#ef4444', '#f97316', '#f59e0b', '#10b981', '#06b6d4', '#3b82f6', '#84cc16', '#6b7280', '#1f2937', ]; const ICON_NAMES = Object.keys(CATEGORY_ICON_MAP); export default function CategoryManager() { const [categories, setCategories] = useState([]); const [showForm, setShowForm] = useState(false); const [editingId, setEditingId] = useState(null); const [form, setForm] = useState({ name: '', color: '#6366f1', icon: 'MapPin' }); const [isSaving, setIsSaving] = useState(false); const [isLoading, setIsLoading] = useState(true); const colorInputRef = useRef(null); const toast = useToast(); const { t } = useTranslation(); useEffect(() => { loadCategories(); }, []); const loadCategories = async () => { setIsLoading(true); try { const data = await categoriesApi.list(); setCategories(data.categories || []); } catch (err: unknown) { toast.error(t('categories.toast.loadError')); } finally { setIsLoading(false); } }; const handleStartEdit = (cat) => { setEditingId(cat.id); setForm({ name: cat.name, color: cat.color || '#6366f1', icon: cat.icon || 'MapPin' }); setShowForm(false); }; const handleStartCreate = () => { setEditingId(null); setForm({ name: '', color: '#6366f1', icon: 'MapPin' }); setShowForm(true); }; const handleCancel = () => { setShowForm(false); setEditingId(null); }; const handleSave = async () => { if (!form.name.trim()) { toast.error(t('categories.toast.nameRequired')); return; } setIsSaving(true); try { if (editingId) { const result = await categoriesApi.update(editingId, form); setCategories((prev) => prev.map((c) => (c.id === editingId ? result.category : c))); setEditingId(null); toast.success(t('categories.toast.updated')); } else { const result = await categoriesApi.create(form); setCategories((prev) => [...prev, result.category]); setShowForm(false); toast.success(t('categories.toast.created')); } setForm({ name: '', color: '#6366f1', icon: 'MapPin' }); } catch (err: unknown) { toast.error(getApiErrorMessage(err, t('categories.toast.saveError'))); } finally { setIsSaving(false); } }; const handleDelete = async (id) => { if (!confirm(t('categories.confirm.delete'))) return; try { await categoriesApi.delete(id); setCategories((prev) => prev.filter((c) => c.id !== id)); toast.success(t('categories.toast.deleted')); } catch (err: unknown) { toast.error(getApiErrorMessage(err, t('categories.toast.deleteError'))); } }; const isPresetColor = PRESET_COLORS.includes(form.color); const PreviewIcon = getCategoryIcon(form.icon); const categoryForm = (
{t('categories.subtitle')}
{t('categories.empty')}