Compare commits

...

3 Commits

19 changed files with 152 additions and 80 deletions

View File

@@ -351,7 +351,7 @@ export default function CategoriesPage() {
onToggleAll={allExpanded ? collapseAll : expandAll} onToggleAll={allExpanded ? collapseAll : expandAll}
/> />
<div className="space-y-1"> <div className="space-y-3 md:space-y-4">
{filteredParentCategories.map((parent: Category) => { {filteredParentCategories.map((parent: Category) => {
const allChildren = childrenByParent[parent.id] || []; const allChildren = childrenByParent[parent.id] || [];
const children = searchQuery.trim() const children = searchQuery.trim()
@@ -387,8 +387,8 @@ export default function CategoriesPage() {
})} })}
{orphanCategories.length > 0 && ( {orphanCategories.length > 0 && (
<div className="border rounded-lg bg-card"> <Card className="card-hover">
<div className="px-3 py-2 border-b"> <div className="px-3 py-2 border-b border-border">
<span className="text-sm font-medium text-muted-foreground"> <span className="text-sm font-medium text-muted-foreground">
Catégories non classées ({orphanCategories.length}) Catégories non classées ({orphanCategories.length})
</span> </span>
@@ -405,7 +405,7 @@ export default function CategoriesPage() {
/> />
))} ))}
</div> </div>
</div> </Card>
)} )}
</div> </div>

View File

