Skip to content
This repository was archived by the owner on May 22, 2026. It is now read-only.

Commit 8fb8a33

Browse files
rusikvashvayka
authored andcommitted
Perpetual pricing section fixes
pricing/index.md - Bold the entire "Starting from $4 999" label, not just the price - Style "This solution is for you if:" as body copy (not <h4>) - Replace "offline deployment" with "development deployment" in the bullets pricing/pricing.sass - Indent the Self-Managed section header (Subscription plans / License packages + descriptions) by 24px so it aligns with the card content that sits below it on PE PAYG / Perpetual js/script.js - Skip the FAQ-anchor click on tooltip icons inside #perpetual; they were scrolling a few px to nothing because the matching FAQ entries don't exist in this section. Tippy hover tooltips still work. _includes/pricing/tb-perpetual-calculator.html - Group all Prod Instance rows (Included, Complimentary, Extra, Extra Cost) together at the top of the Platform section in the on-screen Calculation summary panel - Pre-fill the Contact Us button with the full calculation summary (subject + URL-encoded message), matching the pattern already used by tb-payg / tb-private-cloud calculators - Mirror every line of the panel in the clipboard message (Included Devices/Prod Instances, Complimentary, White Labeling, Base Price, extras, full add-on breakdown for Edge / Trendz / Offline) so the Copy / Download / Contact Us flows all carry the same detail - Fix the missing complimentaryProd argument in the inner tbSmPUpdateClipboard call so the Complimentary Prod Instances line actually appears in the message - Open the Contact Us link in a new tab
1 parent a4df1ae commit 8fb8a33

4 files changed

Lines changed: 82 additions & 22 deletions

File tree

_includes/pricing/tb-perpetual-calculator.html

Lines changed: 72 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -418,18 +418,23 @@ <h4>
418418
<div class="section-content">
419419
${tbSmPCreateItem('Included Devices', formatNumber(plan.includedDevices), null, true)}
420420
${tbSmPCreateItem('Included Prod Instances', formatNumber(plan.includedProdInstances), 'Number of production instances covered by the perpetual license base price.')}
421-
${complimentaryProd > 0 ? tbSmPCreateItem('Complimentary Prod Instances', formatNumber(complimentaryProd), '1 Production Instance provided at no charge for every 5,000 extra devices.') : ''}
421+
${complimentaryProd > 0 ? tbSmPCreateItem('Complimentary Prod Instances', formatNumber(complimentaryProd), '1 Production Instance provided at no charge for every 5,000 extra devices.') : ''}`;
422+
423+
// Group all Prod Instance info together at the top, immediately
424+
// after Complimentary, before White Labeling / Base Price.
425+
if (extraProd > 0) {
426+
detailsHtml += tbSmPCreateItem('Extra Prod Instances', formatNumber(extraProd), 'Additional instances');
427+
detailsHtml += tbSmPCreateItem('Extra Prod Instances Cost', formatCurrency(extraProdCost), `${formatNumber(extraProd)} × ${formatCurrency(plan.extraProdInstancePrice)}`);
428+
}
429+
430+
detailsHtml += `
422431
${tbSmPCreateItem('White Labeling', '<span class="badge enabled">Enabled</span>', 'Customization of the platform interface with your corporate branding.')}
423432
${tbSmPCreateItem('Base Price', formatCurrency(plan.price), 'One-time license fee before extras and add-ons.')}`;
424433

425434
if (extraDevices > 0) {
426435
detailsHtml += tbSmPCreateItem('Extra Devices', formatNumber(extraDevices), 'Devices beyond included');
427436
detailsHtml += tbSmPCreateItem('Extra Devices Cost', formatCurrency(extraDevicesCost), `${formatNumber(extraDevices)} × ${formatCurrency(plan.extraDevicePrice)}`);
428437
}
429-
if (extraProd > 0) {
430-
detailsHtml += tbSmPCreateItem('Extra Prod Instances', formatNumber(extraProd), 'Additional instances');
431-
detailsHtml += tbSmPCreateItem('Extra Prod Instances Cost', formatCurrency(extraProdCost), `${formatNumber(extraProd)} × ${formatCurrency(plan.extraProdInstancePrice)}`);
432-
}
433438
if (tbSmPState.devInstances > 0) {
434439
detailsHtml += tbSmPCreateItem('Extra Dev Instances', formatNumber(tbSmPState.devInstances));
435440
detailsHtml += tbSmPCreateItem('Extra Dev Instances Cost', formatCurrency(devCost), `${formatNumber(tbSmPState.devInstances)} × ${formatCurrency(plan.devQaExtraInstancePrice)}`);
@@ -470,13 +475,21 @@ <h3>Calculation summary</h3>
470475
<span class="tooltip">${infoIcon}<span class="tooltip-text">${tooltips.join(' + ')}</span></span>
471476
</span>
472477
</div>
473-
<a id="perpContactBtn" href="/docs/contact-us/" class="button">Contact Us</a>
478+
<a id="perpContactBtn" href="/docs/contact-us/" class="button" target="_blank" rel="noopener noreferrer">Contact Us</a>
474479
</div>`;
475480

