Files
finanzas/components/debts/DebtCard.tsx
renato97 712b06f118 feat: initial commit - finanzas app
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)
2026-01-29 00:00:32 +00:00

141 lines
4.6 KiB
TypeScript

'use client'
import { FixedDebt, VariableDebt } from '@/lib/types'
import { formatCurrency, formatShortDate } from '@/lib/utils'
import { cn } from '@/lib/utils'
import { Pencil, Trash2, Check } from 'lucide-react'
interface DebtCardProps {
debt: FixedDebt | VariableDebt
type: 'fixed' | 'variable'
onTogglePaid: () => void
onEdit: () => void
onDelete: () => void
}
const fixedCategoryColors: Record<string, string> = {
housing: 'bg-blue-500/20 text-blue-400 border-blue-500/30',
services: 'bg-yellow-500/20 text-yellow-400 border-yellow-500/30',
subscription: 'bg-purple-500/20 text-purple-400 border-purple-500/30',
other: 'bg-gray-500/20 text-gray-400 border-gray-500/30',
}
const variableCategoryColors: Record<string, string> = {
shopping: 'bg-pink-500/20 text-pink-400 border-pink-500/30',
food: 'bg-orange-500/20 text-orange-400 border-orange-500/30',
entertainment: 'bg-indigo-500/20 text-indigo-400 border-indigo-500/30',
health: 'bg-red-500/20 text-red-400 border-red-500/30',
transport: 'bg-cyan-500/20 text-cyan-400 border-cyan-500/30',
other: 'bg-gray-500/20 text-gray-400 border-gray-500/30',
}
const categoryLabels: Record<string, string> = {
housing: 'Vivienda',
services: 'Servicios',
subscription: 'Suscripción',
shopping: 'Compras',
food: 'Comida',
entertainment: 'Entretenimiento',
health: 'Salud',
transport: 'Transporte',
other: 'Otro',
}
export function DebtCard({ debt, type, onTogglePaid, onEdit, onDelete }: DebtCardProps) {
const isFixed = type === 'fixed'
const categoryColors = isFixed ? fixedCategoryColors : variableCategoryColors
const categoryColor = categoryColors[debt.category] || categoryColors.other
const getDueInfo = () => {
if (isFixed) {
const fixedDebt = debt as FixedDebt
return `Vence día ${fixedDebt.dueDay}`
} else {
const variableDebt = debt as VariableDebt
return formatShortDate(variableDebt.date)
}
}
return (
<div
className={cn(
'group relative bg-slate-800 border border-slate-700/50 rounded-lg p-4',
'transition-all duration-200 hover:border-slate-600',
debt.isPaid && 'opacity-60'
)}
>
<div className="flex items-start gap-3">
{/* Checkbox */}
<button
onClick={onTogglePaid}
className={cn(
'mt-1 w-5 h-5 rounded border-2 flex items-center justify-center',
'transition-colors duration-200',
debt.isPaid
? 'bg-emerald-500 border-emerald-500'
: 'border-slate-500 hover:border-emerald-400'
)}
aria-label={debt.isPaid ? 'Marcar como no pagada' : 'Marcar como pagada'}
>
{debt.isPaid && <Check className="w-3 h-3 text-white" />}
</button>
{/* Content */}
<div className="flex-1 min-w-0">
<div className="flex items-start justify-between gap-2">
<div>
<h3
className={cn(
'text-white font-medium truncate',
debt.isPaid && 'line-through text-slate-400'
)}
>
{debt.name}
</h3>
<p className="text-slate-400 text-sm mt-0.5">{getDueInfo()}</p>
</div>
<span className="font-mono text-emerald-400 font-semibold whitespace-nowrap">
{formatCurrency(debt.amount)}
</span>
</div>
<div className="flex items-center justify-between mt-3">
<span
className={cn(
'inline-flex items-center px-2 py-0.5 rounded text-xs font-medium border',
categoryColor
)}
>
{categoryLabels[debt.category] || debt.category}
</span>
{isFixed && (debt as FixedDebt).isAutoDebit && (
<span className="text-xs text-slate-500">
Débito automático
</span>
)}
</div>
</div>
{/* Actions */}
<div className="flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
<button
onClick={onEdit}
className="p-1.5 text-slate-400 hover:text-blue-400 hover:bg-blue-500/10 rounded transition-colors"
aria-label="Editar"
>
<Pencil className="w-4 h-4" />
</button>
<button
onClick={onDelete}
className="p-1.5 text-slate-400 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors"
aria-label="Eliminar"
>
<Trash2 className="w-4 h-4" />
</button>
</div>
</div>
</div>
)
}