Files
finanzas/components/budget/BudgetRing.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

84 lines
2.5 KiB
TypeScript

'use client'
import { cn, formatCurrency } from '@/lib/utils'
interface BudgetRingProps {
spent: number
total: number
label: string
}
export function BudgetRing({ spent, total, label }: BudgetRingProps) {
const percentage = total > 0 ? Math.min((spent / total) * 100, 100) : 0
const remaining = Math.max(total - spent, 0)
const getColor = () => {
if (percentage < 70) return { stroke: '#10b981', bg: 'text-emerald-400' }
if (percentage < 90) return { stroke: '#f59e0b', bg: 'text-amber-400' }
return { stroke: '#ef4444', bg: 'text-red-400' }
}
const colors = getColor()
const radius = 80
const strokeWidth = 12
const normalizedRadius = radius - strokeWidth / 2
const circumference = normalizedRadius * 2 * Math.PI
const strokeDashoffset = circumference - (percentage / 100) * circumference
return (
<div className="flex flex-col items-center">
<div className="relative">
<svg
width={radius * 2}
height={radius * 2}
className="transform -rotate-90"
>
{/* Background circle */}
<circle
stroke="#334155"
strokeWidth={strokeWidth}
fill="transparent"
r={normalizedRadius}
cx={radius}
cy={radius}
/>
{/* Progress circle */}
<circle
stroke={colors.stroke}
strokeWidth={strokeWidth}
strokeLinecap="round"
fill="transparent"
r={normalizedRadius}
cx={radius}
cy={radius}
style={{
strokeDasharray: `${circumference} ${circumference}`,
strokeDashoffset,
transition: 'stroke-dashoffset 0.5s ease-in-out',
}}
/>
</svg>
{/* Center content */}
<div className="absolute inset-0 flex flex-col items-center justify-center">
<span className={cn('text-3xl font-bold', colors.bg)}>
{percentage.toFixed(0)}%
</span>
<span className="text-slate-400 text-sm mt-1">usado</span>
</div>
</div>
{/* Stats below */}
<div className="mt-4 text-center">
<p className="text-slate-400 text-sm">{label}</p>
<p className="text-lg font-semibold text-white mt-1">
{formatCurrency(spent)} <span className="text-slate-500">/ {formatCurrency(total)}</span>
</p>
<p className="text-sm text-slate-500 mt-1">
{formatCurrency(remaining)} disponible
</p>
</div>
</div>
)
}