Add projected net worth to crossover point report (#6384)

This commit is contained in:
scojo
2025-12-13 11:26:15 -08:00
committed by GitHub
parent 2d4b834fe8
commit 7648446bbf
5 changed files with 53 additions and 0 deletions

View File

@@ -27,6 +27,7 @@ type CrossoverGraphProps = {
x: string; x: string;
investmentIncome: number; investmentIncome: number;
expenses: number; expenses: number;
nestEgg: number;
isProjection?: boolean; isProjection?: boolean;
}>; }>;
start: string; start: string;
@@ -60,6 +61,7 @@ export function CrossoverGraph({
x: string; x: string;
investmentIncome: number | string; investmentIncome: number | string;
expenses: number | string; expenses: number | string;
nestEgg: number | string;
isProjection?: boolean; isProjection?: boolean;
}; };
}; };
@@ -118,6 +120,21 @@ export function CrossoverGraph({
</div> </div>
<div>{format(payload[0].payload.expenses, 'financial')}</div> <div>{format(payload[0].payload.expenses, 'financial')}</div>
</View> </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> </div>
</div> </div>

View File

@@ -57,6 +57,7 @@ type CrossoverData = {
x: string; x: string;
investmentIncome: number; investmentIncome: number;
expenses: number; expenses: number;
nestEgg: number;
isProjection?: boolean; isProjection?: boolean;
}>; }>;
start: string; start: string;
@@ -69,6 +70,7 @@ type CrossoverData = {
historicalReturn: number | null; historicalReturn: number | null;
yearsToRetire: number | null; yearsToRetire: number | null;
targetMonthlyIncome: number | null; targetMonthlyIncome: number | null;
targetNestEgg: number | null;
}; };
export function Crossover() { export function Crossover() {
@@ -299,6 +301,9 @@ function CrossoverInner({ widget }: CrossoverInnerProps) {
// Get target monthly income from spreadsheet data // Get target monthly income from spreadsheet data
const targetMonthlyIncome = data?.targetMonthlyIncome ?? null; const targetMonthlyIncome = data?.targetMonthlyIncome ?? null;
// Get target nest egg from spreadsheet data
const targetNestEgg = data?.targetNestEgg ?? null;
const navigate = useNavigate(); const navigate = useNavigate();
const { isNarrowWidth } = useResponsive(); const { isNarrowWidth } = useResponsive();
@@ -791,6 +796,20 @@ function CrossoverInner({ widget }: CrossoverInnerProps) {
</PrivacyFilter> </PrivacyFilter>
</span> </span>
</View> </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>
</View> </View>

View File

@@ -32,6 +32,7 @@ type CrossoverData = {
x: string; x: string;
investmentIncome: number; investmentIncome: number;
expenses: number; expenses: number;
nestEgg: number;
isProjection?: boolean; isProjection?: boolean;
}>; }>;
start: string; start: string;
@@ -44,6 +45,7 @@ type CrossoverData = {
historicalReturn: number | null; historicalReturn: number | null;
yearsToRetire: number | null; yearsToRetire: number | null;
targetMonthlyIncome: number | null; targetMonthlyIncome: number | null;
targetNestEgg: number | null;
}; };
type CrossoverCardProps = { type CrossoverCardProps = {

View File

@@ -80,6 +80,7 @@ export function createCrossoverSpreadsheet({
historicalReturn: null, historicalReturn: null,
yearsToRetire: null, yearsToRetire: null,
targetMonthlyIncome: null, targetMonthlyIncome: null,
targetNestEgg: null,
}); });
return; return;
} }
@@ -231,6 +232,7 @@ function recalculate(
x: string; x: string;
investmentIncome: number; investmentIncome: number;
expenses: number; expenses: number;
nestEgg: number;
isProjection?: boolean; isProjection?: boolean;
}> = []; }> = [];
@@ -245,6 +247,7 @@ function recalculate(
x: d.format(d.parseISO(month + '-01'), 'MMM yyyy'), x: d.format(d.parseISO(month + '-01'), 'MMM yyyy'),
investmentIncome: Math.round(monthlyIncome), investmentIncome: Math.round(monthlyIncome),
expenses: spend, expenses: spend,
nestEgg: balance,
}); });
lastBalance = balance; lastBalance = balance;
lastExpense = spend; lastExpense = spend;
@@ -355,6 +358,7 @@ function recalculate(
x: d.format(monthCursor, 'MMM yyyy'), x: d.format(monthCursor, 'MMM yyyy'),
investmentIncome: Math.round(projectedIncome), investmentIncome: Math.round(projectedIncome),
expenses: Math.round(projectedExpenses), expenses: Math.round(projectedExpenses),
nestEgg: Math.round(projectedBalance),
isProjection: true, isProjection: true,
}); });
@@ -370,6 +374,7 @@ function recalculate(
// Calculate years to retire based on crossover point // Calculate years to retire based on crossover point
let yearsToRetire: number | null = null; let yearsToRetire: number | null = null;
let targetMonthlyIncome: number | null = null; let targetMonthlyIncome: number | null = null;
let targetNestEgg: number | null = null;
if (crossoverIndex != null && crossoverIndex < data.length) { if (crossoverIndex != null && crossoverIndex < data.length) {
const crossoverData = data[crossoverIndex]; const crossoverData = data[crossoverIndex];
@@ -379,6 +384,8 @@ function recalculate(
const monthsDiff = d.differenceInMonths(crossoverDate, currentDate); const monthsDiff = d.differenceInMonths(crossoverDate, currentDate);
yearsToRetire = monthsDiff > 0 ? monthsDiff / 12 : 0; yearsToRetire = monthsDiff > 0 ? monthsDiff / 12 : 0;
targetMonthlyIncome = crossoverData.expenses; 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, yearsToRetire,
// Target monthly income at crossover point // Target monthly income at crossover point
targetMonthlyIncome, targetMonthlyIncome,
// Target nest egg at crossover point
targetNestEgg,
}; };
} }

View File

@@ -0,0 +1,6 @@
---
category: Enhancements
authors: [sjones512]
---
Add a nest egg field to show projected net worth on the crossover point report