'use client' import { useState, useTransition } from 'react' import { Category, Product, ProductModule } from '@/lib/types' import { updateProduct, createProduct, updateCategory, createCategory, deleteProduct, deleteCategory, addProductDependency, removeProductDependency } from '@/lib/actions/products' import { InlineInput } from './components/inline-input' import { ModulePopover } from './components/module-popover' import { DependencyPopover } from './components/dependency-popover' import { Trash2 } from 'lucide-react' export function WysiwygAdminClient({ initialCategories, initialProducts, allModules }: { initialCategories: Category[] initialProducts: Product[] allModules: ProductModule[] }) { const [mode, setMode] = useState<'purchase' | 'subscription'>('purchase') const [categories, setCategories] = useState(initialCategories) const [products, setProducts] = useState(initialProducts) const [isPending, startTransition] = useTransition() const handleDeleteCategory = async (catId: string) => { // Cascade-Check: check if there are products belonging to this category const categoryProducts = products.filter(p => p.category_id === catId) if (categoryProducts.length > 0) { alert(`Diese Kategorie enthält noch ${categoryProducts.length} Produkte. Bitte lösche oder verschiebe diese zuerst!`) return } if (!window.confirm('Möchten Sie diese Kategorie wirklich löschen?')) { return } startTransition(async () => { try { await deleteCategory(catId) setCategories(categories.filter(c => c.id !== catId)) } catch (e) { console.error(e) alert('Fehler beim Löschen der Kategorie.') } }) } const handleDeleteProduct = async (prodId: string) => { if (!window.confirm('Möchten Sie dieses Produkt wirklich löschen?')) { return } startTransition(async () => { try { await deleteProduct(prodId) setProducts(products.filter(p => p.id !== prodId)) } catch (e) { console.error(e) alert('Fehler beim Löschen des Produkts.') } }) } const getDependencyName = (depId: string) => { const matchedProduct = products.find(p => p.id === depId) if (matchedProduct) return matchedProduct.name const matchedModule = allModules.find(m => m.id === depId) if (matchedModule) return `${matchedModule.name} (Modul)` return depId } // Filterung der Kategorien nach aktivem Modus const filteredCategories = categories.filter(cat => mode === 'purchase' ? cat.show_in_kauf : cat.show_in_abo ) // Filterung der Produkte nach aktivem Modus const filteredProducts = products.filter(p => mode === 'purchase' ? p.billing_interval === 'one_time' : p.billing_interval === 'monthly' ) const handleAddCategory = async () => { startTransition(async () => { try { const newCat = await createCategory({ name: 'Neue Kategorie', description: 'Beschreibung hier...', sort_order: categories.length + 1, is_required: false, allow_multiselect: false, free_items_limit: 0, preselect: false, show_in_kauf: mode === 'purchase', show_in_abo: mode === 'subscription', resets_others: false }) setCategories([...categories, newCat]) } catch (e) { console.error(e) } }) } const handleAddProduct = async (categoryId: string) => { startTransition(async () => { try { const newProd = await createProduct({ name: 'Neues Produkt', description: 'Produktbeschreibung...', base_price: 19.99, tax_rate: 19, billing_interval: mode === 'purchase' ? 'one_time' : 'monthly', category_id: categoryId, show_in_kauf: mode === 'purchase', show_in_abo: mode === 'subscription' }, []) setProducts([...products, newProd]) } catch (e) { console.error(e) } }) } const handleCategoryToggle = async (catId: string, fields: Partial) => { startTransition(async () => { try { setCategories(categories.map(c => c.id === catId ? { ...c, ...fields } : c)) await updateCategory(catId, fields) } catch (e) { console.error(e) } }) } return (
{isPending && Speichere Änderungen...}
{filteredCategories .sort((a, b) => a.sort_order - b.sort_order) .map(cat => { const catProducts = filteredProducts.filter(p => p.category_id === cat.id) return (
{ await updateCategory(cat.id, { name: newName }) setCategories(categories.map(c => c.id === cat.id ? { ...c, name: newName } : c)) }} className="text-2xl font-bold text-white block w-full" /> { await updateCategory(cat.id, { description: newDesc }) setCategories(categories.map(c => c.id === cat.id ? { ...c, description: newDesc } : c)) }} className="text-slate-400 text-sm mt-1 block w-full" /> {/* Kategorie Attribute (Toggles) */}
{!cat.allow_multiselect && ( )} {cat.allow_multiselect && (
Freie Artikel Limit: handleCategoryToggle(cat.id, { free_items_limit: parseInt(e.target.value) || 0 })} className="w-12 rounded border-white/10 bg-white/5 text-white focus:ring-0 focus:ring-offset-0 px-1 py-0.5 text-center" />
)}
{catProducts.map(prod => (
{ await updateProduct(prod.id, { name: newName }, prod.modules || []) setProducts(products.map(p => p.id === prod.id ? { ...p, name: newName } : p)) }} className="font-semibold text-white block" />
{ await updateProduct(prod.id, { description: newDesc }, prod.modules || []) setProducts(products.map(p => p.id === prod.id ? { ...p, description: newDesc } : p)) }} className="text-xs text-slate-400 block" />
{ const priceNum = parseFloat(newPrice) || 0 await updateProduct(prod.id, { base_price: priceNum }, prod.modules || []) setProducts(products.map(p => p.id === prod.id ? { ...p, base_price: priceNum } : p)) }} className="inline-block" />
{/* Modul-Badges */}
Module:
{(prod.modules || []).length > 0 ? ( (prod.modules || []).map((m) => ( {m.name} )) ) : ( Keine Module )}
{/* Requirements */}
Benötigt: { const newReqs = [...(prod.requirements || []), depId] setProducts(products.map(p => p.id === prod.id ? { ...p, requirements: newReqs } : p)) await addProductDependency(prod.id, 'requirements', depId) }} />
{(prod.requirements || []).length > 0 ? ( (prod.requirements || []).map((reqId) => ( {getDependencyName(reqId)} )) ) : ( Keine Anforderungen )}
{/* Exclusions */}
Schließt aus: { const newExcs = [...(prod.exclusions || []), depId] setProducts(products.map(p => p.id === prod.id ? { ...p, exclusions: newExcs } : p)) await addProductDependency(prod.id, 'exclusions', depId) }} />
{(prod.exclusions || []).length > 0 ? ( (prod.exclusions || []).map((exId) => ( {getDependencyName(exId)} )) ) : ( Keine Ausschlüsse )}
{/* Modul hinzufügen Popover */}
{ const newMod = { name: mod.name, description: mod.description, price: mod.price, requirements: mod.requirements || [], exclusions: mod.exclusions || [], has_quantity: mod.has_quantity || false } const updatedModules = [...(prod.modules || []), newMod] setProducts(products.map(p => p.id === prod.id ? { ...p, modules: updatedModules as any } : p)) await updateProduct(prod.id, {}, updatedModules) }} />
))}
) })}
) }