Complete personal finance management application with: - Dashboard with financial metrics and alerts - Credit card management and payments - Fixed and variable debt tracking - Monthly budget planning - Intelligent alert system - Responsive design with Tailwind CSS Tech stack: Next.js 14, TypeScript, Zustand, Recharts 🤖 Generated with [Claude Code](https://claude.com/claude-code)
135 lines
3.8 KiB
TypeScript
135 lines
3.8 KiB
TypeScript
'use client'
|
|
|
|
import { useEffect, useState } from 'react'
|
|
import { Sidebar, Header, MobileNav } from '@/components/layout'
|
|
import { SummarySection, QuickActions, RecentActivity } from '@/components/dashboard'
|
|
import { useSidebar } from '@/app/providers'
|
|
import { useFinanzasStore } from '@/lib/store'
|
|
import { AlertBanner, useAlerts } from '@/components/alerts'
|
|
import { AddDebtModal } from '@/components/modals/AddDebtModal'
|
|
import { AddCardModal } from '@/components/modals/AddCardModal'
|
|
import { AddPaymentModal } from '@/components/modals/AddPaymentModal'
|
|
|
|
export default function Home() {
|
|
// Sidebar control
|
|
const sidebar = useSidebar()
|
|
|
|
// Datos del store
|
|
const markAlertAsRead = useFinanzasStore((state) => state.markAlertAsRead)
|
|
const deleteAlert = useFinanzasStore((state) => state.deleteAlert)
|
|
|
|
// Alertas
|
|
const { unreadAlerts, unreadCount, regenerateAlerts } = useAlerts()
|
|
|
|
// Estados locales para modales
|
|
const [isAddDebtModalOpen, setIsAddDebtModalOpen] = useState(false)
|
|
const [isAddCardModalOpen, setIsAddCardModalOpen] = useState(false)
|
|
const [isAddPaymentModalOpen, setIsAddPaymentModalOpen] = useState(false)
|
|
|
|
// Efecto para regenerar alertas al cargar la página
|
|
useEffect(() => {
|
|
regenerateAlerts()
|
|
}, [regenerateAlerts])
|
|
|
|
// Efecto para manejar resize de ventana
|
|
useEffect(() => {
|
|
const handleResize = () => {
|
|
if (window.innerWidth >= 1024) {
|
|
sidebar.open()
|
|
} else {
|
|
sidebar.close()
|
|
}
|
|
}
|
|
|
|
// Estado inicial
|
|
handleResize()
|
|
|
|
window.addEventListener('resize', handleResize)
|
|
return () => window.removeEventListener('resize', handleResize)
|
|
}, [sidebar])
|
|
|
|
// Handlers para modales
|
|
const handleAddDebt = () => {
|
|
setIsAddDebtModalOpen(true)
|
|
}
|
|
|
|
const handleAddCard = () => {
|
|
setIsAddCardModalOpen(true)
|
|
}
|
|
|
|
const handleAddPayment = () => {
|
|
setIsAddPaymentModalOpen(true)
|
|
}
|
|
|
|
// Primeras 3 alertas no leídas
|
|
const topAlerts = unreadAlerts.slice(0, 3)
|
|
|
|
return (
|
|
<div className="flex min-h-screen bg-slate-950">
|
|
{/* Sidebar */}
|
|
<Sidebar
|
|
isOpen={sidebar.isOpen}
|
|
onClose={sidebar.close}
|
|
unreadAlertsCount={unreadCount}
|
|
/>
|
|
|
|
{/* Main content */}
|
|
<div className="flex flex-1 flex-col lg:ml-0">
|
|
{/* Header */}
|
|
<Header onMenuClick={sidebar.toggle} title="Dashboard" />
|
|
|
|
{/* Main content area */}
|
|
<main className="flex-1 p-4 md:p-6 lg:p-8 pb-20 lg:pb-8">
|
|
<div className="mx-auto max-w-7xl space-y-6">
|
|
{/* Alertas destacadas */}
|
|
{topAlerts.length > 0 && (
|
|
<div className="space-y-3">
|
|
{topAlerts.map((alert) => (
|
|
<AlertBanner
|
|
key={alert.id}
|
|
alert={alert}
|
|
onDismiss={() => deleteAlert(alert.id)}
|
|
onMarkRead={() => markAlertAsRead(alert.id)}
|
|
/>
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
{/* Sección de resumen */}
|
|
<SummarySection />
|
|
|
|
{/* Acciones rápidas */}
|
|
<QuickActions
|
|
onAddDebt={handleAddDebt}
|
|
onAddCard={handleAddCard}
|
|
onAddPayment={handleAddPayment}
|
|
/>
|
|
|
|
{/* Actividad reciente */}
|
|
<RecentActivity limit={5} />
|
|
</div>
|
|
</main>
|
|
</div>
|
|
|
|
{/* Mobile navigation */}
|
|
<MobileNav unreadAlertsCount={unreadCount} />
|
|
|
|
{/* Modales */}
|
|
<AddDebtModal
|
|
isOpen={isAddDebtModalOpen}
|
|
onClose={() => setIsAddDebtModalOpen(false)}
|
|
/>
|
|
|
|
<AddCardModal
|
|
isOpen={isAddCardModalOpen}
|
|
onClose={() => setIsAddCardModalOpen(false)}
|
|
/>
|
|
|
|
<AddPaymentModal
|
|
isOpen={isAddPaymentModalOpen}
|
|
onClose={() => setIsAddPaymentModalOpen(false)}
|
|
/>
|
|
</div>
|
|
)
|
|
}
|