fixes to the calculator

This commit is contained in:
2026-10-20 08:32:39 -06:00
parent a9cccf4226
commit 99bf23ecf1
15 changed files with 155 additions and 116 deletions
+13 -9
View File
@@ -1,19 +1,20 @@
{{/*
The savings calculator: pick the apps you pay for today and your team
size, and compare their yearly retail cost with Federated's annual price.
Input: dict with "key" (unique id), "apps" (name, cost, perSeat, selected),
"annual", optional "note", "compact" (one result, no cost breakdown) and
size, and compare their yearly retail cost with the smallest Federated plan
that replaces every app picked (the highest `tier` among them).
Input: dict with "key" (unique id), "apps" (name, cost, tier, perSeat,
selected), "plans" (name, tier, annual; cheapest first), optional "note", "compact" (one result, no cost breakdown) and
"more" (a link to the full calculator). The totals need JS; without it,
the app list still shows each app's retail price.
*/}}
{{ $key := .key }}
<form class="savings-calc{{ if .compact }} is-compact{{ end }}" id="{{ $key }}-calc" data-annual="{{ .annual }}" onsubmit="return false">
<form class="savings-calc{{ if .compact }} is-compact{{ end }}" id="{{ $key }}-calc" data-plans="{{ .plans | jsonify }}" onsubmit="return false">
<fieldset class="calc-apps">
<legend class="plan-subhead">{{ if .compact }}Which of these do you pay for?{{ else }}Which apps do you pay for today?{{ end }}</legend>
<div class="calc-app-grid">
{{ range .apps }}
<label class="calc-app">
<input type="checkbox" value="{{ .cost }}" data-per-seat="{{ .perSeat }}"{{ if .selected }} checked{{ end }}>
<input type="checkbox" value="{{ .cost }}" data-tier="{{ .tier }}" data-per-seat="{{ .perSeat }}"{{ if .selected }} checked{{ end }}>
<span class="calc-app-name">{{ .name }}</span>
<span class="calc-app-cost">${{ .cost }}{{ if .perSeat }}/person{{ else }} flat{{ end }}</span>
</label>
@@ -34,7 +35,7 @@
<div class="calc-stat"><span class="calc-stat-label">Apps replaced</span><span class="calc-stat-value" data-out="count">0</span></div>
<div class="calc-stat"><span class="calc-stat-label">Their retail cost</span><span class="calc-stat-value" data-out="cost">$0</span><span class="calc-stat-unit">/year</span></div>
{{ end }}
<div class="calc-stat is-highlight"><span class="calc-stat-label">You'd save</span><span class="calc-stat-value" data-out="savings">$0</span><span class="calc-stat-unit">/year</span></div>
<div class="calc-stat is-highlight"><span class="calc-stat-label">You save</span><span class="calc-stat-value" data-out="savings">$0</span><span class="calc-stat-unit">/year on the <span data-out="plan">Good</span> plan</span></div>
{{ with .more }}<a class="more calc-more" href="{{ .url | relURL }}">{{ .label }}<span class="arrow" aria-hidden="true">→</span></a>{{ end }}
</div>
{{ with .note }}<p class="plan-note">{{ . | markdownify }}</p>{{ end }}
@@ -43,7 +44,7 @@
(function () {
var form = document.getElementById('{{ $key }}-calc');
if (!form) return;
var annual = +form.dataset.annual || 0;
var plans = JSON.parse(form.dataset.plans || '[]');
var range = form.querySelector('input[type=range]');
var shown = form.querySelector('.calc-users-value');
var fmt = function (n) { return '$' + Math.round(n).toLocaleString('en-US'); };
@@ -56,16 +57,19 @@
return 1000 + (step - 20) * 500;
}
function update() {
var n = users(+range.value), count = 0, cost = 0;
var n = users(+range.value), count = 0, cost = 0, need = 0;
shown.textContent = n.toLocaleString('en-US') + (+range.value === +range.max ? '+' : '');
range.setAttribute('aria-valuetext', shown.textContent + ' people');
form.querySelectorAll('.calc-app input:checked').forEach(function (box) {
count++;
need = Math.max(need, plans.findIndex(function (p) { return p.tier === box.dataset.tier; }));
cost += +box.value * (box.dataset.perSeat === 'true' ? n : 1) * 12;
});
out('count', count);
out('cost', fmt(cost));
out('savings', fmt(Math.max(0, cost - annual)));
var plan = plans[need] || plans[plans.length - 1] || { name: '', annual: 0 };
out('savings', fmt(Math.max(0, cost - plan.annual)));
out('plan', plan.name);
}
form.addEventListener('input', update);
update();