feat(admin): finalizing modular refactoring with testing suite and UI polish
This commit is contained in:
113
frontend/components/admin/CategoryManager.tsx
Normal file
113
frontend/components/admin/CategoryManager.tsx
Normal file
@@ -0,0 +1,113 @@
|
||||
import React from 'react';
|
||||
import { Layers, Plus, Edit2, Trash2, X } from 'lucide-react';
|
||||
|
||||
interface CategoryManagerProps {
|
||||
categories: any[];
|
||||
onAddCategory: () => void;
|
||||
onDeleteCategory: (id: number, name: string) => void;
|
||||
setEditingCategory: (cat: any) => void;
|
||||
setEditCatForm: (form: any) => void;
|
||||
editCatForm: any;
|
||||
editingCategory: any;
|
||||
onUpdateCategorySubmit: () => void;
|
||||
}
|
||||
|
||||
export default function CategoryManager({
|
||||
categories,
|
||||
onAddCategory,
|
||||
onDeleteCategory,
|
||||
setEditingCategory,
|
||||
setEditCatForm,
|
||||
editCatForm,
|
||||
editingCategory,
|
||||
onUpdateCategorySubmit
|
||||
}: CategoryManagerProps) {
|
||||
return (
|
||||
<section className="bg-slate-900/40 backdrop-blur-xl border border-slate-800/50 rounded-[2.5rem] p-5 md:p-8 shadow-2xl space-y-6 transition-all group/categories">
|
||||
<div className="flex items-center justify-between px-2">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-10 h-10 rounded-xl bg-indigo-500/10 flex items-center justify-center text-indigo-400 border border-indigo-500/20">
|
||||
<Layers size={20} />
|
||||
</div>
|
||||
<h2 className="text-xl font-black text-white tracking-tight">Category Groups</h2>
|
||||
</div>
|
||||
<button
|
||||
onClick={onAddCategory}
|
||||
className="flex items-center gap-2 bg-indigo-600 hover:bg-indigo-500 text-white px-6 py-3 rounded-xl text-xs font-black transition-all shadow-xl shadow-indigo-600/10 active:scale-95 border border-indigo-500/30 tracking-tight"
|
||||
>
|
||||
<Plus size={14} /> New Group
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="grid sm:grid-cols-2 lg:grid-cols-4 gap-3">
|
||||
{categories.map(cat => (
|
||||
<div key={cat.id} className="p-4 bg-slate-950/40 border border-slate-800/50 rounded-2xl flex items-center justify-between group hover:border-primary/40 transition-all">
|
||||
<div className="min-w-0 pr-4">
|
||||
<p className="text-sm font-bold text-slate-200 group-hover:text-primary transition-colors">{cat.name}</p>
|
||||
<p className="text-[10px] text-slate-500 font-medium mt-0.5">{cat.description || 'General storage'}</p>
|
||||
</div>
|
||||
<div className="flex gap-1 shrink-0">
|
||||
<button
|
||||
onClick={() => {
|
||||
setEditingCategory(cat);
|
||||
setEditCatForm({ name: cat.name, description: cat.description || '' });
|
||||
}}
|
||||
className="p-2 text-slate-600 hover:text-white hover:bg-slate-800 rounded-lg transition-all"
|
||||
>
|
||||
<Edit2 size={14} />
|
||||
</button>
|
||||
<button
|
||||
onClick={() => onDeleteCategory(cat.id, cat.name)}
|
||||
className="p-2 text-slate-600 hover:text-red-500 hover:bg-red-500/5 rounded-lg transition-all"
|
||||
>
|
||||
<Trash2 size={14} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Edit Category Modal */}
|
||||
{editingCategory && (
|
||||
<div className="fixed inset-0 z-[100] flex items-end sm:items-center justify-center p-0 sm:p-4 bg-slate-950/90 backdrop-blur-xl animate-in fade-in duration-300">
|
||||
<div className="w-full max-w-lg bg-slate-900 border-x border-t sm:border border-slate-800 rounded-t-[2.5rem] sm:rounded-3xl p-6 sm:p-10 shadow-2xl space-y-8 overflow-hidden animate-in slide-in-from-bottom-10">
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-10 h-10 rounded-xl bg-indigo-500/10 flex items-center justify-center text-indigo-400 border border-indigo-500/20">
|
||||
<Edit2 size={20} />
|
||||
</div>
|
||||
<h3 className="text-xl font-black text-white tracking-tight">Modify Group</h3>
|
||||
</div>
|
||||
<button onClick={() => setEditingCategory(null)} className="p-3 hover:bg-slate-800 rounded-2xl text-slate-500 transition-colors border border-slate-800">
|
||||
<X size={20} />
|
||||
</button>
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-[10px] font-black text-slate-500 tracking-tight ml-1">Group Identifier</label>
|
||||
<input
|
||||
type="text"
|
||||
value={editCatForm.name}
|
||||
onChange={(e) => setEditCatForm({...editCatForm, name: e.target.value})}
|
||||
className="w-full bg-slate-950 border border-slate-800 rounded-2xl py-3.5 px-5 text-sm text-white focus:border-primary outline-none transition-all"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-[10px] font-black text-slate-500 tracking-tight ml-1">Strategic Description</label>
|
||||
<textarea
|
||||
value={editCatForm.description}
|
||||
onChange={(e) => setEditCatForm({...editCatForm, description: e.target.value})}
|
||||
className="w-full bg-slate-950 border border-slate-800 rounded-2xl py-4 px-5 text-sm text-white focus:border-primary outline-none transition-all h-32 resize-none"
|
||||
/>
|
||||
</div>
|
||||
<button onClick={onUpdateCategorySubmit} className="w-full bg-indigo-600 hover:bg-indigo-500 text-white font-black py-4 rounded-2xl shadow-xl shadow-indigo-600/20 active:scale-95 transition-all text-xs mb-4 tracking-tight">
|
||||
Update Asset Group
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user