feat: refactor transaction filters to support multiple account selection and improve UI with new account filter component
This commit is contained in:
@@ -11,33 +11,36 @@ import {
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { CategoryFilterCombobox } from "@/components/ui/category-filter-combobox";
|
||||
import { AccountFilterCombobox } from "@/components/ui/account-filter-combobox";
|
||||
import { CategoryIcon } from "@/components/ui/category-icon";
|
||||
import { Search, X, Filter } from "lucide-react";
|
||||
import type { Account, Category } from "@/lib/types";
|
||||
import { Search, X, Filter, Wallet } from "lucide-react";
|
||||
import type { Account, Category, Folder } from "@/lib/types";
|
||||
|
||||
interface TransactionFiltersProps {
|
||||
searchQuery: string;
|
||||
onSearchChange: (query: string) => void;
|
||||
selectedAccount: string;
|
||||
onAccountChange: (account: string) => void;
|
||||
selectedAccounts: string[];
|
||||
onAccountsChange: (accounts: string[]) => void;
|
||||
selectedCategories: string[];
|
||||
onCategoriesChange: (categories: string[]) => void;
|
||||
showReconciled: string;
|
||||
onReconciledChange: (value: string) => void;
|
||||
accounts: Account[];
|
||||
folders: Folder[];
|
||||
categories: Category[];
|
||||
}
|
||||
|
||||
export function TransactionFilters({
|
||||
searchQuery,
|
||||
onSearchChange,
|
||||
selectedAccount,
|
||||
onAccountChange,
|
||||
selectedAccounts,
|
||||
onAccountsChange,
|
||||
selectedCategories,
|
||||
onCategoriesChange,
|
||||
showReconciled,
|
||||
onReconciledChange,
|
||||
accounts,
|
||||
folders,
|
||||
categories,
|
||||
}: TransactionFiltersProps) {
|
||||
return (
|
||||
@@ -56,19 +59,13 @@ export function TransactionFilters({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Select value={selectedAccount} onValueChange={onAccountChange}>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectValue placeholder="Compte" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">Tous les comptes</SelectItem>
|
||||
{accounts.map((account) => (
|
||||
<SelectItem key={account.id} value={account.id}>
|
||||
{account.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<AccountFilterCombobox
|
||||
accounts={accounts}
|
||||
folders={folders}
|
||||
value={selectedAccounts}
|
||||
onChange={onAccountsChange}
|
||||
className="w-[200px]"
|
||||
/>
|
||||
|
||||
<CategoryFilterCombobox
|
||||
categories={categories}
|
||||
@@ -92,8 +89,12 @@ export function TransactionFilters({
|
||||
<ActiveFilters
|
||||
searchQuery={searchQuery}
|
||||
onClearSearch={() => onSearchChange("")}
|
||||
selectedAccount={selectedAccount}
|
||||
onClearAccount={() => onAccountChange("all")}
|
||||
selectedAccounts={selectedAccounts}
|
||||
onRemoveAccount={(id) => {
|
||||
const newAccounts = selectedAccounts.filter((a) => a !== id);
|
||||
onAccountsChange(newAccounts.length > 0 ? newAccounts : ["all"]);
|
||||
}}
|
||||
onClearAccounts={() => onAccountsChange(["all"])}
|
||||
selectedCategories={selectedCategories}
|
||||
onRemoveCategory={(id) => {
|
||||
const newCategories = selectedCategories.filter((c) => c !== id);
|
||||
@@ -113,8 +114,9 @@ export function TransactionFilters({
|
||||
function ActiveFilters({
|
||||
searchQuery,
|
||||
onClearSearch,
|
||||
selectedAccount,
|
||||
onClearAccount,
|
||||
selectedAccounts,
|
||||
onRemoveAccount,
|
||||
onClearAccounts,
|
||||
selectedCategories,
|
||||
onRemoveCategory,
|
||||
onClearCategories,
|
||||
@@ -125,8 +127,9 @@ function ActiveFilters({
|
||||
}: {
|
||||
searchQuery: string;
|
||||
onClearSearch: () => void;
|
||||
selectedAccount: string;
|
||||
onClearAccount: () => void;
|
||||
selectedAccounts: string[];
|
||||
onRemoveAccount: (id: string) => void;
|
||||
onClearAccounts: () => void;
|
||||
selectedCategories: string[];
|
||||
onRemoveCategory: (id: string) => void;
|
||||
onClearCategories: () => void;
|
||||
@@ -136,21 +139,21 @@ function ActiveFilters({
|
||||
categories: Category[];
|
||||
}) {
|
||||
const hasSearch = searchQuery.trim() !== "";
|
||||
const hasAccount = selectedAccount !== "all";
|
||||
const hasAccounts = !selectedAccounts.includes("all");
|
||||
const hasCategories = !selectedCategories.includes("all");
|
||||
const hasReconciled = showReconciled !== "all";
|
||||
|
||||
const hasActiveFilters = hasSearch || hasAccount || hasCategories || hasReconciled;
|
||||
const hasActiveFilters = hasSearch || hasAccounts || hasCategories || hasReconciled;
|
||||
|
||||
if (!hasActiveFilters) return null;
|
||||
|
||||
const account = accounts.find((a) => a.id === selectedAccount);
|
||||
const selectedAccs = accounts.filter((a) => selectedAccounts.includes(a.id));
|
||||
const selectedCats = categories.filter((c) => selectedCategories.includes(c.id));
|
||||
const isUncategorized = selectedCategories.includes("uncategorized");
|
||||
|
||||
const clearAll = () => {
|
||||
onClearSearch();
|
||||
onClearAccount();
|
||||
onClearAccounts();
|
||||
onClearCategories();
|
||||
onClearReconciled();
|
||||
};
|
||||
@@ -168,14 +171,18 @@ function ActiveFilters({
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
{hasAccount && account && (
|
||||
<Badge variant="secondary" className="gap-1 text-xs font-normal">
|
||||
Compte: {account.name}
|
||||
<button onClick={onClearAccount} className="ml-1 hover:text-foreground">
|
||||
{selectedAccs.map((acc) => (
|
||||
<Badge key={acc.id} variant="secondary" className="gap-1 text-xs font-normal">
|
||||
<Wallet className="h-3 w-3" />
|
||||
{acc.name}
|
||||
<button
|
||||
onClick={() => onRemoveAccount(acc.id)}
|
||||
className="ml-1 hover:text-foreground"
|
||||
>
|
||||
<X className="h-3 w-3" />
|
||||
</button>
|
||||
</Badge>
|
||||
)}
|
||||
))}
|
||||
|
||||
{isUncategorized && (
|
||||
<Badge variant="secondary" className="gap-1 text-xs font-normal">
|
||||
|
||||
Reference in New Issue
Block a user