Membership Pricing Calculator
Select your plan and options to see your custom price.
1. Choose Your Plan
2. Select Billing Cycle
Monthly
Annually (Save 17%)
3. Number of Users
4. Optional Add-ons
Quote Summary
Total
per month
$0.00
${formatCurrency(tier.price)}/user/mo
-
${tier.features.map(f => `
- - ${f} `).join('')}
${label}${value}
`;
};
addSummaryLine(`${data.selectedTier.name} Plan (${data.userCount} users)`, formatCurrency(data.baseTierCost) + '/mo');
if (data.selectedAddons.length > 0) {
data.selectedAddons.forEach(addon => {
addSummaryLine(`- ${addon.name}`, `+${formatCurrency(addon.price)}/mo`);
});
}
addSummaryLine('Subtotal (Monthly)', formatCurrency(data.totalMonthlyCost), 'pt-2 border-t border-cyan-600');
if (data.isAnnual) {
addSummaryLine('Annual Discount', `-${formatCurrency(data.annualDiscount / 12)}/mo`);
}
// Update total display
if (data.isAnnual) {
totalBillingCycleText.textContent = 'per year';
summaryTotal.textContent = formatCurrency(data.totalMonthlyCost * 12 - data.annualDiscount);
} else {
totalBillingCycleText.textContent = 'per month';
summaryTotal.textContent = formatCurrency(data.totalMonthlyCost);
}
}
// --- PDF GENERATION ---
function downloadPDF() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF('p', 'mm', 'a4');
const data = calculatePrice();
const date = new Date().toLocaleString('en-US');
doc.setFillColor(14, 116, 144); // Cyan 700
doc.rect(0, 0, doc.internal.pageSize.getWidth(), 30, 'F');
doc.setFont('helvetica', 'bold');
doc.setFontSize(22);
doc.setTextColor(255, 255, 255);
doc.text("Membership Price Quote", 15, 18);
const tableBody = [
[`${data.selectedTier.name} Plan (${data.userCount} Users)`, formatCurrency(data.baseTierCost) + '/mo']
];
data.selectedAddons.forEach(addon => {
tableBody.push([`Add-on: ${addon.name}`, `+${formatCurrency(addon.price)}/mo`]);
});
tableBody.push([{ content: 'Subtotal (per month)', styles: { fontStyle: 'bold' } }, { content: formatCurrency(data.totalMonthlyCost), styles: { fontStyle: 'bold' } }]);
if (data.isAnnual) {
tableBody.push(['Annual Billing Discount', `-${formatCurrency(data.annualDiscount)}/yr`]);
}
const totalLabel = data.isAnnual ? 'Total (per year)' : 'Total (per month)';
const totalValue = data.isAnnual ? formatCurrency(data.totalMonthlyCost * 12 - data.annualDiscount) : formatCurrency(data.totalMonthlyCost);
doc.autoTable({
startY: 40,
head: [['Item', 'Cost']],
body: tableBody,
theme: 'grid',
headStyles: { fillColor: [6, 182, 212] }, // Cyan 500
});
let finalY = doc.autoTable.previous.finalY;
doc.setFontSize(14);
doc.setFont('helvetica', 'bold');
doc.text(totalLabel, 15, finalY + 15);
doc.text(totalValue, doc.internal.pageSize.getWidth() - 15, finalY + 15, { align: 'right' });
doc.setFontSize(10);
doc.setTextColor(150);
doc.text(`Quote generated on: ${date}`, 15, doc.internal.pageSize.getHeight() - 10);
doc.save('membership_quote.pdf');
}
// --- EVENT LISTENERS ---
function addEventListeners() {
tierSelection.addEventListener('change', updateSummary);
addonsSelection.addEventListener('change', updateSummary);
billingCycleToggle.addEventListener('change', updateSummary);
userSlider.addEventListener('input', () => {
userCountInput.value = userSlider.value;
updateSummary();
});
userCountInput.addEventListener('input', () => {
userSlider.value = userCountInput.value;
updateSummary();
});
pdfButton.addEventListener('click', downloadPDF);
}
// --- INITIALIZATION ---
function initialize() {
renderTiers();
renderAddons();
addEventListeners();
updateSummary(); // Initial calculation
}
initialize();
});
