Files
fintrack/components/rules/rule-group-card.tsx

158 lines
5.0 KiB
TypeScript

"use client";
import { ChevronDown, ChevronRight, Plus, Tag } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { cn } from "@/lib/utils";
import type { Transaction, Category } from "@/lib/types";
interface TransactionGroup {
key: string;
displayName: string;
transactions: Transaction[];
totalAmount: number;
suggestedKeyword: string;
}
interface RuleGroupCardProps {
group: TransactionGroup;
isExpanded: boolean;
onToggleExpand: () => void;
onCreateRule: () => void;
categories: Category[];
formatCurrency: (amount: number) => string;
formatDate: (date: string) => string;
}
export function RuleGroupCard({
group,
isExpanded,
onToggleExpand,
onCreateRule,
formatCurrency,
formatDate,
}: RuleGroupCardProps) {
const avgAmount =
group.transactions.reduce((sum, t) => sum + t.amount, 0) /
group.transactions.length;
const isDebit = avgAmount < 0;
return (
<div className="border border-border rounded-lg bg-card overflow-hidden">
{/* Header */}
<div
className="flex items-center gap-3 p-4 cursor-pointer hover:bg-accent/5 transition-colors"
onClick={onToggleExpand}
>
<Button variant="ghost" size="icon" className="h-6 w-6 shrink-0">
{isExpanded ? (
<ChevronDown className="h-4 w-4" />
) : (
<ChevronRight className="h-4 w-4" />
)}
</Button>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2">
<span className="font-medium text-foreground truncate">
{group.displayName}
</span>
<Badge variant="secondary" className="shrink-0">
{group.transactions.length} transaction
{group.transactions.length > 1 ? "s" : ""}
</Badge>
</div>
<div className="flex items-center gap-2 mt-1 text-sm text-muted-foreground">
<Tag className="h-3 w-3" />
<span className="font-mono text-xs bg-muted px-1.5 py-0.5 rounded">
{group.suggestedKeyword}
</span>
</div>
</div>
<div className="flex items-center gap-4">
<div className="text-right">
<div
className={cn(
"font-semibold tabular-nums",
isDebit ? "text-destructive" : "text-success"
)}
>
{formatCurrency(group.totalAmount)}
</div>
<div className="text-xs text-muted-foreground">
Moy: {formatCurrency(avgAmount)}
</div>
</div>
<Button
size="sm"
onClick={(e) => {
e.stopPropagation();
onCreateRule();
}}
className="shrink-0"
>
<Plus className="h-4 w-4 mr-1" />
Créer règle
</Button>
</div>
</div>
{/* Expanded transactions list */}
{isExpanded && (
<div className="border-t border-border bg-muted/30">
<div className="max-h-64 overflow-y-auto">
<table className="w-full text-sm">
<thead className="bg-muted/50 sticky top-0">
<tr>
<th className="px-4 py-2 text-left font-medium text-muted-foreground">
Date
</th>
<th className="px-4 py-2 text-left font-medium text-muted-foreground">
Description
</th>
<th className="px-4 py-2 text-right font-medium text-muted-foreground">
Montant
</th>
</tr>
</thead>
<tbody>
{group.transactions.map((transaction) => (
<tr
key={transaction.id}
className="border-t border-border/50 hover:bg-muted/50"
>
<td className="px-4 py-2 text-muted-foreground whitespace-nowrap">
{formatDate(transaction.date)}
</td>
<td className="px-4 py-2 truncate max-w-md">
{transaction.description}
{transaction.memo && (
<span className="text-muted-foreground ml-2">
({transaction.memo})
</span>
)}
</td>
<td
className={cn(
"px-4 py-2 text-right tabular-nums whitespace-nowrap",
transaction.amount < 0
? "text-destructive"
: "text-success"
)}
>
{formatCurrency(transaction.amount)}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
</div>
);
}