feat(expenses): enhance expenses management with filtering and search capabilities

This commit is contained in:
Jose Selesan
2026-05-29 14:56:35 -03:00
parent e99e97aa14
commit d3cf386be5
9 changed files with 379 additions and 17 deletions

View File

@@ -11,7 +11,15 @@ import {
ResponsiveDialogDescription,
} from "@/components/ui/responsive-dialog";
import { Button } from "@/components/ui/button";
import { Plus, Upload } from "lucide-react";
import { Input } from "@/components/ui/input";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Plus, Upload, Search, X } from "lucide-react";
import type { Expense, ImportExpensesResult } from "@/lib/api";
const priceFormatter = new Intl.NumberFormat("es-AR", {
@@ -32,6 +40,11 @@ export function ExpensesTabContent() {
isLoadingTotals,
totalPending,
isLoadingTotalPending,
periodicExpenses,
periodicExpenseFilter,
setPeriodicExpenseFilter,
searchInput,
setSearchInput,
importExpenses,
} = useExpensesContext();
@@ -64,7 +77,44 @@ export function ExpensesTabContent() {
</Button>
))}
</div>
<div className="flex gap-2">
<div className="flex items-center gap-2">
<div className="relative w-48">
<Search className="pointer-events-none absolute left-2.5 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
<Input
placeholder="Buscar por descripción..."
value={searchInput}
onChange={(e) => setSearchInput(e.target.value)}
className="pl-8 pr-8"
/>
{searchInput && (
<button
type="button"
onClick={() => setSearchInput("")}
className="absolute right-1.5 top-1/2 -translate-y-1/2 flex size-5 items-center justify-center rounded-md text-muted-foreground hover:bg-muted hover:text-foreground transition-colors"
>
<X className="size-3.5" />
</button>
)}
</div>
<Select
value={periodicExpenseFilter !== undefined ? String(periodicExpenseFilter) : "all"}
onValueChange={(val) => {
setPeriodicExpenseFilter(val === "all" ? undefined : Number(val));
setPage(1);
}}
>
<SelectTrigger className="w-52">
<SelectValue placeholder="Todos los gastos" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">Todos los gastos periódicos</SelectItem>
{periodicExpenses.map((pe) => (
<SelectItem key={pe.id} value={String(pe.id)}>
{pe.description}
</SelectItem>
))}
</SelectContent>
</Select>
<Button onClick={() => setImportDialogOpen(true)} variant="outline" size="sm">
<Upload className="size-4" />
Importar