feat: implement enhanced transaction filtering capabilities with support for account and category filters, improving data visibility and user interaction
This commit is contained in:
@@ -33,25 +33,55 @@ export default function StatisticsPage() {
|
||||
const [selectedAccounts, setSelectedAccounts] = useState<string[]>(["all"]);
|
||||
const [selectedCategories, setSelectedCategories] = useState<string[]>(["all"]);
|
||||
|
||||
const stats = useMemo(() => {
|
||||
if (!data) return null;
|
||||
|
||||
// Get start date based on period
|
||||
const startDate = useMemo(() => {
|
||||
const now = new Date();
|
||||
let startDate: Date;
|
||||
|
||||
switch (period) {
|
||||
case "3months":
|
||||
startDate = new Date(now.getFullYear(), now.getMonth() - 3, 1);
|
||||
break;
|
||||
return new Date(now.getFullYear(), now.getMonth() - 3, 1);
|
||||
case "6months":
|
||||
startDate = new Date(now.getFullYear(), now.getMonth() - 6, 1);
|
||||
break;
|
||||
return new Date(now.getFullYear(), now.getMonth() - 6, 1);
|
||||
case "12months":
|
||||
startDate = new Date(now.getFullYear(), now.getMonth() - 12, 1);
|
||||
break;
|
||||
return new Date(now.getFullYear(), now.getMonth() - 12, 1);
|
||||
default:
|
||||
startDate = new Date(0);
|
||||
return new Date(0);
|
||||
}
|
||||
}, [period]);
|
||||
|
||||
// Transactions filtered for account filter (by categories, period - not accounts)
|
||||
const transactionsForAccountFilter = useMemo(() => {
|
||||
if (!data) return [];
|
||||
|
||||
return data.transactions.filter(
|
||||
(t) => new Date(t.date) >= startDate
|
||||
).filter((t) => {
|
||||
if (!selectedCategories.includes("all")) {
|
||||
if (selectedCategories.includes("uncategorized")) {
|
||||
return !t.categoryId;
|
||||
} else {
|
||||
return t.categoryId && selectedCategories.includes(t.categoryId);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}, [data, startDate, selectedCategories]);
|
||||
|
||||
// Transactions filtered for category filter (by accounts, period - not categories)
|
||||
const transactionsForCategoryFilter = useMemo(() => {
|
||||
if (!data) return [];
|
||||
|
||||
return data.transactions.filter(
|
||||
(t) => new Date(t.date) >= startDate
|
||||
).filter((t) => {
|
||||
if (!selectedAccounts.includes("all")) {
|
||||
return selectedAccounts.includes(t.accountId);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}, [data, startDate, selectedAccounts]);
|
||||
|
||||
const stats = useMemo(() => {
|
||||
if (!data) return null;
|
||||
|
||||
let transactions = data.transactions.filter(
|
||||
(t) => new Date(t.date) >= startDate
|
||||
@@ -226,7 +256,7 @@ export default function StatisticsPage() {
|
||||
perAccountBalanceData,
|
||||
transactionCount: transactions.length,
|
||||
};
|
||||
}, [data, period, selectedAccounts, selectedCategories]);
|
||||
}, [data, startDate, selectedAccounts, selectedCategories]);
|
||||
|
||||
const formatCurrency = (amount: number) => {
|
||||
return new Intl.NumberFormat("fr-FR", {
|
||||
@@ -255,6 +285,7 @@ export default function StatisticsPage() {
|
||||
value={selectedAccounts}
|
||||
onChange={setSelectedAccounts}
|
||||
className="w-[200px]"
|
||||
filteredTransactions={transactionsForAccountFilter}
|
||||
/>
|
||||
|
||||
<CategoryFilterCombobox
|
||||
@@ -262,6 +293,7 @@ export default function StatisticsPage() {
|
||||
value={selectedCategories}
|
||||
onChange={setSelectedCategories}
|
||||
className="w-[220px]"
|
||||
filteredTransactions={transactionsForCategoryFilter}
|
||||
/>
|
||||
|
||||
<Select
|
||||
|
||||
@@ -46,6 +46,72 @@ export default function TransactionsPage() {
|
||||
const [ruleDialogOpen, setRuleDialogOpen] = useState(false);
|
||||
const [ruleTransaction, setRuleTransaction] = useState<Transaction | null>(null);
|
||||
|
||||
// Transactions filtered for account filter (by categories, search, reconciled - not accounts)
|
||||
const transactionsForAccountFilter = useMemo(() => {
|
||||
if (!data) return [];
|
||||
|
||||
let transactions = [...data.transactions];
|
||||
|
||||
if (searchQuery) {
|
||||
const query = searchQuery.toLowerCase();
|
||||
transactions = transactions.filter(
|
||||
(t) =>
|
||||
t.description.toLowerCase().includes(query) ||
|
||||
t.memo?.toLowerCase().includes(query)
|
||||
);
|
||||
}
|
||||
|
||||
if (!selectedCategories.includes("all")) {
|
||||
if (selectedCategories.includes("uncategorized")) {
|
||||
transactions = transactions.filter((t) => !t.categoryId);
|
||||
} else {
|
||||
transactions = transactions.filter(
|
||||
(t) => t.categoryId && selectedCategories.includes(t.categoryId)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (showReconciled !== "all") {
|
||||
const isReconciled = showReconciled === "reconciled";
|
||||
transactions = transactions.filter(
|
||||
(t) => t.isReconciled === isReconciled
|
||||
);
|
||||
}
|
||||
|
||||
return transactions;
|
||||
}, [data, searchQuery, selectedCategories, showReconciled]);
|
||||
|
||||
// Transactions filtered for category filter (by accounts, search, reconciled - not categories)
|
||||
const transactionsForCategoryFilter = useMemo(() => {
|
||||
if (!data) return [];
|
||||
|
||||
let transactions = [...data.transactions];
|
||||
|
||||
if (searchQuery) {
|
||||
const query = searchQuery.toLowerCase();
|
||||
transactions = transactions.filter(
|
||||
(t) =>
|
||||
t.description.toLowerCase().includes(query) ||
|
||||
t.memo?.toLowerCase().includes(query)
|
||||
);
|
||||
}
|
||||
|
||||
if (!selectedAccounts.includes("all")) {
|
||||
transactions = transactions.filter(
|
||||
(t) => selectedAccounts.includes(t.accountId)
|
||||
);
|
||||
}
|
||||
|
||||
if (showReconciled !== "all") {
|
||||
const isReconciled = showReconciled === "reconciled";
|
||||
transactions = transactions.filter(
|
||||
(t) => t.isReconciled === isReconciled
|
||||
);
|
||||
}
|
||||
|
||||
return transactions;
|
||||
}, [data, searchQuery, selectedAccounts, showReconciled]);
|
||||
|
||||
const filteredTransactions = useMemo(() => {
|
||||
if (!data) return [];
|
||||
|
||||
@@ -385,6 +451,8 @@ export default function TransactionsPage() {
|
||||
accounts={data.accounts}
|
||||
folders={data.folders}
|
||||
categories={data.categories}
|
||||
transactionsForAccountFilter={transactionsForAccountFilter}
|
||||
transactionsForCategoryFilter={transactionsForCategoryFilter}
|
||||
/>
|
||||
|
||||
<TransactionBulkActions
|
||||
|
||||
Reference in New Issue
Block a user