export function homeAffordabilityCalculator(form: FormTs) {
form.addRow(row => {
row.addTextPanel('header', {
computedValue: () => 'Home Affordability Calculator',
customStyles: { 'font-size': '1.5rem', 'font-weight': '600', 'color': '#1e293b' }
});
});
form.addSpacer({ height: 20 });
// Income Section
const incomeSection = form.addSubform('income', { title: '💰 Your Income' });
incomeSection.addRow(row => {
row.addMoney('annualIncome', {
label: 'Annual Gross Income',
min: 0,
max: 10000000,
defaultValue: 75000,
isRequired: true,
tooltip: 'Your total yearly income before taxes'
}, '1fr');
row.addMoney('spouseIncome', {
label: 'Spouse/Co-borrower Income',
min: 0,
max: 10000000,
defaultValue: 0,
tooltip: 'Annual income of co-borrower if applicable'
}, '1fr');
});
incomeSection.addRow(row => {
row.addMoney('otherIncome', {
label: 'Other Annual Income',
min: 0,
max: 1000000,
defaultValue: 0,
tooltip: 'Bonuses, rental income, investments, etc.'
}, '1fr');
row.addMoney('monthlyDebts', {
label: 'Monthly Debt Payments',
min: 0,
max: 50000,
defaultValue: 500,
tooltip: 'Car loans, student loans, credit cards, etc.'
}, '1fr');
});
// Savings Section
const savingsSection = form.addSubform('savings', { title: '🏦 Your Savings' });
savingsSection.addRow(row => {
row.addMoney('downPayment', {
label: 'Available Down Payment',
min: 0,
max: 5000000,
defaultValue: 50000,
isRequired: true,
tooltip: 'Cash available for down payment'
}, '1fr');
row.addDropdown('downPaymentPercent', {
label: 'Target Down Payment %',
options: [
{ id: '3', name: '3% (FHA minimum)' },
{ id: '5', name: '5%' },
{ id: '10', name: '10%' },
{ id: '20', name: '20% (Avoid PMI)' },
{ id: '25', name: '25%' },
{ id: '30', name: '30%+' }
],
defaultValue: '20',
tooltip: 'Higher down payment = lower monthly payment'
}, '1fr');
});
savingsSection.addRow(row => {
row.addMoney('closingCosts', {
label: 'Closing Costs Reserve',
min: 0,
max: 100000,
defaultValue: 10000,
tooltip: 'Typically 2-5% of home price'
}, '1fr');
row.addMoney('emergencyFund', {
label: 'Emergency Fund (keep)',
min: 0,
max: 500000,
defaultValue: 15000,
tooltip: 'Amount to keep in savings after purchase'
}, '1fr');
});
// Loan Details Section
const loanSection = form.addSubform('loan', { title: '📋 Loan Details' });
loanSection.addRow(row => {
row.addDropdown('loanType', {
label: 'Loan Type',
options: [
{ id: 'conventional', name: 'Conventional' },
{ id: 'fha', name: 'FHA' },
{ id: 'va', name: 'VA' },
{ id: 'usda', name: 'USDA' },
{ id: 'jumbo', name: 'Jumbo' }
],
defaultValue: 'conventional',
isRequired: true
}, '1fr');
row.addDropdown('loanTerm', {
label: 'Loan Term',
options: [
{ id: '15', name: '15 years' },
{ id: '20', name: '20 years' },
{ id: '30', name: '30 years' }
],
defaultValue: '30',
isRequired: true
}, '1fr');
});
loanSection.addRow(row => {
row.addDecimal('interestRate', {
label: 'Interest Rate (%)',
min: 0.5,
max: 15,
step: 0.125,
defaultValue: 6.5,
isRequired: true,
tooltip: 'Current mortgage rates are typically 6-7%'
}, '1fr');
row.addDropdown('creditScore', {
label: 'Credit Score Range',
options: [
{ id: 'excellent', name: 'Excellent (740+)' },
{ id: 'good', name: 'Good (700-739)' },
{ id: 'fair', name: 'Fair (660-699)' },
{ id: 'poor', name: 'Poor (620-659)' },
{ id: 'very-poor', name: 'Below 620' }
],
defaultValue: 'good',
tooltip: 'Credit score affects rate and loan options'
}, '1fr');
});
// Housing Costs Section
const costsSection = form.addSubform('costs', { title: '🏠 Housing Costs' });
costsSection.addRow(row => {
row.addDecimal('propertyTaxRate', {
label: 'Property Tax Rate (%)',
min: 0,
max: 5,
step: 0.1,
defaultValue: 1.2,
tooltip: 'Annual property tax as % of home value'
}, '1fr');
row.addMoney('monthlyHOA', {
label: 'Monthly HOA Fees',
min: 0,
max: 2000,
defaultValue: 0,
tooltip: 'Homeowners association fees if applicable'
}, '1fr');
});
costsSection.addRow(row => {
row.addMoney('annualInsurance', {
label: 'Annual Home Insurance',
min: 0,
max: 20000,
defaultValue: 1500,
tooltip: 'Typical range: $1,000-3,000/year'
}, '1fr');
row.addDropdown('pmiRequired', {
label: 'PMI (if <20% down)',
options: [
{ id: 'yes', name: 'Include PMI estimate' },
{ id: 'no', name: 'No PMI (20%+ down or VA/USDA)' }
],
defaultValue: 'yes'
}, '1fr');
});
// DTI Preferences Section
const dtiSection = form.addSubform('dti', { title: '📊 Affordability Settings' });
dtiSection.addRow(row => {
row.addDropdown('maxDTI', {
label: 'Max Debt-to-Income Ratio',
options: [
{ id: '28', name: 'Conservative (28%)' },
{ id: '36', name: 'Standard (36%)' },
{ id: '43', name: 'FHA Maximum (43%)' },
{ id: '50', name: 'VA Maximum (50%)' }
],
defaultValue: '36',
tooltip: 'Total debt payments / gross income'
}, '1fr');
row.addDropdown('maxHousingRatio', {
label: 'Max Housing Ratio',
options: [
{ id: '25', name: 'Conservative (25%)' },
{ id: '28', name: 'Standard (28%)' },
{ id: '31', name: 'FHA (31%)' },
{ id: '35', name: 'Stretch (35%)' }
],
defaultValue: '28',
tooltip: 'Housing payment / gross income'
}, '1fr');
});
form.addSpacer({ height: 20, showLine: true, lineStyle: 'dashed' });
// Affordability Results Section
const resultsSection = form.addSubform('results', { title: '🎯 What You Can Afford', isCollapsible: false });
resultsSection.addRow(row => {
row.addPriceDisplay('maxHomePrice', {
label: 'Maximum Home Price',
computedValue: () => {
const annualIncome = incomeSection.money('annualIncome')?.value() || 75000;
const spouseIncome = incomeSection.money('spouseIncome')?.value() || 0;
const otherIncome = incomeSection.money('otherIncome')?.value() || 0;
const monthlyDebts = incomeSection.money('monthlyDebts')?.value() || 500;
const downPayment = savingsSection.money('downPayment')?.value() || 50000;
const closingCostsReserve = savingsSection.money('closingCosts')?.value() || 10000;
const emergencyFund = savingsSection.money('emergencyFund')?.value() || 15000;
const downPaymentPercent = parseFloat(savingsSection.dropdown('downPaymentPercent')?.value() || '20') / 100;
const interestRate = (loanSection.decimal('interestRate')?.value() || 6.5) / 100 / 12;
const loanTerm = parseInt(loanSection.dropdown('loanTerm')?.value() || '30') * 12;
const propertyTaxRate = (costsSection.decimal('propertyTaxRate')?.value() || 1.2) / 100 / 12;
const monthlyHOA = costsSection.money('monthlyHOA')?.value() || 0;
const annualInsurance = costsSection.money('annualInsurance')?.value() || 1500;
const monthlyInsurance = annualInsurance / 12;
const maxDTI = parseFloat(dtiSection.dropdown('maxDTI')?.value() || '36') / 100;
const maxHousingRatio = parseFloat(dtiSection.dropdown('maxHousingRatio')?.value() || '28') / 100;
const totalMonthlyIncome = (annualIncome + spouseIncome + otherIncome) / 12;
// Calculate max payment based on DTI
const maxTotalDebt = totalMonthlyIncome * maxDTI;
const maxHousingFromDTI = maxTotalDebt - monthlyDebts;
// Calculate max payment based on housing ratio
const maxHousingFromRatio = totalMonthlyIncome * maxHousingRatio;
// Use lower of the two
const maxHousingPayment = Math.min(maxHousingFromDTI, maxHousingFromRatio);
// Back-calculate home price from payment
// P&I = maxPayment - taxes - insurance - HOA - PMI
// We'll iterate to find the right price since taxes and PMI depend on price
let homePrice = 100000;
for (let i = 0; i < 20; i++) {
const loanAmount = homePrice * (1 - downPaymentPercent);
// Monthly P&I
const monthlyPI = loanAmount * (interestRate * Math.pow(1 + interestRate, loanTerm)) /
(Math.pow(1 + interestRate, loanTerm) - 1);
// Monthly property tax
const monthlyTax = homePrice * propertyTaxRate;
// PMI (roughly 0.5-1% annually if down < 20%)
let monthlyPMI = 0;
if (downPaymentPercent < 0.2 && costsSection.dropdown('pmiRequired')?.value() === 'yes') {
monthlyPMI = (loanAmount * 0.007) / 12;
}
const totalPayment = monthlyPI + monthlyTax + monthlyInsurance + monthlyHOA + monthlyPMI;
if (Math.abs(totalPayment - maxHousingPayment) < 10) break;
// Adjust home price
homePrice = homePrice * (maxHousingPayment / totalPayment);
}
// Also check against available down payment
const availableForDown = downPayment - closingCostsReserve - emergencyFund;
const maxFromSavings = availableForDown / downPaymentPercent;
return Math.round(Math.min(homePrice, maxFromSavings));
},
variant: 'large'
}, '1fr');
row.addPriceDisplay('recommendedPrice', {
label: 'Comfortable Price (Conservative)',
computedValue: () => {
const annualIncome = incomeSection.money('annualIncome')?.value() || 75000;
const spouseIncome = incomeSection.money('spouseIncome')?.value() || 0;
const otherIncome = incomeSection.money('otherIncome')?.value() || 0;
const monthlyDebts = incomeSection.money('monthlyDebts')?.value() || 500;
const downPayment = savingsSection.money('downPayment')?.value() || 50000;
const closingCostsReserve = savingsSection.money('closingCosts')?.value() || 10000;
const emergencyFund = savingsSection.money('emergencyFund')?.value() || 15000;
const downPaymentPercent = parseFloat(savingsSection.dropdown('downPaymentPercent')?.value() || '20') / 100;
const interestRate = (loanSection.decimal('interestRate')?.value() || 6.5) / 100 / 12;
const loanTerm = parseInt(loanSection.dropdown('loanTerm')?.value() || '30') * 12;
const propertyTaxRate = (costsSection.decimal('propertyTaxRate')?.value() || 1.2) / 100 / 12;
const monthlyHOA = costsSection.money('monthlyHOA')?.value() || 0;
const annualInsurance = costsSection.money('annualInsurance')?.value() || 1500;
const monthlyInsurance = annualInsurance / 12;
const totalMonthlyIncome = (annualIncome + spouseIncome + otherIncome) / 12;
// Conservative: 25% of income for housing
const maxHousingPayment = totalMonthlyIncome * 0.25;
let homePrice = 100000;
for (let i = 0; i < 20; i++) {
const loanAmount = homePrice * (1 - downPaymentPercent);
const monthlyPI = loanAmount * (interestRate * Math.pow(1 + interestRate, loanTerm)) /
(Math.pow(1 + interestRate, loanTerm) - 1);
const monthlyTax = homePrice * propertyTaxRate;
let monthlyPMI = 0;
if (downPaymentPercent < 0.2 && costsSection.dropdown('pmiRequired')?.value() === 'yes') {
monthlyPMI = (loanAmount * 0.007) / 12;
}
const totalPayment = monthlyPI + monthlyTax + monthlyInsurance + monthlyHOA + monthlyPMI;
if (Math.abs(totalPayment - maxHousingPayment) < 10) break;
homePrice = homePrice * (maxHousingPayment / totalPayment);
}
const availableForDown = downPayment - closingCostsReserve - emergencyFund;
const maxFromSavings = availableForDown / downPaymentPercent;
return Math.round(Math.min(homePrice, maxFromSavings));
},
variant: 'large'
}, '1fr');
});
// Monthly Payment Breakdown Section
const paymentSection = form.addSubform('payment', { title: '📅 Monthly Payment Estimate', isCollapsible: false });
paymentSection.addRow(row => {
row.addPriceDisplay('monthlyPI', {
label: 'Principal & Interest',
computedValue: () => {
const annualIncome = incomeSection.money('annualIncome')?.value() || 75000;
const spouseIncome = incomeSection.money('spouseIncome')?.value() || 0;
const otherIncome = incomeSection.money('otherIncome')?.value() || 0;
const downPaymentPercent = parseFloat(savingsSection.dropdown('downPaymentPercent')?.value() || '20') / 100;
const interestRate = (loanSection.decimal('interestRate')?.value() || 6.5) / 100 / 12;
const loanTerm = parseInt(loanSection.dropdown('loanTerm')?.value() || '30') * 12;
const maxHousingRatio = parseFloat(dtiSection.dropdown('maxHousingRatio')?.value() || '28') / 100;
const totalMonthlyIncome = (annualIncome + spouseIncome + otherIncome) / 12;
const maxHousingPayment = totalMonthlyIncome * maxHousingRatio;
// Simplified home price estimate
const homePrice = maxHousingPayment * 150; // rough estimate
const loanAmount = homePrice * (1 - downPaymentPercent);
const monthlyPI = loanAmount * (interestRate * Math.pow(1 + interestRate, loanTerm)) /
(Math.pow(1 + interestRate, loanTerm) - 1);
return Math.round(monthlyPI);
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('monthlyTax', {
label: 'Property Tax',
computedValue: () => {
const annualIncome = incomeSection.money('annualIncome')?.value() || 75000;
const spouseIncome = incomeSection.money('spouseIncome')?.value() || 0;
const otherIncome = incomeSection.money('otherIncome')?.value() || 0;
const maxHousingRatio = parseFloat(dtiSection.dropdown('maxHousingRatio')?.value() || '28') / 100;
const propertyTaxRate = (costsSection.decimal('propertyTaxRate')?.value() || 1.2) / 100 / 12;
const totalMonthlyIncome = (annualIncome + spouseIncome + otherIncome) / 12;
const maxHousingPayment = totalMonthlyIncome * maxHousingRatio;
const homePrice = maxHousingPayment * 150;
return Math.round(homePrice * propertyTaxRate);
},
variant: 'default'
}, '1fr');
});
paymentSection.addRow(row => {
row.addPriceDisplay('monthlyInsurance', {
label: 'Home Insurance',
computedValue: () => {
const annualInsurance = costsSection.money('annualInsurance')?.value() || 1500;
return Math.round(annualInsurance / 12);
},
variant: 'default'
}, '1fr');
row.addPriceDisplay('monthlyPMI', {
label: 'PMI (if applicable)',
computedValue: () => {
const downPaymentPercent = parseFloat(savingsSection.dropdown('downPaymentPercent')?.value() || '20') / 100;
const annualIncome = incomeSection.money('annualIncome')?.value() || 75000;
const spouseIncome = incomeSection.money('spouseIncome')?.value() || 0;
const otherIncome = incomeSection.money('otherIncome')?.value() || 0;
const maxHousingRatio = parseFloat(dtiSection.dropdown('maxHousingRatio')?.value() || '28') / 100;
if (downPaymentPercent >= 0.2 || costsSection.dropdown('pmiRequired')?.value() === 'no') {
return 0;
}
const totalMonthlyIncome = (annualIncome + spouseIncome + otherIncome) / 12;
const maxHousingPayment = totalMonthlyIncome * maxHousingRatio;
const homePrice = maxHousingPayment * 150;
const loanAmount = homePrice * (1 - downPaymentPercent);
return Math.round((loanAmount * 0.007) / 12);
},
variant: 'default'
}, '1fr');
});
// Summary Section
const summarySection = form.addSubform('summary', {
title: '💵 Total Monthly Payment',
isCollapsible: false,
sticky: 'bottom'
});
summarySection.addRow(row => {
row.addPriceDisplay('totalMonthly', {
label: 'Est. Monthly Payment',
computedValue: () => {
const annualIncome = incomeSection.money('annualIncome')?.value() || 75000;
const spouseIncome = incomeSection.money('spouseIncome')?.value() || 0;
const otherIncome = incomeSection.money('otherIncome')?.value() || 0;
const maxHousingRatio = parseFloat(dtiSection.dropdown('maxHousingRatio')?.value() || '28') / 100;
const totalMonthlyIncome = (annualIncome + spouseIncome + otherIncome) / 12;
return Math.round(totalMonthlyIncome * maxHousingRatio);
},
variant: 'large'
});
});
summarySection.addRow(row => {
row.addTextPanel('disclaimer', {
computedValue: () => 'This is an estimate only. Actual affordability depends on credit score, debt, and lender requirements. Get pre-approved for accurate figures.',
customStyles: { 'font-size': '0.85rem', 'color': '#64748b', 'text-align': 'center' }
});
});
form.configureSubmitButton({
label: 'Get Pre-Approval Information'
});
}