@@ -10,9 +10,9 @@
--foreground: oklch(0.1 0.015 280); --foreground: oklch(0.1 0.015 280);
/* Cards avec glassmorphism très prononcé */ /* Cards avec glassmorphism très prononcé */
--card: oklch(1 0 0 / 0.6); --card: oklch(1 0 0 / 0.5);
--card-foreground: oklch(0.1 0.015 280); --card-foreground: oklch(0.1 0.015 280);
--card-hover: oklch(1 0 0 / 0.75); --card-hover: oklch(1 0 0 / 0.65);
/* Popover avec backdrop blur très fort */ /* Popover avec backdrop blur très fort */
--popover: oklch(1 0 0 / 0.95); --popover: oklch(1 0 0 / 0.95);
@@ -82,9 +82,9 @@
--foreground: oklch(0.97 0.005 280); --foreground: oklch(0.97 0.005 280);
/* Cards avec effet glassmorphism sombre très prononcé */ /* Cards avec effet glassmorphism sombre très prononcé */
--card: oklch(0.15 0.015 280 / 0.6); --card: oklch(0.15 0.015 280 / 0.5);
--card-foreground: oklch(0.97 0.005 280); --card-foreground: oklch(0.97 0.005 280);
--card-hover: oklch(0.18 0.015 280 / 0.75); --card-hover: oklch(0.18 0.015 280 / 0.65);
/* Popover avec backdrop blur très fort */ /* Popover avec backdrop blur très fort */
--popover: oklch(0.15 0.015 280 / 0.95); --popover: oklch(0.15 0.015 280 / 0.95);
@@ -459,18 +459,19 @@
z-index: 1; z-index: 1;
} }
/* Fintech card styles avec design moderne et élégant */ /* Fintech card styles avec effet glassmorphism prononcé */
.fintech-card { .fintech-card {
background: var(--card); background: color-mix(in srgb, var(--card) 70%, transparent);
backdrop-filter: blur(40px) saturate(180%); backdrop-filter: blur(60px) saturate(200%) brightness(1.05);
-webkit-backdrop-filter: blur(40px) saturate(180%); -webkit-backdrop-filter: blur(60px) saturate(200%) brightness(1.05);
border: 1px solid color-mix(in srgb, var(--border) 60%, transparent); border: none;
border-radius: calc(var(--radius) + 0.25rem); border-radius: calc(var(--radius) + 0.25rem);
box-shadow: box-shadow:
0 1px 3px 0 color-mix(in srgb, var(--foreground) 4%, transparent), 0 2px 8px 0 color-mix(in srgb, var(--foreground) 6%, transparent),
0 4px 12px -2px color-mix(in srgb, var(--primary) 6%, transparent), 0 8px 24px -4px color-mix(in srgb, var(--primary) 8%, transparent),
0 8px 24px -4px color-mix(in srgb, var(--foreground) 2%, transparent), 0 16px 48px -8px color-mix(in srgb, var(--foreground) 3%, transparent),
inset 0 1px 0 0 color-mix(in srgb, white 30%, transparent); inset 0 1px 0 0 color-mix(in srgb, white 40%, transparent),
inset 0 -1px 0 0 color-mix(in srgb, var(--foreground) 2%, transparent);
position: relative; position: relative;
overflow: hidden; overflow: hidden;
} }
@@ -494,13 +495,47 @@
opacity: 0.1; opacity: 0.1;
} }
/* Texture plus prononcée pour les cards de statistiques */
.stat-card-textured::before {
background-image:
radial-gradient(circle at 1px 1px, color-mix(in srgb, var(--foreground) 3%, transparent) 1px, transparent 0),
radial-gradient(circle at 11px 11px, color-mix(in srgb, var(--foreground) 1.5%, transparent) 1px, transparent 0);
background-size: 16px 16px, 24px 24px;
opacity: 0.2;
z-index: 1;
}
.dark .stat-card-textured::before {
background-image:
radial-gradient(circle at 1px 1px, color-mix(in srgb, white 4%, transparent) 1px, transparent 0),
radial-gradient(circle at 11px 11px, color-mix(in srgb, white 2%, transparent) 1px, transparent 0);
opacity: 0.15;
}
/* Effet glass renforcé pour les cards de contenu */
.fintech-card.card-hover {
background: color-mix(in srgb, var(--card) 60%, transparent);
backdrop-filter: blur(80px) saturate(220%) brightness(1.08);
-webkit-backdrop-filter: blur(80px) saturate(220%) brightness(1.08);
}
.dark .fintech-card.card-hover {
background: color-mix(in srgb, var(--card) 55%, transparent);
backdrop-filter: blur(80px) saturate(220%) brightness(0.92);
-webkit-backdrop-filter: blur(80px) saturate(220%) brightness(0.92);
}
.dark .fintech-card { .dark .fintech-card {
border-color: color-mix(in srgb, var(--border) 40%, transparent); background: color-mix(in srgb, var(--card) 65%, transparent);
backdrop-filter: blur(60px) saturate(200%) brightness(0.95);
-webkit-backdrop-filter: blur(60px) saturate(200%) brightness(0.95);
border: none;
box-shadow: box-shadow:
0 1px 3px 0 color-mix(in srgb, var(--foreground) 8%, transparent), 0 2px 8px 0 color-mix(in srgb, var(--foreground) 12%, transparent),
0 4px 12px -2px color-mix(in srgb, var(--primary) 8%, transparent), 0 8px 24px -4px color-mix(in srgb, var(--primary) 12%, transparent),
0 8px 24px -4px color-mix(in srgb, black 40%, transparent), 0 16px 48px -8px color-mix(in srgb, black 50%, transparent),
inset 0 1px 0 0 color-mix(in srgb, white 8%, transparent); inset 0 1px 0 0 color-mix(in srgb, white 12%, transparent),
inset 0 -1px 0 0 color-mix(in srgb, var(--foreground) 4%, transparent);
} }
.fintech-card::after { .fintech-card::after {
@@ -509,19 +544,29 @@
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
height: 1px; height: 2px;
background: linear-gradient( background: linear-gradient(
90deg, 90deg,
transparent 0%, transparent 0%,
color-mix(in srgb, white 50%, transparent) 50%, color-mix(in srgb, white 60%, transparent) 20%,
color-mix(in srgb, white 80%, transparent) 50%,
color-mix(in srgb, white 60%, transparent) 80%,
transparent 100% transparent 100%
); );
opacity: 0.6; opacity: 0.7;
z-index: 2; z-index: 2;
} }
.dark .fintech-card::after { .dark .fintech-card::after {
opacity: 0.2; opacity: 0.25;
background: linear-gradient(
90deg,
transparent 0%,
color-mix(in srgb, white 30%, transparent) 20%,
color-mix(in srgb, white 40%, transparent) 50%,
color-mix(in srgb, white 30%, transparent) 80%,
transparent 100%
);
} }
/* Gradient backgrounds for stat cards - design moderne et subtil */ /* Gradient backgrounds for stat cards - design moderne et subtil */

