Split budget Resumen into Detalle, Transacciones, and Proyecciones sub-tabs
All checks were successful
Deploy to VPS / deploy (push) Successful in 14s

Reduces scrolling by organizing the budget overview into three inner tabs.
Clicking a month in the yearly table auto-switches to the Detalle tab.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Carlos Escalante
2026-03-30 11:14:43 -06:00
parent 26a26b8ca2
commit 99d0c4ebd7

View File

@@ -36,6 +36,8 @@ export default function Budget() {
refresh, refresh,
} = useBudget(currentYear); } = useBudget(currentYear);
const [subTab, setSubTab] = useState<'detail' | 'transactions' | 'projections'>('detail');
// Transaction list state for the selected month // Transaction list state for the selected month
const [transactions, setTransactions] = useState<Transaction[]>([]); const [transactions, setTransactions] = useState<Transaction[]>([]);
const [txLoading, setTxLoading] = useState(false); const [txLoading, setTxLoading] = useState(false);
@@ -95,8 +97,50 @@ export default function Budget() {
<TabsTrigger value="items">Items Recurrentes</TabsTrigger> <TabsTrigger value="items">Items Recurrentes</TabsTrigger>
</TabsList> </TabsList>
<TabsContent value="overview" className="space-y-6 mt-4"> <TabsContent value="overview" className="mt-4">
{/* Annual Summary */} <Tabs
value={subTab}
onValueChange={(v) => setSubTab(v as typeof subTab)}
>
<TabsList variant="line">
<TabsTrigger value="detail">
Detalle: {MONTH_NAMES[selectedMonth]} {year}
</TabsTrigger>
<TabsTrigger value="transactions">Transacciones</TabsTrigger>
<TabsTrigger value="projections">Proyecciones</TabsTrigger>
</TabsList>
<TabsContent value="detail" className="space-y-6 mt-4">
{monthDetail && <MonthlyDetail detail={monthDetail} loading={monthLoading} />}
</TabsContent>
<TabsContent value="transactions" className="space-y-3 mt-4">
<Tabs
value={txSource}
onValueChange={(v) => setTxSource(v as typeof txSource)}
>
<TabsList>
<TabsTrigger value="CREDIT_CARD">Tarjeta</TabsTrigger>
<TabsTrigger value="CASH">Efectivo</TabsTrigger>
<TabsTrigger value="TRANSFER">Transferencias</TabsTrigger>
</TabsList>
</Tabs>
<TransactionList
transactions={transactions}
loading={txLoading}
source={txSource}
search={txSearch}
onSearchChange={setTxSearch}
onRefresh={() => {
fetchTransactions();
refresh();
}}
showCategory={txSource === 'CREDIT_CARD'}
emptyMessage={`Sin transacciones de ${txSource === 'CREDIT_CARD' ? 'tarjeta' : txSource === 'CASH' ? 'efectivo' : 'transferencia'} en ${MONTH_NAMES[selectedMonth]}`}
/>
</TabsContent>
<TabsContent value="projections" className="space-y-6 mt-4">
{projection && ( {projection && (
<div className="grid gap-3 grid-cols-2 md:grid-cols-4"> <div className="grid gap-3 grid-cols-2 md:grid-cols-4">
<Card> <Card>
@@ -140,7 +184,6 @@ export default function Budget() {
</div> </div>
)} )}
{/* Yearly Overview Table */}
{loading ? ( {loading ? (
<div className="flex items-center justify-center py-12"> <div className="flex items-center justify-center py-12">
<Loader2 className="w-6 h-6 animate-spin text-muted-foreground" /> <Loader2 className="w-6 h-6 animate-spin text-muted-foreground" />
@@ -151,44 +194,16 @@ export default function Budget() {
<YearlyOverview <YearlyOverview
months={projection.months} months={projection.months}
selectedMonth={selectedMonth} selectedMonth={selectedMonth}
onSelectMonth={setSelectedMonth} onSelectMonth={(m) => {
setSelectedMonth(m);
setSubTab('detail');
}}
/> />
</CardContent> </CardContent>
</Card> </Card>
) : null} ) : null}
</TabsContent>
{/* Monthly Detail */}
{monthDetail && <MonthlyDetail detail={monthDetail} loading={monthLoading} />}
{/* Transactions for selected month */}
<div className="space-y-3">
<h3 className="text-lg font-semibold">
Transacciones {MONTH_NAMES[selectedMonth]} {year}
</h3>
<Tabs
value={txSource}
onValueChange={(v) => setTxSource(v as typeof txSource)}
>
<TabsList>
<TabsTrigger value="CREDIT_CARD">Tarjeta</TabsTrigger>
<TabsTrigger value="CASH">Efectivo</TabsTrigger>
<TabsTrigger value="TRANSFER">Transferencias</TabsTrigger>
</TabsList>
</Tabs> </Tabs>
<TransactionList
transactions={transactions}
loading={txLoading}
source={txSource}
search={txSearch}
onSearchChange={setTxSearch}
onRefresh={() => {
fetchTransactions();
refresh();
}}
showCategory={txSource === 'CREDIT_CARD'}
emptyMessage={`Sin transacciones de ${txSource === 'CREDIT_CARD' ? 'tarjeta' : txSource === 'CASH' ? 'efectivo' : 'transferencia'} en ${MONTH_NAMES[selectedMonth]}`}
/>
</div>
</TabsContent> </TabsContent>
<TabsContent value="items" className="mt-4"> <TabsContent value="items" className="mt-4">