@@ -167,7 +179,9 @@ export default function AccountManagement({ accounts, onAccountAdd, onAccountUpd
-
${account.balance.toFixed(2)}
+
+ ${account.balance.toFixed(2)}
+
{account.isActive ? 'Active' : 'Inactive'}
diff --git a/src/components/DashboardCharts.tsx b/src/components/DashboardCharts.tsx
index 6fa6083..19ddc61 100644
--- a/src/components/DashboardCharts.tsx
+++ b/src/components/DashboardCharts.tsx
@@ -3,6 +3,7 @@
interface Account {
id: string;
name: string;
+ type: 'checking' | 'savings' | 'credit_card' | 'mortgage' | 'investment' | 'loan';
balance: number;
color: string;
}
@@ -26,9 +27,33 @@ interface DashboardChartsProps {
accounts: Account[];
envelopes: Envelope[];
transactions: Transaction[];
+ visibleCharts?: {
+ incomeExpenses: boolean;
+ budgetAlerts: boolean;
+ assetsDebt: boolean;
+ envelopeSpending: boolean;
+ accountBalances: boolean;
+ dailySpending: boolean;
+ };
}
-export default function DashboardCharts({ accounts, envelopes, transactions }: DashboardChartsProps) {
+const assetTypes: Account['type'][] = ['checking', 'savings', 'investment'];
+const debtTypes: Account['type'][] = ['credit_card', 'mortgage', 'loan'];
+
+export default function DashboardCharts({ accounts, envelopes, transactions, visibleCharts = {
+ incomeExpenses: true,
+ budgetAlerts: true,
+ assetsDebt: true,
+ envelopeSpending: true,
+ accountBalances: true,
+ dailySpending: true,
+} }: DashboardChartsProps) {
+ // Separate accounts into assets and debt
+ const assetAccounts = accounts.filter(acc => assetTypes.includes(acc.type));
+ const debtAccounts = accounts.filter(acc => debtTypes.includes(acc.type));
+ const totalAssets = assetAccounts.reduce((sum, acc) => sum + acc.balance, 0);
+ const totalDebt = Math.abs(debtAccounts.reduce((sum, acc) => sum + acc.balance, 0));
+
// Calculate spending by envelope
const envelopeSpending = envelopes.map(env => ({
name: env.name,
@@ -38,6 +63,16 @@ export default function DashboardCharts({ accounts, envelopes, transactions }: D
percentage: env.allocated > 0 ? (Math.abs(env.spent) / env.allocated) * 100 : 0
})).sort((a, b) => b.spent - a.spent);
+ // Find envelopes with alerts (overspent or near limit >80%)
+ const envelopeAlerts = envelopes.filter(env => {
+ const percentage = env.allocated > 0 ? (Math.abs(env.spent) / env.allocated) * 100 : 0;
+ return percentage >= 80;
+ }).sort((a, b) => {
+ const aPerc = a.allocated > 0 ? (Math.abs(a.spent) / a.allocated) * 100 : 0;
+ const bPerc = b.allocated > 0 ? (Math.abs(b.spent) / b.allocated) * 100 : 0;
+ return bPerc - aPerc;
+ });
+
// Calculate total balance across accounts
const totalBalance = accounts.reduce((sum, acc) => sum + acc.balance, 0);
const accountBalances = accounts.map(acc => ({
@@ -47,8 +82,27 @@ export default function DashboardCharts({ accounts, envelopes, transactions }: D
percentage: totalBalance > 0 ? (acc.balance / totalBalance) * 100 : 0
}));
- // Calculate spending over time (last 30 days)
+ // Calculate income vs expenses (this month)
const now = new Date();
+ const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
+ const monthEnd = new Date(now.getFullYear(), now.getMonth() + 1, 0);
+
+ const monthTransactions = transactions.filter(t => {
+ const txDate = t.date instanceof Date ? t.date : new Date(t.date);
+ return txDate >= monthStart && txDate <= monthEnd;
+ });
+
+ const totalIncome = monthTransactions
+ .filter(t => t.amount > 0 && !t.envelopeId)
+ .reduce((sum, t) => sum + t.amount, 0);
+
+ const totalExpenses = monthTransactions
+ .filter(t => t.amount < 0)
+ .reduce((sum, t) => sum + Math.abs(t.amount), 0);
+
+ const netIncome = totalIncome - totalExpenses;
+
+ // Calculate spending over time (last 30 days)
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
const recentTransactions = transactions.filter(t => {
@@ -72,8 +126,112 @@ export default function DashboardCharts({ accounts, envelopes, transactions }: D
const maxDailySpending = Math.max(...spendingData.map(([_, amount]) => amount), 1);
return (
-
+
+ {/* Income vs Expenses Card */}
+ {visibleCharts.incomeExpenses && (
+
+
Income vs Expenses (This Month)
+
+
+ Income
+ ${totalIncome.toFixed(2)}
+
+
+ Expenses
+ ${totalExpenses.toFixed(2)}
+
+
+
+ Net Income
+ = 0 ? 'text-green-600' : 'text-red-600'}`}>
+ ${netIncome.toFixed(2)}
+
+
+
+
+
+ )}
+
+ {/* Budget Alerts Card */}
+ {visibleCharts.budgetAlerts && (
+
+
Budget Alerts
+ {envelopeAlerts.length > 0 ? (
+
+ {envelopeAlerts.slice(0, 5).map((env) => {
+ const percentage = env.allocated > 0 ? (Math.abs(env.spent) / env.allocated) * 100 : 0;
+ const isOverspent = percentage > 100;
+ return (
+
+
+
+
+ {env.name}
+
+
+ {isOverspent
+ ? `Over budget by $${(Math.abs(env.spent) - env.allocated).toFixed(2)}`
+ : `${percentage.toFixed(0)}% of budget used`}
+
+
+
+ {percentage.toFixed(0)}%
+
+
+
+ );
+ })}
+
+ ) : (
+
✓ All envelopes are within budget
+ )}
+
+ )}
+
+ {/* Assets & Debt Summary */}
+ {visibleCharts.assetsDebt && (
+
+
Assets vs Debt
+
+
+
+ Total Assets
+ ${totalAssets.toFixed(2)}
+
+
+ {assetAccounts.map(acc => acc.name).join(', ') || 'None'}
+
+
+
+
+ Total Debt
+ ${totalDebt.toFixed(2)}
+
+
+ {debtAccounts.map(acc => acc.name).join(', ') || 'None'}
+
+
+
+
+ Net Worth
+ = 0 ? 'text-green-600' : 'text-red-600'}`}>
+ ${(totalAssets - totalDebt).toFixed(2)}
+
+
+
+
+
+ )}
+
{/* Envelope Spending Chart */}
+ {visibleCharts.envelopeSpending && (
Envelope Spending
{envelopeSpending.length > 0 ? (
@@ -104,8 +262,10 @@ export default function DashboardCharts({ accounts, envelopes, transactions }: D
No envelope spending data yet.
)}
+ )}
{/* Account Balances Chart */}
+ {visibleCharts.accountBalances && (
Account Balances
{accountBalances.length > 0 ? (
@@ -139,8 +299,10 @@ export default function DashboardCharts({ accounts, envelopes, transactions }: D
No account data yet.
)}
+ )}
{/* Daily Spending Chart (Last 7 Days) */}
+ {visibleCharts.dailySpending && (
Daily Spending (Last 7 Days)
{spendingData.length > 0 ? (
@@ -172,6 +334,7 @@ export default function DashboardCharts({ accounts, envelopes, transactions }: D
No spending data for the last 7 days.
)}
+ )}
);
}
diff --git a/src/components/GetPaid.tsx b/src/components/GetPaid.tsx
index d9583a1..d3dd2ae 100644
--- a/src/components/GetPaid.tsx
+++ b/src/components/GetPaid.tsx
@@ -364,18 +364,11 @@ export default function GetPaid({
required
>
- {accounts
- .filter(
- (account) =>
- account.type !== 'credit_card' &&
- account.type !== 'mortgage' &&
- account.type !== 'loan',
- )
- .map((account) => (
-
- ))}
+ {accounts.map((account) => (
+
+ ))}
@@ -502,6 +495,12 @@ export default function GetPaid({
>
)}
+ {selectedAccountId && accountEnvelopes.length === 0 && (
+
+ No envelopes are linked to this account. Create envelopes for this account to distribute income here.
+
+ )}
+
-
+