Pre-Alpha to Alpha Ready
This commit is contained in:
@@ -13,6 +13,47 @@
|
||||
return document.getElementById(id);
|
||||
}
|
||||
|
||||
/* ── Animated number counter ─────────────────────────────────
|
||||
Smoothly interpolates a displayed dollar value from old → new.
|
||||
Targets both the desktop element and its _m mobile clone.
|
||||
Duration: 350ms ease-out via requestAnimationFrame.
|
||||
──────────────────────────────────────────────────────────── */
|
||||
var _animFrames = {};
|
||||
function animateValue(elId, newVal, formatFn) {
|
||||
var el = document.getElementById(elId);
|
||||
if (!el) return;
|
||||
var elM = document.getElementById(elId + '_m');
|
||||
|
||||
var raw = (el.textContent || '').replace(/[^0-9.\-]/g, '');
|
||||
var from = parseFloat(raw) || 0;
|
||||
var to = parseFloat(newVal) || 0;
|
||||
|
||||
if (from === to) {
|
||||
el.textContent = formatFn(to);
|
||||
if (elM) elM.textContent = formatFn(to);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_animFrames[elId]) cancelAnimationFrame(_animFrames[elId]);
|
||||
|
||||
var duration = 350;
|
||||
var start = null;
|
||||
function step(ts) {
|
||||
if (!start) start = ts;
|
||||
var progress = Math.min((ts - start) / duration, 1);
|
||||
var eased = 1 - Math.pow(1 - progress, 3);
|
||||
var current = from + (to - from) * eased;
|
||||
el.textContent = formatFn(current);
|
||||
if (elM) elM.textContent = formatFn(current);
|
||||
if (progress < 1) {
|
||||
_animFrames[elId] = requestAnimationFrame(step);
|
||||
} else {
|
||||
delete _animFrames[elId];
|
||||
}
|
||||
}
|
||||
_animFrames[elId] = requestAnimationFrame(step);
|
||||
}
|
||||
|
||||
function getQuote(q) {
|
||||
return q || (typeof global.calcQuote === 'function' ? global.calcQuote() : null);
|
||||
}
|
||||
@@ -268,7 +309,7 @@
|
||||
show('sl-users', users > 0);
|
||||
getEl('sl-users-sub')?.classList.toggle('hidden', users === 0);
|
||||
if (users > 0) {
|
||||
getEl('sl-users-val').textContent = fmt(userTotal);
|
||||
animateValue('sl-users-val', userTotal, fmt);
|
||||
const sub = getEl('sl-users-sub');
|
||||
sub.classList.remove('hidden');
|
||||
const subRows = [{ copy: `${users} × ${fmt(baseUserRate)}/user (${byol ? 'BYOL' : 'M365 Incl.'})` }];
|
||||
@@ -283,7 +324,7 @@
|
||||
getEl('sl-endpoints-sub')?.classList.toggle('hidden', endpoints === 0);
|
||||
if (endpoints > 0) {
|
||||
const epOnly = endpointTotal - serverBase;
|
||||
getEl('sl-endpoints-val').textContent = fmt(epOnly);
|
||||
animateValue('sl-endpoints-val', epOnly, fmt);
|
||||
const sub = getEl('sl-endpoints-sub');
|
||||
sub.classList.remove('hidden');
|
||||
const epRows = [{ copy: `${endpoints} × ${fmt(pricing.RATE_ENDPOINT)}/endpoint` }];
|
||||
@@ -293,13 +334,13 @@
|
||||
}
|
||||
|
||||
show('sl-servers', servers > 0);
|
||||
if (servers > 0) getEl('sl-servers-val').textContent = fmt(serverBase);
|
||||
if (servers > 0) animateValue('sl-servers-val', serverBase, fmt);
|
||||
|
||||
show('sl-zt', ztNetTotal > 0);
|
||||
if (ztNetTotal > 0) getEl('sl-zt-val').textContent = fmt(ztNetTotal);
|
||||
if (ztNetTotal > 0) animateValue('sl-zt-val', ztNetTotal, fmt);
|
||||
|
||||
show('sl-voip', voipTotal > 0);
|
||||
if (voipTotal > 0) getEl('sl-voip-val').textContent = fmt(voipTotal);
|
||||
if (voipTotal > 0) animateValue('sl-voip-val', voipTotal, fmt);
|
||||
|
||||
const slAdminEl = getEl('sl-admin');
|
||||
const slAdminValEl = getEl('sl-admin-val');
|
||||
@@ -322,9 +363,9 @@
|
||||
slAdminSubEl.innerHTML = renderSubRows(adminRows);
|
||||
}
|
||||
|
||||
getEl('mrrDisplay').textContent = fmt(effectiveMrr);
|
||||
animateValue('mrrDisplay', effectiveMrr, fmt);
|
||||
const monthlyTotalEl = getEl('sl-monthly-total-val');
|
||||
if (monthlyTotalEl) monthlyTotalEl.textContent = fmt(effectiveMrr) + '/mo';
|
||||
if (monthlyTotalEl) monthlyTotalEl.innerHTML = fmt(effectiveMrr) + '<span class="suffix-mo">/mo</span>';
|
||||
getEl('annualDisplay').textContent = fmt(effectiveAnnual);
|
||||
getEl('perUserRow').classList.toggle('hidden', users === 0);
|
||||
if (users > 0) getEl('perUserDisplay').textContent = fmt(effectiveMrr / users) + '/user';
|
||||
@@ -620,22 +661,26 @@
|
||||
if (!q) return;
|
||||
|
||||
const collapsed = id => !document.getElementById(id)?.classList.contains('sec-open');
|
||||
const setSummary = (id, text) => {
|
||||
const setSummary = (id, text, numericVal) => {
|
||||
const el = document.getElementById(id);
|
||||
if (!el) return;
|
||||
const secId = id.replace('-summary', '').replace('sec0', 'sec-0');
|
||||
const show = collapsed(secId) && !!text;
|
||||
el.textContent = text || '';
|
||||
if (numericVal !== undefined && show) {
|
||||
animateValue(id, numericVal, function(v) { return fmt(v) + '/mo'; });
|
||||
} else {
|
||||
el.textContent = text || '';
|
||||
}
|
||||
el.hidden = !show;
|
||||
el.style.display = show ? 'flex' : 'none';
|
||||
};
|
||||
|
||||
setSummary('sec01-summary', q.adminWaived ? 'WAIVED' : fmt(q.adminFeeNet) + '/mo');
|
||||
setSummary('sec02-summary', q.users > 0 ? `${fmt(q.userTotal)}/mo` : '');
|
||||
setSummary('sec03-summary', q.endpoints > 0 ? `${fmt(q.endpointTotal - q.serverBase)}/mo` : '');
|
||||
setSummary('sec04-summary', q.servers > 0 ? `${fmt(q.serverBase)}/mo` : '');
|
||||
setSummary('sec05-summary', q.ztNetTotal > 0 ? `${fmt(q.ztNetTotal)}/mo` : '');
|
||||
setSummary('sec06-summary', q.voipSeats > 0 ? `${fmt(q.voipTotal)}/mo` : '');
|
||||
setSummary('sec02-summary', q.users > 0 ? `${fmt(q.userTotal)}/mo` : '', q.users > 0 ? q.userTotal : undefined);
|
||||
setSummary('sec03-summary', q.endpoints > 0 ? `${fmt(q.endpointTotal - q.serverBase)}/mo` : '', q.endpoints > 0 ? q.endpointTotal - q.serverBase : undefined);
|
||||
setSummary('sec04-summary', q.servers > 0 ? `${fmt(q.serverBase)}/mo` : '', q.servers > 0 ? q.serverBase : undefined);
|
||||
setSummary('sec05-summary', q.ztNetTotal > 0 ? `${fmt(q.ztNetTotal)}/mo` : '', q.ztNetTotal > 0 ? q.ztNetTotal : undefined);
|
||||
setSummary('sec06-summary', q.voipSeats > 0 ? `${fmt(q.voipTotal)}/mo` : '', q.voipSeats > 0 ? q.voipTotal : undefined);
|
||||
}
|
||||
|
||||
function updateVsComparison(q) {
|
||||
|
||||
Reference in New Issue
Block a user