mirror of
https://github.com/actualbudget/actual.git
synced 2026-03-11 17:47:26 -05:00
Add projected net worth to crossover point report (#6384)
This commit is contained in:
@@ -27,6 +27,7 @@ type CrossoverGraphProps = {
|
||||
x: string;
|
||||
investmentIncome: number;
|
||||
expenses: number;
|
||||
nestEgg: number;
|
||||
isProjection?: boolean;
|
||||
}>;
|
||||
start: string;
|
||||
@@ -60,6 +61,7 @@ export function CrossoverGraph({
|
||||
x: string;
|
||||
investmentIncome: number | string;
|
||||
expenses: number | string;
|
||||
nestEgg: number | string;
|
||||
isProjection?: boolean;
|
||||
};
|
||||
};
|
||||
@@ -118,6 +120,21 @@ export function CrossoverGraph({
|
||||
</div>
|
||||
<div>{format(payload[0].payload.expenses, 'financial')}</div>
|
||||
</View>
|
||||
<View
|
||||
className={css({
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
})}
|
||||
>
|
||||
<div>
|
||||
{payload[0].payload.isProjection ? (
|
||||
<Trans>Target Nest Egg:</Trans>
|
||||
) : (
|
||||
<Trans>Nest Egg:</Trans>
|
||||
)}
|
||||
</div>
|
||||
<div>{format(payload[0].payload.nestEgg, 'financial')}</div>
|
||||
</View>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -57,6 +57,7 @@ type CrossoverData = {
|
||||
x: string;
|
||||
investmentIncome: number;
|
||||
expenses: number;
|
||||
nestEgg: number;
|
||||
isProjection?: boolean;
|
||||
}>;
|
||||
start: string;
|
||||
@@ -69,6 +70,7 @@ type CrossoverData = {
|
||||
historicalReturn: number | null;
|
||||
yearsToRetire: number | null;
|
||||
targetMonthlyIncome: number | null;
|
||||
targetNestEgg: number | null;
|
||||
};
|
||||
|
||||
export function Crossover() {
|
||||
@@ -299,6 +301,9 @@ function CrossoverInner({ widget }: CrossoverInnerProps) {
|
||||
// Get target monthly income from spreadsheet data
|
||||
const targetMonthlyIncome = data?.targetMonthlyIncome ?? null;
|
||||
|
||||
// Get target nest egg from spreadsheet data
|
||||
const targetNestEgg = data?.targetNestEgg ?? null;
|
||||
|
||||
const navigate = useNavigate();
|
||||
const { isNarrowWidth } = useResponsive();
|
||||
|
||||
@@ -791,6 +796,20 @@ function CrossoverInner({ widget }: CrossoverInnerProps) {
|
||||
</PrivacyFilter>
|
||||
</span>
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
<span>
|
||||
<Trans>Target Nest Egg</Trans>:{' '}
|
||||
<PrivacyFilter>
|
||||
{targetNestEgg != null && !isNaN(targetNestEgg)
|
||||
? format(targetNestEgg, 'financial')
|
||||
: t('N/A')}
|
||||
</PrivacyFilter>
|
||||
</span>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ type CrossoverData = {
|
||||
x: string;
|
||||
investmentIncome: number;
|
||||
expenses: number;
|
||||
nestEgg: number;
|
||||
isProjection?: boolean;
|
||||
}>;
|
||||
start: string;
|
||||
@@ -44,6 +45,7 @@ type CrossoverData = {
|
||||
historicalReturn: number | null;
|
||||
yearsToRetire: number | null;
|
||||
targetMonthlyIncome: number | null;
|
||||
targetNestEgg: number | null;
|
||||
};
|
||||
|
||||
type CrossoverCardProps = {
|
||||
|
||||
@@ -80,6 +80,7 @@ export function createCrossoverSpreadsheet({
|
||||
historicalReturn: null,
|
||||
yearsToRetire: null,
|
||||
targetMonthlyIncome: null,
|
||||
targetNestEgg: null,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -231,6 +232,7 @@ function recalculate(
|
||||
x: string;
|
||||
investmentIncome: number;
|
||||
expenses: number;
|
||||
nestEgg: number;
|
||||
isProjection?: boolean;
|
||||
}> = [];
|
||||
|
||||
@@ -245,6 +247,7 @@ function recalculate(
|
||||
x: d.format(d.parseISO(month + '-01'), 'MMM yyyy'),
|
||||
investmentIncome: Math.round(monthlyIncome),
|
||||
expenses: spend,
|
||||
nestEgg: balance,
|
||||
});
|
||||
lastBalance = balance;
|
||||
lastExpense = spend;
|
||||
@@ -355,6 +358,7 @@ function recalculate(
|
||||
x: d.format(monthCursor, 'MMM yyyy'),
|
||||
investmentIncome: Math.round(projectedIncome),
|
||||
expenses: Math.round(projectedExpenses),
|
||||
nestEgg: Math.round(projectedBalance),
|
||||
isProjection: true,
|
||||
});
|
||||
|
||||
@@ -370,6 +374,7 @@ function recalculate(
|
||||
// Calculate years to retire based on crossover point
|
||||
let yearsToRetire: number | null = null;
|
||||
let targetMonthlyIncome: number | null = null;
|
||||
let targetNestEgg: number | null = null;
|
||||
|
||||
if (crossoverIndex != null && crossoverIndex < data.length) {
|
||||
const crossoverData = data[crossoverIndex];
|
||||
@@ -379,6 +384,8 @@ function recalculate(
|
||||
const monthsDiff = d.differenceInMonths(crossoverDate, currentDate);
|
||||
yearsToRetire = monthsDiff > 0 ? monthsDiff / 12 : 0;
|
||||
targetMonthlyIncome = crossoverData.expenses;
|
||||
// Calculate target nest egg: target monthly income / monthly safe withdrawal rate
|
||||
targetNestEgg = Math.round(targetMonthlyIncome / monthlySWR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,5 +412,7 @@ function recalculate(
|
||||
yearsToRetire,
|
||||
// Target monthly income at crossover point
|
||||
targetMonthlyIncome,
|
||||
// Target nest egg at crossover point
|
||||
targetNestEgg,
|
||||
};
|
||||
}
|
||||
|
||||
6
upcoming-release-notes/6384.md
Normal file
6
upcoming-release-notes/6384.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: Enhancements
|
||||
authors: [sjones512]
|
||||
---
|
||||
|
||||
Add a nest egg field to show projected net worth on the crossover point report
|
||||
Reference in New Issue
Block a user