View File

@@ -48,7 +48,7 @@ export default function LoginPage() {
return ( return (
<div className="min-h-screen flex items-center justify-center bg-[var(--background)] p-4 page-background"> <div className="min-h-screen flex items-center justify-center bg-[var(--background)] p-4 page-background">
<Card className="w-full max-w-md page-content"> <Card className="w-full max-w-md page-content card-hover">
<CardHeader className="space-y-1"> <CardHeader className="space-y-1">
<div className="flex items-center justify-center mb-4"> <div className="flex items-center justify-center mb-4">
<Lock className="w-12 h-12 text-[var(--primary)]" /> <Lock className="w-12 h-12 text-[var(--primary)]" />

View File

@@ -60,8 +60,7 @@ export default function DashboardPage() {
} }
/> />
<Card className="mb-6 card-hover"> <div className="mb-6">
<CardContent className="px-5 py-5 sm:px-6 sm:py-6">
<AccountFilterCombobox <AccountFilterCombobox
accounts={data.accounts} accounts={data.accounts}
folders={data.folders} folders={data.folders}
@@ -70,8 +69,7 @@ export default function DashboardPage() {
className="w-full md:w-[320px]" className="w-full md:w-[320px]"
filteredTransactions={data.transactions} filteredTransactions={data.transactions}
/> />
</CardContent> </div>
</Card>
<OverviewCards data={filteredData} /> <OverviewCards data={filteredData} />

View File

@@ -238,7 +238,7 @@ export default function TransactionsPage() {
/> />
{(!isLoadingChart || !isLoadingTransactions) && ( {(!isLoadingChart || !isLoadingTransactions) && (
<Card className="mb-6"> <Card className="mb-6 card-hover">
<Collapsible open={isStatsExpanded} onOpenChange={setIsStatsExpanded}> <Collapsible open={isStatsExpanded} onOpenChange={setIsStatsExpanded}>
<CardHeader className="flex flex-row items-center justify-between space-y-0 py-3 px-6"> <CardHeader className="flex flex-row items-center justify-between space-y-0 py-3 px-6">
<CardTitle className="text-base font-semibold"> <CardTitle className="text-base font-semibold">
@@ -272,7 +272,7 @@ export default function TransactionsPage() {
{/* Summary cards */} {/* Summary cards */}
{!isLoadingTransactions && ( {!isLoadingTransactions && (
<div className="grid gap-4 grid-cols-1 sm:grid-cols-2 mb-6"> <div className="grid gap-4 grid-cols-1 sm:grid-cols-2 mb-6">
<Card> <Card className="card-hover">
<CardContent className="pt-6"> <CardContent className="pt-6">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
@@ -287,7 +287,7 @@ export default function TransactionsPage() {
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card className="card-hover">
<CardContent className="pt-6"> <CardContent className="pt-6">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>

View File

@@ -13,6 +13,7 @@ import {
CollapsibleContent, CollapsibleContent,
CollapsibleTrigger, CollapsibleTrigger,
} from "@/components/ui/collapsible"; } from "@/components/ui/collapsible";
import { Card } from "@/components/ui/card";
import { CategoryIcon } from "@/components/ui/category-icon"; import { CategoryIcon } from "@/components/ui/category-icon";
import { import {
Plus, Plus,
@@ -54,7 +55,7 @@ export function ParentCategoryRow({
const isMobile = useIsMobile(); const isMobile = useIsMobile();
return ( return (
<div className="border rounded-lg bg-card"> <Card className="card-hover">
<Collapsible open={isExpanded} onOpenChange={onToggleExpanded}> <Collapsible open={isExpanded} onOpenChange={onToggleExpanded}>
<div className="flex items-center justify-between px-2 md:px-3 py-1.5 md:py-2"> <div className="flex items-center justify-between px-2 md:px-3 py-1.5 md:py-2">
<CollapsibleTrigger asChild> <CollapsibleTrigger asChild>
@@ -155,6 +156,6 @@ export function ParentCategoryRow({
)} )}
</CollapsibleContent> </CollapsibleContent>
</Collapsible> </Collapsible>
</div> </Card>
); );
} }

View File

@@ -61,13 +61,13 @@ export function RecentTransactions({ data }: RecentTransactionsProps) {
} }
return ( return (
<Card className="card-hover"> <Card className="card-hover relative overflow-hidden">
<CardHeader className="pb-5"> <CardHeader className="pb-5 relative z-10">
<CardTitle className="text-lg md:text-xl font-black tracking-tight"> <CardTitle className="text-lg md:text-xl font-black tracking-tight">
Transactions récentes Transactions récentes
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent className="px-5 md:px-6"> <CardContent className="px-5 md:px-6 relative z-10">
<div className="space-y-3"> <div className="space-y-3">
{recentTransactions.map((transaction) => { {recentTransactions.map((transaction) => {
const category = getCategory(transaction.categoryId); const category = getCategory(transaction.categoryId);

View File

@@ -5,6 +5,7 @@ import { ChevronDown, ChevronRight, Plus, Tag } from "lucide-react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { CategoryCombobox } from "@/components/ui/category-combobox"; import { CategoryCombobox } from "@/components/ui/category-combobox";
import { Card } from "@/components/ui/card";
import { useIsMobile } from "@/hooks/use-mobile"; import { useIsMobile } from "@/hooks/use-mobile";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import type { Transaction, Category } from "@/lib/types"; import type { Transaction, Category } from "@/lib/types";
@@ -54,7 +55,7 @@ export function RuleGroupCard({
}; };
return ( return (
<div className="border border-border rounded-lg bg-card overflow-hidden"> <Card className="card-hover overflow-hidden">
{/* Header */} {/* Header */}
<div <div
className="flex flex-col md:flex-row md:items-center gap-2 md:gap-3 p-3 md:p-4 cursor-pointer hover:bg-accent/5" className="flex flex-col md:flex-row md:items-center gap-2 md:gap-3 p-3 md:p-4 cursor-pointer hover:bg-accent/5"
@@ -247,6 +248,6 @@ export function RuleGroupCard({
)} )}
</div> </div>
)} )}
</div> </Card>
); );
} }

View File

@@ -57,7 +57,7 @@ export function BalanceLineChart({
}; };
return ( return (
<Card> <Card className="card-hover">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle>Évolution du solde</CardTitle> <CardTitle>Évolution du solde</CardTitle>
<div className="flex gap-1"> <div className="flex gap-1">

View File

@@ -73,7 +73,7 @@ export function CategoryBarChart({
}; };
return ( return (
<Card> <Card className="card-hover">
<CardHeader> <CardHeader>
<CardTitle>{title}</CardTitle> <CardTitle>{title}</CardTitle>
</CardHeader> </CardHeader>
@@ -154,3 +154,5 @@ export function CategoryBarChart({
</Card> </Card>
); );
} }
// Find the Card component in this file

View File

@@ -51,7 +51,7 @@ export function CategoryPieChart({
const currentData = isExpanded ? baseData : baseData.slice(0, maxItems); const currentData = isExpanded ? baseData : baseData.slice(0, maxItems);
return ( return (
<Card> <Card className="card-hover">
<CardHeader className="flex flex-col md:flex-row md:items-center md:justify-between space-y-2 md:space-y-0 pb-2"> <CardHeader className="flex flex-col md:flex-row md:items-center md:justify-between space-y-2 md:space-y-0 pb-2">
<CardTitle className="text-sm md:text-base">{title}</CardTitle> <CardTitle className="text-sm md:text-base">{title}</CardTitle>
<div className="flex flex-col md:flex-row gap-2 w-full md:w-auto"> <div className="flex flex-col md:flex-row gap-2 w-full md:w-auto">

View File

@@ -96,7 +96,7 @@ export function CategoryTrendChart({
}; };
return ( return (
<Card> <Card className="card-hover">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle>Évolution des dépenses par catégorie</CardTitle> <CardTitle>Évolution des dépenses par catégorie</CardTitle>
<div className="flex gap-2"> <div className="flex gap-2">

View File

@@ -28,7 +28,7 @@ export function IncomeExpenseTrendChart({
formatCurrency, formatCurrency,
}: IncomeExpenseTrendChartProps) { }: IncomeExpenseTrendChartProps) {
return ( return (
<Card> <Card className="card-hover">
<CardHeader> <CardHeader>
<CardTitle>Tendances revenus et dépenses</CardTitle> <CardTitle>Tendances revenus et dépenses</CardTitle>
</CardHeader> </CardHeader>

View File

@@ -44,20 +44,35 @@ export function MonthlyChart({
}: MonthlyChartProps) { }: MonthlyChartProps) {
const [isExpanded, setIsExpanded] = useState(defaultExpanded); const [isExpanded, setIsExpanded] = useState(defaultExpanded);
// Calculer l'intervalle dynamiquement selon le nombre de données
const getXAxisInterval = () => {
if (data.length <= 6) return 0; // Afficher tous les labels pour 6 mois ou moins
if (data.length <= 12) return 1; // Afficher un label sur deux pour 7-12 mois
return Math.floor(data.length / 12); // Pour plus de 12 mois, afficher environ 12 labels
};
// Formater les labels de manière plus compacte
const formatMonthLabel = (month: string) => {
// Format: "janv. 24" -> "janv 24" (enlever le point)
return month.replace('.', '');
};
const chartContent = ( const chartContent = (
<> <>
{data.length > 0 ? ( {data.length > 0 ? (
<div className="h-[400px] sm:h-[300px]"> <div className="h-[400px] sm:h-[300px]">
<ResponsiveContainer width="100%" height="100%"> <ResponsiveContainer width="100%" height="100%">
<LineChart data={data} margin={{ left: 0, right: 10, top: 10, bottom: 5 }}> <LineChart data={data} margin={{ left: 0, right: 10, top: 10, bottom: data.length > 6 ? 80 : 60 }}>
<CartesianGrid strokeDasharray="3 3" className="stroke-muted" /> <CartesianGrid strokeDasharray="3 3" className="stroke-muted" />
<XAxis <XAxis
dataKey="month" dataKey="month"
className="text-xs" className="text-xs"
angle={-45} angle={data.length > 6 ? -45 : 0}
textAnchor="end" textAnchor={data.length > 6 ? "end" : "middle"}
height={60} height={data.length > 6 ? 80 : 60}
interval={0} interval={getXAxisInterval()}
tickFormatter={formatMonthLabel}
tick={{ fontSize: 11 }}
/> />
<YAxis <YAxis
className="text-xs" className="text-xs"
@@ -112,7 +127,7 @@ export function MonthlyChart({
if (!collapsible) { if (!collapsible) {
return ( return (
<Card> <Card className="card-hover">
<CardHeader> <CardHeader>
<CardTitle>Revenus vs Dépenses par mois</CardTitle> <CardTitle>Revenus vs Dépenses par mois</CardTitle>
</CardHeader> </CardHeader>
@@ -122,7 +137,7 @@ export function MonthlyChart({
} }
return ( return (
<Card> <Card className="card-hover">
<Collapsible open={isExpanded} onOpenChange={setIsExpanded}> <Collapsible open={isExpanded} onOpenChange={setIsExpanded}>
<CardHeader className="flex flex-row items-center justify-between space-y-0 py-3 px-6"> <CardHeader className="flex flex-row items-center justify-between space-y-0 py-3 px-6">
<CardTitle className="text-base font-semibold"> <CardTitle className="text-base font-semibold">

View File

@@ -31,7 +31,7 @@ export function SavingsTrendChart({
const isPositive = latestSavings >= 0; const isPositive = latestSavings >= 0;
return ( return (
<Card> <Card className="card-hover">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle>Évolution des économies</CardTitle> <CardTitle>Évolution des économies</CardTitle>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">

View File

@@ -21,7 +21,7 @@ export function StatsSummaryCards({
return ( return (
<div className="grid gap-3 md:gap-4 grid-cols-2 md:grid-cols-4"> <div className="grid gap-3 md:gap-4 grid-cols-2 md:grid-cols-4">
<Card className="relative overflow-hidden"> <Card className="stat-card-textured relative overflow-hidden">
{/* Icône en arrière-plan */} {/* Icône en arrière-plan */}
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none"> <div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
<TrendingUp className="h-16 w-16 md:h-20 md:w-20 text-emerald-600 dark:text-emerald-400" strokeWidth={1} /> <TrendingUp className="h-16 w-16 md:h-20 md:w-20 text-emerald-600 dark:text-emerald-400" strokeWidth={1} />
@@ -38,7 +38,7 @@ export function StatsSummaryCards({
</CardContent> </CardContent>
</Card> </Card>
<Card className="relative overflow-hidden"> <Card className="stat-card-textured relative overflow-hidden">
{/* Icône en arrière-plan */} {/* Icône en arrière-plan */}
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none"> <div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
<TrendingDown className="h-16 w-16 md:h-20 md:w-20 text-red-600 dark:text-red-400" strokeWidth={1} /> <TrendingDown className="h-16 w-16 md:h-20 md:w-20 text-red-600 dark:text-red-400" strokeWidth={1} />
@@ -55,7 +55,7 @@ export function StatsSummaryCards({
</CardContent> </CardContent>
</Card> </Card>
<Card className="relative overflow-hidden"> <Card className="stat-card-textured relative overflow-hidden">
{/* Icône en arrière-plan */} {/* Icône en arrière-plan */}
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none"> <div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
<ArrowRight className="h-16 w-16 md:h-20 md:w-20 text-muted-foreground/40" strokeWidth={1} /> <ArrowRight className="h-16 w-16 md:h-20 md:w-20 text-muted-foreground/40" strokeWidth={1} />
@@ -72,7 +72,7 @@ export function StatsSummaryCards({
</CardContent> </CardContent>
</Card> </Card>
<Card className="relative overflow-hidden"> <Card className="stat-card-textured relative overflow-hidden">
{/* Icône en arrière-plan */} {/* Icône en arrière-plan */}
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none"> <div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
<div className={cn( <div className={cn(

View File

@@ -21,7 +21,7 @@ export function TopExpensesList({
const isMobile = useIsMobile(); const isMobile = useIsMobile();
return ( return (
<Card> <Card className="card-hover">
<CardHeader> <CardHeader>
<CardTitle className="text-sm md:text-base">Top 5 dépenses</CardTitle> <CardTitle className="text-sm md:text-base">Top 5 dépenses</CardTitle>
</CardHeader> </CardHeader>

View File

@@ -33,7 +33,7 @@ export function YearOverYearChart({
previousYearLabel = "Année précédente", previousYearLabel = "Année précédente",
}: YearOverYearChartProps) { }: YearOverYearChartProps) {
return ( return (
<Card> <Card className="card-hover">
<CardHeader> <CardHeader>
<CardTitle>Comparaison année sur année</CardTitle> <CardTitle>Comparaison année sur année</CardTitle>
</CardHeader> </CardHeader>

View File

@@ -139,19 +139,29 @@ export function useTransactionsChartData({
monthlyMap.set(monthKey, current); monthlyMap.set(monthKey, current);
}); });
const monthlyChartData: MonthlyChartData[] = Array.from( // Format months with year: use short format for better readability
monthlyMap.entries() const sortedMonths = Array.from(monthlyMap.entries()).sort((a, b) =>
) a[0].localeCompare(b[0])
.sort((a, b) => a[0].localeCompare(b[0])) );
.map(([month, values]) => ({
month: new Date(month + "-01").toLocaleDateString("fr-FR", { const monthlyChartData: MonthlyChartData[] = sortedMonths.map(
([monthKey, values]) => {
const date = new Date(monthKey + "-01");
// Format: "janv. 24" instead of "janv. 2024" for compactness
const monthLabel = date.toLocaleDateString("fr-FR", {
month: "short", month: "short",
year: "numeric", });
}), const yearShort = date.getFullYear().toString().slice(-2);
return {
month: `${monthLabel} ${yearShort}`,
revenus: values.income, revenus: values.income,
depenses: values.expenses, depenses: values.expenses,
solde: values.income - values.expenses, solde: values.income - values.expenses,
})); };
}
);
return monthlyChartData; return monthlyChartData;
}, [transactionsData]); }, [transactionsData]);