feat: add new navigation item for rules in the dashboard sidebar with associated icon
This commit is contained in:
157
components/rules/rule-group-card.tsx
Normal file
157
components/rules/rule-group-card.tsx
Normal file
@@ -0,0 +1,157 @@
|
||||
"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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user