Ran prettier
This commit is contained in:
@@ -14,12 +14,18 @@ export default function CashflowPage() {
|
||||
|
||||
const getMonthlyAmount = (amount: number, frequency: string) => {
|
||||
switch (frequency) {
|
||||
case 'weekly': return amount * 4.33;
|
||||
case 'biweekly': return amount * 2.17;
|
||||
case 'monthly': return amount;
|
||||
case 'quarterly': return amount / 3;
|
||||
case 'yearly': return amount / 12;
|
||||
default: return 0;
|
||||
case 'weekly':
|
||||
return amount * 4.33;
|
||||
case 'biweekly':
|
||||
return amount * 2.17;
|
||||
case 'monthly':
|
||||
return amount;
|
||||
case 'quarterly':
|
||||
return amount / 3;
|
||||
case 'yearly':
|
||||
return amount / 12;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -30,11 +36,16 @@ export default function CashflowPage() {
|
||||
|
||||
const fmt = (value: number) => new Intl.NumberFormat('en-US', {style: 'currency', currency: 'USD', maximumFractionDigits: 0}).format(value);
|
||||
|
||||
const expensesByCategory = expenses.filter(e => e.isActive).reduce((acc, e) => {
|
||||
const monthly = getMonthlyAmount(e.amount, e.frequency);
|
||||
acc[e.category] = (acc[e.category] || 0) + monthly;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
const expensesByCategory = expenses
|
||||
.filter(e => e.isActive)
|
||||
.reduce(
|
||||
(acc, e) => {
|
||||
const monthly = getMonthlyAmount(e.amount, e.frequency);
|
||||
acc[e.category] = (acc[e.category] || 0) + monthly;
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, number>
|
||||
);
|
||||
|
||||
const sortedCategories = Object.entries(expensesByCategory).sort((a, b) => b[1] - a[1]);
|
||||
const topExpenses = expenses.filter(e => e.isActive).sort((a, b) => getMonthlyAmount(b.amount, b.frequency) - getMonthlyAmount(a.amount, a.frequency));
|
||||
@@ -46,15 +57,29 @@ export default function CashflowPage() {
|
||||
<div className="flex items-center gap-6">
|
||||
<h1 className="text-lg font-semibold">Cashflow</h1>
|
||||
<div className="flex gap-4 text-sm">
|
||||
<div><span className="text-muted-foreground">Income</span> <span className="font-medium text-green-400">{fmt(monthlyIncome)}</span></div>
|
||||
<div><span className="text-muted-foreground">Expenses</span> <span className="font-medium">{fmt(monthlyExpenses)}</span></div>
|
||||
<div><span className="text-muted-foreground">Net</span> <span className={`font-semibold ${monthlySavings >= 0 ? 'text-green-400' : 'text-red-400'}`}>{fmt(monthlySavings)}</span></div>
|
||||
<div><span className="text-muted-foreground">Savings</span> <span className={`font-medium ${savingsRate >= 20 ? 'text-green-400' : ''}`}>{savingsRate.toFixed(0)}%</span></div>
|
||||
<div>
|
||||
<span className="text-muted-foreground">Income</span> <span className="font-medium text-green-400">{fmt(monthlyIncome)}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-muted-foreground">Expenses</span> <span className="font-medium">{fmt(monthlyExpenses)}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-muted-foreground">Net</span>{' '}
|
||||
<span className={`font-semibold ${monthlySavings >= 0 ? 'text-green-400' : 'text-red-400'}`}>{fmt(monthlySavings)}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-muted-foreground">Savings</span>{' '}
|
||||
<span className={`font-medium ${savingsRate >= 20 ? 'text-green-400' : ''}`}>{savingsRate.toFixed(0)}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="secondary" size="sm" onClick={() => setIncomeDialogOpen(true)}>Add Income</Button>
|
||||
<Button size="sm" onClick={() => setExpenseDialogOpen(true)}>Add Expense</Button>
|
||||
<Button variant="secondary" size="sm" onClick={() => setIncomeDialogOpen(true)}>
|
||||
Add Income
|
||||
</Button>
|
||||
<Button size="sm" onClick={() => setExpenseDialogOpen(true)}>
|
||||
Add Expense
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -66,15 +91,17 @@ export default function CashflowPage() {
|
||||
</CardHeader>
|
||||
<CardContent className="p-3 pt-0">
|
||||
<div className="space-y-3">
|
||||
{incomeSources.filter(i => i.isActive).map(income => (
|
||||
<div key={income.id} className="flex justify-between items-baseline">
|
||||
<div>
|
||||
<p className="text-sm font-medium">{income.name}</p>
|
||||
<p className="text-xs text-muted-foreground">{income.frequency}</p>
|
||||
{incomeSources
|
||||
.filter(i => i.isActive)
|
||||
.map(income => (
|
||||
<div key={income.id} className="flex justify-between items-baseline">
|
||||
<div>
|
||||
<p className="text-sm font-medium">{income.name}</p>
|
||||
<p className="text-xs text-muted-foreground">{income.frequency}</p>
|
||||
</div>
|
||||
<p className="text-sm font-medium tabular-nums">{fmt(income.amount)}</p>
|
||||
</div>
|
||||
<p className="text-sm font-medium tabular-nums">{fmt(income.amount)}</p>
|
||||
</div>
|
||||
))}
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -106,7 +133,9 @@ export default function CashflowPage() {
|
||||
<Card className="card-elevated col-span-4">
|
||||
<CardHeader className="flex flex-row items-center justify-between p-3 pb-2">
|
||||
<CardTitle className="text-xs font-medium text-muted-foreground uppercase tracking-wide">Recent Activity</CardTitle>
|
||||
<Button variant="ghost" size="sm" className="h-5 px-2 text-xs" onClick={() => setTransactionDialogOpen(true)}>+</Button>
|
||||
<Button variant="ghost" size="sm" className="h-5 px-2 text-xs" onClick={() => setTransactionDialogOpen(true)}>
|
||||
+
|
||||
</Button>
|
||||
</CardHeader>
|
||||
<CardContent className="p-3 pt-0">
|
||||
<div className="space-y-2">
|
||||
@@ -117,7 +146,8 @@ export default function CashflowPage() {
|
||||
<p className="text-xs text-muted-foreground">{tx.date}</p>
|
||||
</div>
|
||||
<span className={`text-sm font-medium tabular-nums ${tx.type === 'income' ? 'text-green-400' : ''}`}>
|
||||
{tx.type === 'income' ? '+' : '−'}{fmt(tx.amount)}
|
||||
{tx.type === 'income' ? '+' : '−'}
|
||||
{fmt(tx.amount)}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
@@ -168,7 +198,10 @@ export default function CashflowPage() {
|
||||
<span className={`font-medium ${savingsRate >= 20 ? 'text-green-400' : ''}`}>{savingsRate.toFixed(1)}%</span>
|
||||
</div>
|
||||
<div className="h-2 rounded-full bg-foreground/10 overflow-hidden">
|
||||
<div className={`h-full rounded-full ${savingsRate >= 20 ? 'bg-green-400/50' : 'bg-foreground/30'}`} style={{width: `${Math.min(savingsRate, 100)}%`}} />
|
||||
<div
|
||||
className={`h-full rounded-full ${savingsRate >= 20 ? 'bg-green-400/50' : 'bg-foreground/30'}`}
|
||||
style={{width: `${Math.min(savingsRate, 100)}%`}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
Reference in New Issue
Block a user