151 lines
5.4 KiB
TypeScript
151 lines
5.4 KiB
TypeScript
"use client";
|
|
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { CheckCircle2, Circle } from "lucide-react";
|
|
import { CategoryIcon } from "@/components/ui/category-icon";
|
|
import type { BankingData } from "@/lib/types";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface RecentTransactionsProps {
|
|
data: BankingData;
|
|
}
|
|
|
|
export function RecentTransactions({ data }: RecentTransactionsProps) {
|
|
const recentTransactions = [...data.transactions]
|
|
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
|
.slice(0, 10);
|
|
|
|
const formatCurrency = (amount: number) => {
|
|
return new Intl.NumberFormat("fr-FR", {
|
|
style: "currency",
|
|
currency: "EUR",
|
|
}).format(amount);
|
|
};
|
|
|
|
const formatDate = (dateStr: string) => {
|
|
return new Date(dateStr).toLocaleDateString("fr-FR", {
|
|
day: "2-digit",
|
|
month: "short",
|
|
});
|
|
};
|
|
|
|
const getCategory = (categoryId: string | null) => {
|
|
if (!categoryId) return null;
|
|
return data.categories.find((c) => c.id === categoryId);
|
|
};
|
|
|
|
const getAccount = (accountId: string) => {
|
|
return data.accounts.find((a) => a.id === accountId);
|
|
};
|
|
|
|
if (recentTransactions.length === 0) {
|
|
return (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Transactions récentes</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex flex-col items-center justify-center py-8 text-center">
|
|
<p className="text-muted-foreground">Aucune transaction</p>
|
|
<p className="text-sm text-muted-foreground mt-1">
|
|
Importez un fichier OFX pour commencer
|
|
</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="text-sm md:text-base">Transactions récentes</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="px-3 md:px-6">
|
|
<div className="space-y-3">
|
|
{recentTransactions.map((transaction) => {
|
|
const category = getCategory(transaction.categoryId);
|
|
const account = getAccount(transaction.accountId);
|
|
|
|
return (
|
|
<div
|
|
key={transaction.id}
|
|
className="rounded-lg bg-muted/50 hover:bg-muted transition-colors overflow-hidden"
|
|
>
|
|
<div className="flex items-start gap-2 md:gap-3 p-2 md:p-3">
|
|
<div className="flex-shrink-0 pt-0.5">
|
|
{transaction.isReconciled ? (
|
|
<CheckCircle2 className="w-4 h-4 md:w-5 md:h-5 text-emerald-600" />
|
|
) : (
|
|
<Circle className="w-4 h-4 md:w-5 md:h-5 text-muted-foreground" />
|
|
)}
|
|
</div>
|
|
|
|
<div className="flex-1 min-w-0 overflow-hidden">
|
|
<div className="flex items-start justify-between gap-2">
|
|
<p className="font-medium text-xs md:text-base truncate flex-1">
|
|
{transaction.description}
|
|
</p>
|
|
<div
|
|
className={cn(
|
|
"font-semibold tabular-nums text-xs md:text-base shrink-0 md:hidden",
|
|
transaction.amount >= 0
|
|
? "text-emerald-600"
|
|
: "text-red-600",
|
|
)}
|
|
>
|
|
{transaction.amount >= 0 ? "+" : ""}
|
|
{formatCurrency(transaction.amount)}
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center gap-1.5 md:gap-2 mt-1 flex-wrap">
|
|
<span className="text-[10px] md:text-xs text-muted-foreground whitespace-nowrap">
|
|
{formatDate(transaction.date)}
|
|
</span>
|
|
{account && (
|
|
<span className="text-[10px] md:text-xs text-muted-foreground truncate">
|
|
• {account.name}
|
|
</span>
|
|
)}
|
|
{category && (
|
|
<Badge
|
|
variant="secondary"
|
|
className="text-[10px] md:text-xs gap-1 shrink-0"
|
|
style={{
|
|
backgroundColor: `${category.color}20`,
|
|
color: category.color,
|
|
}}
|
|
>
|
|
<CategoryIcon
|
|
icon={category.icon}
|
|
color={category.color}
|
|
size={10}
|
|
/>
|
|
<span className="truncate">{category.name}</span>
|
|
</Badge>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
className={cn(
|
|
"font-semibold tabular-nums text-sm md:text-base shrink-0 hidden md:block",
|
|
transaction.amount >= 0
|
|
? "text-emerald-600"
|
|
: "text-red-600",
|
|
)}
|
|
>
|
|
{transaction.amount >= 0 ? "+" : ""}
|
|
{formatCurrency(transaction.amount)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|