feat: replace category selection with CategoryCombobox in RuleCreateDialog and TransactionTable for improved user experience

This commit is contained in:
Julien Froidefond
2025-11-29 17:26:20 +01:00
parent 9e576f2b0e
commit 0ce50d1477
3 changed files with 283 additions and 130 deletions

View File

@@ -4,21 +4,18 @@ import { useEffect, useRef, useState, useCallback } from "react";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import { Badge } from "@/components/ui/badge";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
DropdownMenuSeparator,
} from "@/components/ui/dropdown-menu";
import { CategoryIcon } from "@/components/ui/category-icon";
import { CategoryCombobox } from "@/components/ui/category-combobox";
import {
CheckCircle2,
Circle,
MoreVertical,
ArrowUpDown,
Check,
} from "lucide-react";
import { cn } from "@/lib/utils";
import type { Transaction, Account, Category } from "@/lib/types";
@@ -110,11 +107,6 @@ export function TransactionTable({
useEffect(() => {
setFocusedIndex(null);
}, [transactions.length]);
const getCategory = (categoryId: string | null) => {
if (!categoryId) return null;
return categories.find((c) => c.id === categoryId);
};
const getAccount = (accountId: string) => {
return accounts.find((a) => a.id === accountId);
};
@@ -181,7 +173,6 @@ export function TransactionTable({
</thead>
<tbody>
{transactions.map((transaction, index) => {
const category = getCategory(transaction.categoryId);
const account = getAccount(transaction.accountId);
const isFocused = focusedIndex === index;
@@ -222,64 +213,16 @@ export function TransactionTable({
<td className="p-3 text-sm text-muted-foreground">
{account?.name || "-"}
</td>
<td className="p-3">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button className="flex items-center gap-1 hover:opacity-80">
{category ? (
<Badge
variant="secondary"
className="gap-1"
style={{
backgroundColor: `${category.color}20`,
color: category.color,
}}
>
<CategoryIcon
icon={category.icon}
color={category.color}
size={12}
/>
{category.name}
</Badge>
) : (
<Badge
variant="outline"
className="text-muted-foreground"
>
Non catégorisé
</Badge>
)}
</button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem
onClick={() => onSetCategory(transaction.id, null)}
>
Aucune catégorie
</DropdownMenuItem>
<DropdownMenuSeparator />
{categories.map((cat) => (
<DropdownMenuItem
key={cat.id}
onClick={() =>
onSetCategory(transaction.id, cat.id)
}
>
<CategoryIcon
icon={cat.icon}
color={cat.color}
size={14}
className="mr-2"
/>
{cat.name}
{transaction.categoryId === cat.id && (
<Check className="w-4 h-4 ml-auto" />
)}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
<td className="p-3" onClick={(e) => e.stopPropagation()}>
<CategoryCombobox
categories={categories}
value={transaction.categoryId}
onChange={(categoryId) =>
onSetCategory(transaction.id, categoryId)
}
showBadge
align="start"
/>
</td>
<td
className={cn(