Add interest income benefit calculator widget to hero
- New "✦ Calculate Your Interest Income Potential" button between hero CTAs with gradient border styling distinct from primary/ghost buttons - Modal overlay collects: homesites, property type, annual dues + frequency, reserve fund balance, and 2025 actual interest income - Conservative calculation model: 4.0% HYSA for operating cash, 4.25% CD ladder for 65% of investable reserves; operating multiplier varies by payment frequency (monthly 10%, quarterly 20%, annual 35%) - Results screen shows animated dollar counter, operating vs reserve breakdown, AI-style narrative recommendation, and direct CTA to signup - Modal closes on backdrop click or Escape key; CTA closes modal and scrolls to early access signup form Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
118
app.js
118
app.js
@@ -20,6 +20,124 @@
|
||||
if (signupEl) signupEl.textContent = text;
|
||||
})();
|
||||
|
||||
// ── Benefit Calculator ───────────────────────────────────
|
||||
(function initCalculator() {
|
||||
const overlay = document.getElementById('calcOverlay');
|
||||
const openBtn = document.getElementById('openCalc');
|
||||
const closeBtn = document.getElementById('calcClose');
|
||||
const submitBtn = document.getElementById('calcSubmit');
|
||||
const recalcBtn = document.getElementById('calcRecalc');
|
||||
const calcForm = document.getElementById('calcForm');
|
||||
const calcRes = document.getElementById('calcResults');
|
||||
const calcErr = document.getElementById('calcError');
|
||||
const ctaBtn = document.getElementById('calcCTABtn');
|
||||
|
||||
if (!overlay) return;
|
||||
|
||||
function open() { overlay.classList.add('open'); document.body.style.overflow = 'hidden'; }
|
||||
function close() { overlay.classList.remove('open'); document.body.style.overflow = ''; }
|
||||
|
||||
openBtn?.addEventListener('click', open);
|
||||
closeBtn?.addEventListener('click', close);
|
||||
overlay.addEventListener('click', e => { if (e.target === overlay) close(); });
|
||||
document.addEventListener('keydown', e => { if (e.key === 'Escape') close(); });
|
||||
|
||||
recalcBtn?.addEventListener('click', () => {
|
||||
calcRes.classList.add('hidden');
|
||||
calcForm.classList.remove('hidden');
|
||||
});
|
||||
|
||||
// Close modal and scroll to signup when CTA clicked
|
||||
ctaBtn?.addEventListener('click', () => {
|
||||
close();
|
||||
});
|
||||
|
||||
submitBtn?.addEventListener('click', () => {
|
||||
const homesites = parseFloat(document.getElementById('calcHomesites').value) || 0;
|
||||
const propertyType = document.getElementById('calcPropertyType').value;
|
||||
const annualIncome = parseFloat(document.getElementById('calcAnnualIncome').value) || 0;
|
||||
const paymentFreq = document.getElementById('calcPaymentFreq').value;
|
||||
const reserveFunds = parseFloat(document.getElementById('calcReserveFunds').value) || 0;
|
||||
const interest2025 = parseFloat(document.getElementById('calcInterest2025').value) || 0;
|
||||
|
||||
if (!homesites || !annualIncome) {
|
||||
calcErr.classList.remove('hidden');
|
||||
return;
|
||||
}
|
||||
calcErr.classList.add('hidden');
|
||||
|
||||
// ── Conservative investment assumptions ──
|
||||
// Operating cash: depending on payment frequency, portion investable in high-yield savings
|
||||
const opMultiplier = { monthly: 0.10, quarterly: 0.20, annually: 0.35 }[paymentFreq] || 0.10;
|
||||
const opRate = 0.040; // 4.0% money market / HYSA
|
||||
const resRatio = 0.65; // 65% of reserves investable (keep 35% liquid)
|
||||
const resRate = 0.0425; // 4.25% CD ladder / short-term treasuries
|
||||
|
||||
const investableOp = annualIncome * opMultiplier;
|
||||
const investableRes = reserveFunds * resRatio;
|
||||
const opInterest = Math.round(investableOp * opRate);
|
||||
const resInterest = Math.round(investableRes * resRate);
|
||||
const totalPotential = opInterest + resInterest;
|
||||
const increase = totalPotential - interest2025;
|
||||
const pctIncrease = interest2025 > 0
|
||||
? Math.round((increase / interest2025) * 100)
|
||||
: (totalPotential > 0 ? 100 : 0);
|
||||
|
||||
// ── Populate results ──
|
||||
const fmt = n => '$' + Math.round(n).toLocaleString();
|
||||
|
||||
document.getElementById('resultAmount').textContent = fmt(totalPotential);
|
||||
document.getElementById('resultCurrent').textContent = fmt(interest2025);
|
||||
document.getElementById('resultOperating').textContent = fmt(opInterest);
|
||||
document.getElementById('resultReserve').textContent = fmt(resInterest);
|
||||
|
||||
const badge = document.getElementById('resultBadge');
|
||||
if (increase > 0) {
|
||||
badge.textContent = `+${fmt(increase)} · +${pctIncrease}%`;
|
||||
badge.style.display = 'inline-block';
|
||||
} else {
|
||||
badge.style.display = 'none';
|
||||
}
|
||||
|
||||
// ── AI-style suggestion text ──
|
||||
const typeLabels = { sfh:'single-family home', townhomes:'townhome', condos:'condo', mixed:'mixed-use', '':'' };
|
||||
const typeLabel = typeLabels[propertyType] || '';
|
||||
const freqLabel = { monthly:'monthly', quarterly:'quarterly', annually:'annual' }[paymentFreq];
|
||||
const communityDesc = [homesites && `${homesites}-unit`, typeLabel, 'community'].filter(Boolean).join(' ');
|
||||
|
||||
let ai = `Based on your ${communityDesc} collecting ${fmt(annualIncome)} in ${freqLabel} dues`;
|
||||
if (reserveFunds > 0) ai += ` and ${fmt(reserveFunds)} in reserve funds`;
|
||||
ai += `, a conservative investment strategy could generate approximately ${fmt(totalPotential)} in annual interest income. `;
|
||||
if (resInterest > 0) ai += `Deploying ${fmt(investableRes)} of your reserve funds into a short-term CD ladder at ~4.25% yields ${fmt(resInterest)} annually. `;
|
||||
if (opInterest > 0) ai += `Keeping a ${fmt(investableOp)} operating cash buffer in a high-yield money market at ~4.0% adds another ${fmt(opInterest)}. `;
|
||||
if (interest2025 > 0 && increase > 0) {
|
||||
ai += `That's a ${fmt(increase)} improvement (+${pctIncrease}%) over your 2025 interest income of ${fmt(interest2025)} — with no additional risk.`;
|
||||
} else if (interest2025 === 0) {
|
||||
ai += `This would represent entirely new interest income for your community at no additional risk.`;
|
||||
}
|
||||
|
||||
document.getElementById('calcAiText').textContent = ai;
|
||||
|
||||
// ── Animate the main number ──
|
||||
animateValue(document.getElementById('resultAmount'), 0, totalPotential);
|
||||
|
||||
calcForm.classList.add('hidden');
|
||||
calcRes.classList.remove('hidden');
|
||||
});
|
||||
|
||||
function animateValue(el, from, to) {
|
||||
const duration = 900;
|
||||
const start = performance.now();
|
||||
function step(now) {
|
||||
const progress = Math.min((now - start) / duration, 1);
|
||||
const ease = 1 - Math.pow(1 - progress, 3);
|
||||
el.textContent = '$' + Math.round(from + (to - from) * ease).toLocaleString();
|
||||
if (progress < 1) requestAnimationFrame(step);
|
||||
}
|
||||
requestAnimationFrame(step);
|
||||
}
|
||||
})();
|
||||
|
||||
// ── Screenshot Carousel ──────────────────────────────────
|
||||
(function initCarousel() {
|
||||
const carousel = document.getElementById('screenshotCarousel');
|
||||
|
||||
Reference in New Issue
Block a user