476481
tbSmPInitExpandable();
477482
document.getElementById('perpCopyBtn')?.addEventListener('click', e => tbSmPCopy(e.currentTarget));
478483
document.getElementById('perpDownloadBtn')?.addEventListener('click', tbSmPDownload);
479-
tbSmPUpdateClipboard({ plan, devices, extraDevices, extraDevicesCost, extraProd, extraProdCost, devCost, breakdown, totalPrice });
484+
tbSmPUpdateClipboard({ plan, devices, extraDevices, extraDevicesCost, complimentaryProd, extraProd, extraProdCost, devCost, breakdown, totalPrice });
485+
486+
// Pre-fill the Contact Us form with the calculation summary —
487+
// matches the pattern used by tb-payg / tb-private-cloud calculators.
488+
const perpContactBtn = document.getElementById('perpContactBtn');
489+
if (perpContactBtn) {
490+
const subject = 'ThingsBoard Perpetual License';
491+
perpContactBtn.href = `/docs/contact-us/?subject=${encodeURIComponent(subject)}&message=${encodeURIComponent(tbSmPState.clipboardMessage)}`;
492+
}
480493
};
481494

482495
const tbSmPGenAddons = (breakdown, plan) => {
@@ -561,22 +574,62 @@ <h3>Calculation summary</h3>
561574
};
562575

563576
const tbSmPUpdateClipboard = ({ plan, devices, extraDevices, extraDevicesCost, complimentaryProd, extraProd, extraProdCost, devCost, breakdown, totalPrice }) => {
564-
let msg = `Perpetual License: ${plan.name} (${formatCurrency(plan.price)})\n`;
565-
msg += `- Devices: ${formatNumber(devices)}\n`;
566-
msg += `- Prod Instances: ${formatNumber(tbSmPState.prodInstances)}`;
567-
if (complimentaryProd > 0) msg += ` (${plan.includedProdInstances} included + ${complimentaryProd} complimentary)`;
568-
msg += '\n';
569-
msg += `- Dev Instances: ${formatNumber(tbSmPState.devInstances)}\n`;
570-
if (extraDevices) msg += `- Extra Devices: ${formatNumber(extraDevices)} (${formatCurrency(extraDevicesCost)})\n`;
571-
if (extraProd) msg += `- Extra Prod: ${formatNumber(extraProd)} (${formatCurrency(extraProdCost)})\n`;
572-
if (tbSmPState.devInstances) msg += `- Dev Cost: ${formatCurrency(devCost)}\n`;
577+
// Mirror the on-screen "Calculation summary" panel as faithfully as
578+
// possible — single flat list under Platform, in the same order
579+
// shown in the UI, so the contact form / clipboard / download all
580+
// match what the user is looking at.
581+
let msg = `Perpetual License: ${plan.name}\n\n`;
582+
583+
msg += `Platform: ${formatCurrency(plan.price)}\n`;
584+
msg += `- Included Devices: ${formatNumber(plan.includedDevices)}\n`;
585+
msg += `- Included Prod Instances: ${formatNumber(plan.includedProdInstances)}\n`;
586+
if (complimentaryProd > 0) {
587+
msg += `- Complimentary Prod Instances: ${formatNumber(complimentaryProd)}\n`;
588+
}
589+
if (extraProd > 0) {
590+
msg += `- Extra Prod Instances: ${formatNumber(extraProd)}\n`;
591+
msg += `- Extra Prod Instances Cost: ${formatCurrency(extraProdCost)}\n`;
592+
}
593+
msg += `- White Labeling: Enabled\n`;
594+
msg += `- Base Price: ${formatCurrency(plan.price)}\n`;
595+
if (extraDevices > 0) {
596+
msg += `- Extra Devices: ${formatNumber(extraDevices)}\n`;
597+
msg += `- Extra Devices Cost: ${formatCurrency(extraDevicesCost)}\n`;
598+
}
599+
if (tbSmPState.devInstances > 0) {
600+
msg += `- Extra Dev Instances: ${formatNumber(tbSmPState.devInstances)}\n`;
601+
msg += `- Extra Dev Instances Cost: ${formatCurrency(devCost)}\n`;
602+
}
573603

574604
if (Object.keys(breakdown).length) {
575605
msg += '\nAdd-ons:\n';
576-
if (breakdown.edge) msg += `- Edge: ${formatCurrency(breakdown.edge.cost)} (${breakdown.edge.total} instances)\n`;
577-
if (breakdown.trendz) msg += `- Trendz: ${formatCurrency(breakdown.trendz.cost)}\n`;
578-
if (breakdown.offline) msg += `- Offline Mode: ${formatCurrency(breakdown.offline.cost)}\n`;
606+
607+
if (breakdown.edge) {
608+
const edge = breakdown.edge;
609+
msg += `\nEdge Computing: ${formatCurrency(edge.cost)}\n`;
610+
msg += `- Included Edges: ${formatNumber(edge.included)}\n`;
611+
msg += `- Add-on Base Price: ${formatCurrency(edge.base)}\n`;
612+
if (edge.extra > 0) {
613+
msg += `- Extra Edges: ${formatNumber(edge.extra)}\n`;
614+
msg += `- Extra Edges Cost: ${formatCurrency(edge.extraCost)}\n`;
615+
}
616+
}
617+
618+
if (breakdown.trendz) {
619+
const trendz = breakdown.trendz;
620+
msg += `\nTrendz Analytics: ${formatCurrency(trendz.cost)}\n`;
621+
msg += `- Add-on Base Price: ${formatCurrency(trendz.base)}\n`;
622+
if (trendz.extraDevices > 0) {
623+
msg += `- Extra Devices: ${formatNumber(trendz.extraDevices)}\n`;
624+
msg += `- Extra Devices Cost: ${formatCurrency(trendz.extraCost)}\n`;
625+
}
626+
}
627+
628+
if (breakdown.offline) {
629+
msg += `\nOffline Mode: ${formatCurrency(breakdown.offline.cost)}\n`;
630+
}
579631
}
632+
580633
tbSmPState.clipboardMessage = msg + `\nTotal: ${formatCurrency(totalPrice)}`;
581634
};
582635

