Files
finanzas/app/incomes/page.tsx

166 lines
6.8 KiB
TypeScript

'use client'
import { useState } from 'react'
import { useFinanzasStore } from '@/lib/store'
import { Plus, Trash2, TrendingUp, DollarSign } from 'lucide-react'
import { format } from 'date-fns'
import { es } from 'date-fns/locale'
import { DashboardLayout } from '@/components/layout/DashboardLayout'
export default function IncomesPage() {
const incomes = useFinanzasStore((state) => state.incomes) || []
const addIncome = useFinanzasStore((state) => state.addIncome)
const removeIncome = useFinanzasStore((state) => state.removeIncome)
const [newIncome, setNewIncome] = useState({
amount: '',
description: '',
category: 'salary' as const,
})
const handleAdd = () => {
if (!newIncome.amount || !newIncome.description) return
addIncome({
amount: parseFloat(newIncome.amount),
description: newIncome.description,
category: newIncome.category,
date: new Date().toISOString(),
})
setNewIncome({ amount: '', description: '', category: 'salary' })
}
const totalIncomes = incomes.reduce((acc, curr) => acc + curr.amount, 0)
return (
<DashboardLayout title="Ingresos">
<div className="space-y-6">
<div className="flex items-center justify-between">
<h2 className="text-3xl font-bold flex items-center gap-2 text-white">
<TrendingUp className="text-green-500" /> Ingresos
</h2>
<div className="text-right">
<p className="text-sm text-gray-400">Total Acumulado</p>
<p className="text-2xl font-bold text-green-400">
${totalIncomes.toLocaleString()}
</p>
</div>
</div>
<div className="grid md:grid-cols-3 gap-6">
{/* Formulario */}
<div className="bg-slate-800 border border-slate-700 rounded-xl md:col-span-1 h-fit overflow-hidden">
<div className="p-6 border-b border-slate-700">
<h3 className="font-semibold text-lg text-white">Nuevo Ingreso</h3>
</div>
<div className="p-6 space-y-4">
<div>
<label className="text-sm text-gray-400 block mb-2">Descripción</label>
<input
placeholder="Ej. Pago Freelance"
value={newIncome.description}
onChange={(e) =>
setNewIncome({ ...newIncome, description: e.target.value })
}
className="w-full bg-slate-700 border-slate-600 border rounded-lg px-3 py-2 text-white focus:outline-none focus:ring-2 focus:ring-emerald-500"
/>
</div>
<div>
<label className="text-sm text-gray-400 block mb-2">Monto</label>
<div className="relative">
<DollarSign className="absolute left-3 top-2.5 h-4 w-4 text-gray-400" />
<input
type="number"
placeholder="0.00"
value={newIncome.amount}
onChange={(e) =>
setNewIncome({ ...newIncome, amount: e.target.value })
}
className="w-full pl-9 bg-slate-700 border-slate-600 border rounded-lg px-3 py-2 text-white focus:outline-none focus:ring-2 focus:ring-emerald-500"
/>
</div>
</div>
<div>
<label className="text-sm text-gray-400 block mb-2">Categoría</label>
<select
className="w-full bg-slate-700 border border-slate-600 rounded-lg px-3 py-2 text-sm text-white focus:outline-none focus:ring-2 focus:ring-emerald-500"
value={newIncome.category}
onChange={(e) =>
setNewIncome({
...newIncome,
category: e.target.value as any,
})
}
>
<option value="salary">Salario</option>
<option value="freelance">Freelance</option>
<option value="business">Negocio</option>
<option value="gift">Regalo</option>
<option value="other">Otro</option>
</select>
</div>
<button
onClick={handleAdd}
className="w-full bg-emerald-600 hover:bg-emerald-700 text-white font-semibold py-2 px-4 rounded-lg flex items-center justify-center gap-2 transition-colors"
>
<Plus className="w-4 h-4" /> Agregar Ingreso
</button>
</div>
</div>
{/* Lista */}
<div className="bg-slate-800 border border-slate-700 rounded-xl md:col-span-2 overflow-hidden">
<div className="p-6 border-b border-slate-700">
<h3 className="font-semibold text-lg text-white">Historial de Ingresos</h3>
</div>
<div className="p-6">
{incomes.length === 0 ? (
<p className="text-center text-gray-500 py-8">
No hay ingresos registrados aún.
</p>
) : (
<div className="space-y-4">
{incomes
.sort(
(a, b) =>
new Date(b.date).getTime() - new Date(a.date).getTime()
)
.map((income) => (
<div
key={income.id}
className="flex items-center justify-between p-4 bg-slate-700/50 rounded-lg border border-slate-700 hover:border-slate-600 transition-colors"
>
<div>
<p className="font-semibold text-white">
{income.description}
</p>
<p className="text-xs text-gray-400 capitalize">
{income.category} {' '}
{format(new Date(income.date), "d 'de' MMMM", {
locale: es,
})}
</p>
</div>
<div className="flex items-center gap-4">
<span className="text-emerald-400 font-mono font-bold">
+${income.amount.toLocaleString()}
</span>
<button
onClick={() => removeIncome(income.id)}
className="text-slate-500 hover:text-red-400 transition-colors"
>
<Trash2 className="w-4 h-4" />
</button>
</div>
</div>
))}
</div>
)}
</div>
</div>
</div>
</div>
</DashboardLayout>
)
}