feat: enhance transactions page with total amount and count display; integrate collapsible statistics card and update chart data handling
This commit is contained in:
@@ -2,7 +2,14 @@
|
|||||||
|
|
||||||
import { useCallback, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
import { PageLayout, PageHeader } from "@/components/layout";
|
import { PageLayout, PageHeader } from "@/components/layout";
|
||||||
import { RefreshCw, Maximize2, Minimize2 } from "lucide-react";
|
import {
|
||||||
|
RefreshCw,
|
||||||
|
Maximize2,
|
||||||
|
Minimize2,
|
||||||
|
Receipt,
|
||||||
|
Euro,
|
||||||
|
ChevronDown,
|
||||||
|
} from "lucide-react";
|
||||||
import {
|
import {
|
||||||
TransactionFilters,
|
TransactionFilters,
|
||||||
TransactionBulkActions,
|
TransactionBulkActions,
|
||||||
@@ -16,6 +23,12 @@ import { OFXImportDialog } from "@/components/import/ofx-import-dialog";
|
|||||||
import { MonthlyChart } from "@/components/statistics";
|
import { MonthlyChart } from "@/components/statistics";
|
||||||
import { useQueryClient } from "@tanstack/react-query";
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
import {
|
||||||
|
Collapsible,
|
||||||
|
CollapsibleContent,
|
||||||
|
CollapsibleTrigger,
|
||||||
|
} from "@/components/ui/collapsible";
|
||||||
import { Upload } from "lucide-react";
|
import { Upload } from "lucide-react";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
@@ -98,7 +111,12 @@ export default function TransactionsPage() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Chart data
|
// Chart data
|
||||||
const { monthlyData, isLoading: isLoadingChart } = useTransactionsChartData({
|
const {
|
||||||
|
monthlyData,
|
||||||
|
isLoading: isLoadingChart,
|
||||||
|
totalAmount: chartTotalAmount,
|
||||||
|
totalCount: chartTotalCount,
|
||||||
|
} = useTransactionsChartData({
|
||||||
selectedAccounts,
|
selectedAccounts,
|
||||||
selectedCategories,
|
selectedCategories,
|
||||||
period,
|
period,
|
||||||
@@ -138,6 +156,10 @@ export default function TransactionsPage() {
|
|||||||
? Math.round((uncategorizedCount / totalTransactions) * 100)
|
? Math.round((uncategorizedCount / totalTransactions) * 100)
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
|
// Use total from chart data (all filtered transactions) or fallback to paginated data
|
||||||
|
const totalAmount = chartTotalAmount ?? 0;
|
||||||
|
const displayTotalCount = chartTotalCount ?? totalTransactions;
|
||||||
|
|
||||||
// For filter comboboxes, we'll use empty arrays for now
|
// For filter comboboxes, we'll use empty arrays for now
|
||||||
// They can be enhanced later with separate queries if needed
|
// They can be enhanced later with separate queries if needed
|
||||||
const transactionsForAccountFilter: never[] = [];
|
const transactionsForAccountFilter: never[] = [];
|
||||||
@@ -199,19 +221,80 @@ export default function TransactionsPage() {
|
|||||||
transactionsForCategoryFilter={transactionsForCategoryFilter}
|
transactionsForCategoryFilter={transactionsForCategoryFilter}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{(!isLoadingChart || !isLoadingTransactions) && (
|
||||||
|
<Card className="mb-6">
|
||||||
|
<Collapsible defaultOpen={true}>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 py-3 px-6">
|
||||||
|
<CardTitle className="text-base font-semibold">
|
||||||
|
Statistiques
|
||||||
|
</CardTitle>
|
||||||
|
<CollapsibleTrigger asChild>
|
||||||
|
<Button variant="ghost" size="sm" className="h-8">
|
||||||
|
<ChevronDown className="w-4 h-4 mr-1" />
|
||||||
|
Réduire
|
||||||
|
</Button>
|
||||||
|
</CollapsibleTrigger>
|
||||||
|
</CardHeader>
|
||||||
|
<CollapsibleContent>
|
||||||
|
<CardContent className="pt-0">
|
||||||
|
{/* Summary cards */}
|
||||||
|
{!isLoadingTransactions && (
|
||||||
|
<div className="grid gap-4 grid-cols-2 mb-6">
|
||||||
|
<Card>
|
||||||
|
<CardContent className="pt-6">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<p className="text-sm font-medium text-muted-foreground">
|
||||||
|
Nombre de transactions
|
||||||
|
</p>
|
||||||
|
<p className="text-2xl font-bold mt-1">
|
||||||
|
{displayTotalCount}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Receipt className="w-8 h-8 text-muted-foreground" />
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
<Card>
|
||||||
|
<CardContent className="pt-6">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<p className="text-sm font-medium text-muted-foreground">
|
||||||
|
Total
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
className={`text-2xl font-bold mt-1 ${
|
||||||
|
totalAmount >= 0
|
||||||
|
? "text-emerald-600"
|
||||||
|
: "text-red-600"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{formatCurrency(totalAmount)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Euro className="w-8 h-8 text-muted-foreground" />
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Chart */}
|
||||||
{!isLoadingChart && monthlyData.length > 0 && (
|
{!isLoadingChart && monthlyData.length > 0 && (
|
||||||
<div className="mb-6">
|
|
||||||
<MonthlyChart
|
<MonthlyChart
|
||||||
data={monthlyData}
|
data={monthlyData}
|
||||||
formatCurrency={formatCurrency}
|
formatCurrency={formatCurrency}
|
||||||
collapsible
|
collapsible={false}
|
||||||
defaultExpanded={true}
|
|
||||||
showDots={
|
showDots={
|
||||||
period !== "all" &&
|
period !== "all" &&
|
||||||
(period === "12months" || monthlyData.length <= 12)
|
(period === "12months" || monthlyData.length <= 12)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
)}
|
||||||
|
</CardContent>
|
||||||
|
</CollapsibleContent>
|
||||||
|
</Collapsible>
|
||||||
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<TransactionBulkActions
|
<TransactionBulkActions
|
||||||
|
|||||||
@@ -191,10 +191,25 @@ export function useTransactionsChartData({
|
|||||||
return categoryChartData;
|
return categoryChartData;
|
||||||
}, [transactionsData, metadata]);
|
}, [transactionsData, metadata]);
|
||||||
|
|
||||||
|
// Calculate total amount and count from all filtered transactions
|
||||||
|
const totalAmount = useMemo(() => {
|
||||||
|
if (!transactionsData) return 0;
|
||||||
|
return transactionsData.transactions.reduce(
|
||||||
|
(sum, t) => sum + t.amount,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}, [transactionsData]);
|
||||||
|
|
||||||
|
const totalCount = useMemo(() => {
|
||||||
|
return transactionsData?.total || 0;
|
||||||
|
}, [transactionsData?.total]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
monthlyData,
|
monthlyData,
|
||||||
categoryData,
|
categoryData,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
totalAmount,
|
||||||
|
totalCount,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user