js/script.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ var tb = (function () {
164164
let faqAnchor = this;
165165
let nodeId = this.getAttribute('data-faq-id');
166166
let faqLink = $(faqAnchor).children('a')[0];
167+
if ($(faqAnchor).closest('#perpetual').length) {
168+
return;
169+
}
167170
$(faqLink).on('click', function() {
168171
navigateToFaq(nodeId);
169172
});

pricing/index.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,10 +1062,10 @@ defaultActivePricingSection: thingsboard-pe-options
10621062
<h3>Own Your IoT Solution. Perpetually.</h3>
10631063
<p class="subtitle">The one-time, enterprise-grade license for maximum security, permanent data control, and predictable costs.</p>
10641064
<p>A perpetual license transforms your core IoT platform into a permanent asset, giving you a predictable financial model and complete control over your technology roadmap. It's the ideal foundation for a long-term, large-scale enterprise deployment.</p>
1065-
<p class="perpetual-price">Starting from <strong>$4 999</strong></p>
1066-
<h4>This solution is for you if:</h4>
1065+
<p class="perpetual-price"><strong>Starting from $4 999</strong></p>
1066+
<p>This solution is for you if:</p>
10671067
<ul>
1068-
<li>Your security policy requires an isolated, on-premises, or offline deployment.</li>
1068+
<li>Your security policy requires an isolated, on-premises, or development deployment.</li>
10691069
<li>Your financial model favors a one-time capital investment (CAPEX) over recurring expenses.</li>
10701070
<li>Your business needs a unique, tailored solution, not a one-size-fits-all subscription.</li>
10711071
</ul>

pricing/pricing.sass

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#pricing #pricingContent #thingsboard-pe .pricing-content-description
2+
padding-left: 24px
13

24
.container
35
&.top
@@ -1297,8 +1299,10 @@ html#pricing
12971299
z-index: 6
12981300
display: flex
12991301
align-items: center
1302+
justify-content: center
13001303

13011304
.pricing-hero-content
1305+
text-align: center
13021306
padding-top: 40px
13031307
@media (min-width: 992px)
13041308
padding-top: 35px

0 commit comments

Comments
 (0)