feat: replace category selection with CategoryCombobox in RuleCreateDialog and TransactionTable for improved user experience
This commit is contained in:
@@ -13,15 +13,8 @@ import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { CategoryIcon } from "@/components/ui/category-icon";
|
||||
import { CategoryCombobox } from "@/components/ui/category-combobox";
|
||||
import { Tag, AlertCircle, CheckCircle2 } from "lucide-react";
|
||||
import type { Category, Transaction } from "@/lib/types";
|
||||
|
||||
@@ -54,7 +47,7 @@ export function RuleCreateDialog({
|
||||
onSave,
|
||||
}: RuleCreateDialogProps) {
|
||||
const [keyword, setKeyword] = useState("");
|
||||
const [categoryId, setCategoryId] = useState<string>("");
|
||||
const [categoryId, setCategoryId] = useState<string | null>(null);
|
||||
const [applyToExisting, setApplyToExisting] = useState(true);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
@@ -62,28 +55,11 @@ export function RuleCreateDialog({
|
||||
useEffect(() => {
|
||||
if (group) {
|
||||
setKeyword(group.suggestedKeyword);
|
||||
setCategoryId("");
|
||||
setCategoryId(null);
|
||||
setApplyToExisting(true);
|
||||
}
|
||||
}, [group]);
|
||||
|
||||
// Organize categories by parent
|
||||
const { parentCategories, childrenByParent } = useMemo(() => {
|
||||
const parents = categories.filter((c) => c.parentId === null);
|
||||
const children: Record<string, Category[]> = {};
|
||||
|
||||
categories
|
||||
.filter((c) => c.parentId !== null)
|
||||
.forEach((child) => {
|
||||
if (!children[child.parentId!]) {
|
||||
children[child.parentId!] = [];
|
||||
}
|
||||
children[child.parentId!].push(child);
|
||||
});
|
||||
|
||||
return { parentCategories: parents, childrenByParent: children };
|
||||
}, [categories]);
|
||||
|
||||
// Check if keyword already exists in any category
|
||||
const existingCategory = useMemo(() => {
|
||||
if (!keyword) return null;
|
||||
@@ -166,42 +142,16 @@ export function RuleCreateDialog({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Category select */}
|
||||
{/* Category select with search */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="category">Catégorie</Label>
|
||||
<Select value={categoryId} onValueChange={setCategoryId}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Sélectionner une catégorie" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{parentCategories.map((parent) => (
|
||||
<div key={parent.id}>
|
||||
<SelectItem value={parent.id} className="font-medium">
|
||||
<div className="flex items-center gap-2">
|
||||
<CategoryIcon
|
||||
icon={parent.icon}
|
||||
color={parent.color}
|
||||
size={16}
|
||||
/>
|
||||
<span>{parent.name}</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
{childrenByParent[parent.id]?.map((child) => (
|
||||
<SelectItem key={child.id} value={child.id}>
|
||||
<div className="flex items-center gap-2 pl-4">
|
||||
<CategoryIcon
|
||||
icon={child.icon}
|
||||
color={child.color}
|
||||
size={16}
|
||||
/>
|
||||
<span>{child.name}</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Label>Catégorie</Label>
|
||||
<CategoryCombobox
|
||||
categories={categories}
|
||||
value={categoryId}
|
||||
onChange={setCategoryId}
|
||||
placeholder="Sélectionner une catégorie..."
|
||||
width="w-full"
|
||||
/>
|
||||
{selectedCategory && (
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<span className="text-xs text-muted-foreground">
|
||||
|
||||
Reference in New Issue
Block a user