import { Alert, AlertColor, Button, Container, IconButton, List, ListItem, ListItemText, Stack, TextField, Typography, } from '@mui/material'; import CheckIcon from '@mui/icons-material/Check'; import CloseIcon from '@mui/icons-material/Close'; import DeleteIcon from '@mui/icons-material/Delete'; import EditIcon from '@mui/icons-material/Edit'; import { useMemo, useState } from 'react'; import { v4 as uuidv4 } from 'uuid'; import { useDatabase } from '../context/DBProvider'; import { useCategories, useProducts } from '../hooks/dataHooks'; export const ManageCategoriesScreen = () => { const db = useDatabase(); const categories = useCategories(); const products = useProducts(); const [name, setName] = useState(''); const [editingCategoryId, setEditingCategoryId] = useState(null); const [editName, setEditName] = useState(''); const [feedback, setFeedback] = useState<{ text: string; severity: AlertColor } | null>(null); const usageByCategory = useMemo(() => { return products.reduce>((acc, product) => { acc[product.category] = (acc[product.category] ?? 0) + 1; return acc; }, {}); }, [products]); const addCategory = async () => { const trimmed = name.trim(); if (!trimmed) return; const exists = categories.some((category) => category.name.toLowerCase() === trimmed.toLowerCase()); if (exists) { setFeedback({ text: 'A category with this name already exists.', severity: 'error' }); return; } await db.categories.add({ id: uuidv4(), name: trimmed, created_at: Date.now(), updated_at: Date.now() }); setName(''); setFeedback({ text: 'Category added.', severity: 'success' }); }; const startEditing = (categoryId: string, currentName: string) => { setEditingCategoryId(categoryId); setEditName(currentName); setFeedback(null); }; const saveCategory = async () => { if (!editingCategoryId) return; const trimmed = editName.trim(); if (!trimmed) return; const category = categories.find((item) => item.id === editingCategoryId); if (!category) return; const nameExists = categories.some( (item) => item.id !== editingCategoryId && item.name.toLowerCase() === trimmed.toLowerCase(), ); if (nameExists) { setFeedback({ text: 'A category with this name already exists.', severity: 'error' }); return; } await db.transaction('rw', db.categories, db.products, async () => { await db.categories.update(editingCategoryId, { name: trimmed, updated_at: Date.now() }); await db.products .where('category') .equals(category.name) .modify({ category: trimmed, updated_at: Date.now() }); }); setEditingCategoryId(null); setEditName(''); setFeedback({ text: 'Category updated. Linked products were refreshed.', severity: 'success' }); }; const cancelEditing = () => { setEditingCategoryId(null); setEditName(''); setFeedback(null); }; const deleteCategory = async (categoryId: string, categoryName: string) => { const usageCount = usageByCategory[categoryName] ?? 0; if (usageCount > 0) { setFeedback({ text: `Cannot delete '${categoryName}' while ${usageCount} product(s) use it. Update those products first.`, severity: 'error', }); return; } await db.categories.delete(categoryId); if (editingCategoryId === categoryId) { cancelEditing(); } setFeedback({ text: 'Category deleted.', severity: 'success' }); }; return ( Manage Categories {feedback ? {feedback.text} : null} setName(event.target.value)} /> {categories.map((category) => ( {editingCategoryId === category.id ? ( setEditName(event.target.value)} /> ) : ( startEditing(category.id, category.name)} aria-label={`Edit ${category.name}`} size="small" > deleteCategory(category.id, category.name)} aria-label={`Delete ${category.name}`} size="small" > )} ))} ); };