rfunds-online/components/mortgage/ComparisonPanel.tsx

130 lines
4.9 KiB
TypeScript

'use client'
import type { MortgageSummary } from '@/lib/mortgage-engine'
import type { MortgageState } from '@/lib/mortgage-types'
interface Props {
state: MortgageState
summary: MortgageSummary
}
function fmt(n: number): string {
return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }).format(n)
}
function fmtPct(n: number): string {
return `${n.toFixed(1)}%`
}
export default function ComparisonPanel({ state, summary }: Props) {
const repaidPct = state.totalPrincipal > 0
? (state.totalPrincipalPaid / state.totalPrincipal) * 100
: 0
return (
<div className="flex flex-col gap-4 text-sm">
{/* Progress */}
<div>
<h3 className="text-xs font-semibold text-slate-400 uppercase tracking-wider mb-2">Progress</h3>
<div className="grid grid-cols-2 gap-2">
<StatCard label="Principal Repaid" value={fmt(state.totalPrincipalPaid)} sub={fmtPct(repaidPct)} />
<StatCard label="Remaining" value={fmt(state.totalPrincipalRemaining)} />
<StatCard label="Interest Paid" value={fmt(state.totalInterestPaid)} color="text-amber-400" />
<StatCard label="Tranches Done" value={`${state.tranchesRepaid} / ${state.tranches.length}`} color="text-emerald-400" />
</div>
{/* Overall progress bar */}
<div className="mt-2">
<div className="h-2 bg-slate-700 rounded-full overflow-hidden">
<div
className="h-full bg-gradient-to-r from-sky-500 to-emerald-500 rounded-full transition-all duration-300"
style={{ width: `${Math.min(100, repaidPct)}%` }}
/>
</div>
</div>
</div>
{/* Community Fund */}
{state.communityFundBalance > 0 && (
<div>
<h3 className="text-xs font-semibold text-slate-400 uppercase tracking-wider mb-2">Community Fund</h3>
<div className="bg-emerald-900/30 rounded p-3 border border-emerald-800/50">
<div className="text-lg font-mono text-emerald-400">{fmt(state.communityFundBalance)}</div>
<div className="text-xs text-slate-400 mt-1">Overflow directed to community resilience</div>
</div>
</div>
)}
{/* Comparison */}
<div>
<h3 className="text-xs font-semibold text-slate-400 uppercase tracking-wider mb-2">
rMortgage vs Traditional
</h3>
<div className="space-y-3">
<CompareRow
label="Monthly Payment"
myco={fmt(summary.mycoMonthlyPayment)}
trad={fmt(summary.tradMonthlyPayment)}
/>
<CompareRow
label="Total Interest"
myco={fmt(summary.mycoTotalInterest)}
trad={fmt(summary.tradTotalInterest)}
highlight={summary.interestSaved > 0}
/>
<CompareRow
label="Payoff"
myco={`${Math.ceil(summary.mycoPayoffMonths / 12)}y`}
trad={`${Math.ceil(summary.tradPayoffMonths / 12)}y`}
highlight={summary.monthsSaved > 0}
/>
<CompareRow
label="Avg Lender Yield"
myco={fmtPct(summary.avgLenderYield)}
trad="N/A (bank)"
/>
</div>
</div>
{/* Key insight */}
<div className="bg-gradient-to-br from-sky-900/40 to-emerald-900/40 rounded-lg p-4 border border-sky-800/30">
<h4 className="text-xs font-semibold text-sky-300 uppercase mb-2">Community Wealth</h4>
<div className="text-2xl font-mono text-emerald-400 mb-1">{fmt(summary.communityRetained)}</div>
<p className="text-xs text-slate-400">
Interest that stays in the community instead of flowing to a distant institution.
{summary.interestSaved > 0 && (
<> Plus {fmt(summary.interestSaved)} saved through distributed rates.</>
)}
</p>
</div>
</div>
)
}
function StatCard({ label, value, sub, color }: { label: string; value: string; sub?: string; color?: string }) {
return (
<div className="bg-slate-800 rounded p-2">
<div className="text-[10px] text-slate-500 uppercase">{label}</div>
<div className={`text-sm font-mono ${color ?? 'text-white'}`}>
{value}
{sub && <span className="text-xs text-slate-400 ml-1">{sub}</span>}
</div>
</div>
)
}
function CompareRow({ label, myco, trad, highlight }: { label: string; myco: string; trad: string; highlight?: boolean }) {
return (
<div className="grid grid-cols-3 gap-2 items-center">
<div className="text-xs text-slate-400">{label}</div>
<div className={`text-xs font-mono text-center px-2 py-1 rounded ${
highlight ? 'bg-emerald-900/40 text-emerald-400' : 'bg-slate-800 text-white'
}`}>
{myco}
</div>
<div className="text-xs font-mono text-center px-2 py-1 rounded bg-slate-800 text-slate-400">
{trad}
</div>
</div>
)
}