Skip to content

Commit

Permalink
Merge branch 'main' of github.com:FusionAuth/fusionauth-site into lyl…
Browse files Browse the repository at this point in the history
…e/better-html-checker
  • Loading branch information
lyleschemmerling committed Dec 11, 2024
2 parents 8bd9ecd + f6d74da commit 2a55557
Show file tree
Hide file tree
Showing 86 changed files with 594 additions and 535 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ jobs:
- name: ESLint
run: |
cd astro
bash ../src/scripts/lint-recent-files.sh
npm run lint-pr
shell: /usr/bin/bash -e -o pipefail {0}
5 changes: 3 additions & 2 deletions astro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"astro": "astro",
"vale": "./node_modules/@vvago/vale/bin/vale",
"spellcheck": "npm run vale src/content src/components",
"lint": "eslint"
"lint": "eslint",
"lint-pr": "node ../src/scripts/lint-recent-files.mjs"
},
"dependencies": {
"@astro-community/astro-embed-youtube": "^0.4.1",
Expand Down Expand Up @@ -53,4 +54,4 @@
"remark-toc": "^9.0.0",
"typescript-eslint": "^8.4.0"
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 45 additions & 0 deletions astro/public/img/cta/corner-circ.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
177 changes: 134 additions & 43 deletions astro/public/js/Pricing-0.3.0.js → astro/public/js/Pricing-0.5.0.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
/*
* Copyright (c) 2020, Inversoft Inc., All Rights Reserved
* Copyright (c) 2020-2023, Inversoft Inc., All Rights Reserved
*/
'use strict';

// noinspection DuplicatedCode
class FusionAuthPriceCalculator {
constructor() {

this.accountHost = 'account.fusionauth.io';
this.hostingSelectionDiv = document.getElementById('hosting-selection');
this.hostingPriceDiv = document.getElementById('hosting-price');
this.planSelectionDiv = document.getElementById('plan-selection');
this.planPriceDiv = document.getElementById('plan-price');
this.sumDiv = document.getElementById('sum');
this.mauChargeDiv = document.getElementById('mau-charge');
this.mauChargeLabelDiv = document.getElementById('mau-charge-label');
this.sumLabel = document.querySelector('h3[class=total]');
this.sumDiv = document.getElementById('total-price');
this.monthlyActiveUserSlider = document.querySelector('input[name=monthly-active-users]');
this.monthlyActiveUserSlider.addEventListener('input', event => this._handleSliderChange(event));
this.monthlyActiveUserSlider.addEventListener('mouseup', event => this._handleSliderChange(event));
Expand All @@ -19,24 +24,32 @@ class FusionAuthPriceCalculator {
this.monthlyActiveUserValue = document.getElementById('monthly-active-users-value');
this.communityButton = document.querySelector('a[data-plan=Community]');
this.starterButton = document.querySelector('a[data-plan=Starter]');
this.purchaseButton = document.getElementById('purchase-button');

this.hostingPrice = 0;
this.planPrice = 0;
this.billingToggle = document.getElementById('billing-toggle');
this.billingToggle.addEventListener('click', event => this._handleBillingIntervalChange(event));
this._loadState();
this.billingInterval = 'monthly';
this.monthlyMAUToolTip = 'This is your estimated Monthly Active User (MAU) charge after your initial month of deployment. This price will adjust based on your actual MAU.';
this.yearlyMAUToolTip = 'This charge reflects the MAU capacity purchased as part of your annual subscription.';

document.querySelectorAll('a[data-step]')
.forEach(e => e.addEventListener('click', event => this._handleStepClick(event)))
.forEach(e => e.addEventListener('click', event => this._handleStepClick(event)));
document.querySelectorAll('a[data-plan]')
.forEach(e => e.addEventListener('click', event => this._handlePlanClick(event)))
.forEach(e => e.addEventListener('click', event => this._handlePlanClick(event)));
window.addEventListener('popstate', event => this._handleStateChange(event));

fetch('https://account.fusionauth.io/ajax/purchase/price-model')
this._setTooltipContent();

fetch(`https://${this.accountHost}/ajax/purchase/price-model`)
.then(response => response.json())
.then(json => {
this.priceModel = json;
this._changeStep();
})
this._drawPlanPrices();
});
}

_setTooltipContent() {
document.getElementById('pricing-tooltip')._tippy.setContent(this.billingInterval === 'monthly' ? this.monthlyMAUToolTip : this.yearlyMAUToolTip);
}

_calculateHostingPrice(type) {
Expand All @@ -50,27 +63,55 @@ class FusionAuthPriceCalculator {
price = (2 * this.priceModel.ec2['medium']) + this.priceModel.elb.base + (this.priceModel.rds['medium'] * 2);
}

price = Math.floor(price);

if (this.billingInterval === 'yearly') {
price *= 12;
}

return price;
}

_getBillingIntervalKey(billingInterval) {
const interval = billingInterval || this.billingInterval;
return 'pricePerUnit' + this._billingIntervalReadable(interval);
}

_billingIntervalReadable(billingInterval) {
const interval = billingInterval || this.billingInterval;
return interval.charAt(0).toUpperCase() + interval.slice(1);
}

_calculatePlanPrice(plan) {
if (plan === 'Community') {
return 0;
if (!plan || plan === 'Community') {
return { planPrice: 0, mauPrice: 0, discount: 0 };
}

var mau = parseInt(this.monthlyActiveUserSlider.value);
var planPricing = this.priceModel.plan.tierPricing[plan];
var increments = mau / 10000;
var price;
const mau = parseInt(this.monthlyActiveUserSlider.value);
const planPricing = this.priceModel.plan.tierPricing[plan];
const billingKey = this._getBillingIntervalKey();
const increments = mau / 10000;
let mauPrice;

if (increments < 10) {
price = planPricing.base.pricePerUnit + (planPricing.tier2.pricePerUnit * (increments - 1));
mauPrice = planPricing.tier2[billingKey] * (increments - 1);
} else if (increments < 100) {
price = planPricing.base.pricePerUnit + (planPricing.tier2.pricePerUnit * 9) + (planPricing.tier3.pricePerUnit * (increments - 10));
mauPrice = (planPricing.tier2[billingKey] * 9) + (planPricing.tier3[billingKey] * (increments - 10));
} else {
price = planPricing.base.pricePerUnit + (planPricing.tier2.pricePerUnit * 9) + (planPricing.tier3.pricePerUnit * 90) + (planPricing.tier4.pricePerUnit * (increments - 100));
mauPrice = (planPricing.tier2[billingKey] * 9) + (planPricing.tier3[billingKey] * 90) + (planPricing.tier4[billingKey] * (increments - 100));
}

return price;
let discount = 0;
const basePrice = planPricing.base[billingKey];

if (plan && plan !== 'Community') {
const monthlyPrice = planPricing.base['pricePerUnitMonthly'] * 12;
const yearlyPrice = planPricing.base['pricePerUnitYearly'];

discount = Math.round(100.0 * (monthlyPrice - yearlyPrice) / monthlyPrice);
}

return { planPrice: basePrice, mauPrice: mauPrice, discount: discount };
}

_changeStep() {
Expand Down Expand Up @@ -105,7 +146,7 @@ class FusionAuthPriceCalculator {
const mau = parseInt(this.monthlyActiveUserSlider.value);
let mauText = new Intl.NumberFormat('en').format(mau);
if (mau === 1000000) {
mauText += "+";
mauText += '+';
}
this.monthlyActiveUserValue.innerText = mauText;

Expand All @@ -122,6 +163,23 @@ class FusionAuthPriceCalculator {
this._redraw();
}

_handleBillingIntervalChange() {

if (this.billingInterval === 'monthly') {
this.billingInterval = 'yearly';
this.billingToggle.classList.add('toggle-on')
this.billingToggle.classList.remove('toggle-off')
} else {
this.billingInterval = 'monthly';
this.billingToggle.classList.add('toggle-off')
this.billingToggle.classList.remove('toggle-on')
}

this._setTooltipContent();

this._redraw();
}

_handleStateChange() {
this._loadState();
this._redraw();
Expand Down Expand Up @@ -156,18 +214,35 @@ class FusionAuthPriceCalculator {
}
}

_drawPlanPrices() {
for (const plan in FusionAuthPriceCalculator.plans) {
if (plan !== 'community') {
const planPricing = this.priceModel.plan.tierPricing[FusionAuthPriceCalculator.plans[plan]];
const billingKey = this._getBillingIntervalKey();
let price = planPricing.base[billingKey];
const pricingDiv = document.getElementById(plan + '-base-price');

if (this.billingInterval === 'yearly') {
price = Math.ceil(price / 12.0);
}

pricingDiv.textContent = price.toLocaleString();
}
}
}

_redraw() {
document.querySelectorAll(`div[data-step]`).forEach(e => e.style.display = 'none');
document.querySelector(`div[data-step=${this.step}]`).style.display = 'block';

this.hostingSelectionDiv.innerText = this.hosting ? FusionAuthPriceCalculator.names[this.hosting] : '-';
this.planSelectionDiv.innerText = this.plan ? this.plan : '-';

const hostingPrice = this.hosting ? this._calculateHostingPrice(this.hosting) : 0;

if (this.hosting) {
this.hostingPrice = this._calculateHostingPrice(this.hosting);
this.hostingPriceDiv.innerText = '$' + new Intl.NumberFormat('en').format(Math.floor(this.hostingPrice));
this.hostingPriceDiv.innerText = '$' + new Intl.NumberFormat('en').format(Math.floor(hostingPrice));
} else {
this.hostingPrice = 0;
this.hostingPriceDiv.innerText = '-';
}

Expand Down Expand Up @@ -196,46 +271,62 @@ class FusionAuthPriceCalculator {
this.communityButton.innerText = 'Download';
}

this._updatePriceBox(hostingPrice);

this._drawPlanPrices();
}

_updatePriceBox(hostingPrice) {
document.querySelectorAll('div[data-plan]').forEach(e => e.style.border = '2px solid transparent');

const billingIntervalLabel = this.billingInterval === 'yearly' ? 'Annually' : 'Monthly';
const billingIntervalLabelAdj = this.billingInterval === 'yearly' ? 'Annual' : 'Monthly';
this.mauChargeLabelDiv.innerText = `${billingIntervalLabelAdj} MAU charge`;
document.querySelectorAll('.renewal-abb').forEach(e => e.textContent = this.billingInterval === 'yearly' ? ' /yr' : ' /mo');
document.querySelectorAll('.billed').forEach(e => e.textContent = billingIntervalLabel);
document.querySelectorAll('.renewal-type').forEach(e => e.textContent = billingIntervalLabelAdj);
this.sumLabel.textContent = this.billingInterval === 'yearly' ? 'Total' : 'Estimate Total';

const { planPrice, mauPrice, discount } = this._calculatePlanPrice(this.plan);

if (this.plan) {
this.planPrice = this._calculatePlanPrice(this.plan);
this.planPriceDiv.innerText = '$' + new Intl.NumberFormat('en').format(Math.floor(this.planPrice));
this.planPriceDiv.innerText = '$' + new Intl.NumberFormat('en').format(Math.floor(planPrice));
this.mauChargeDiv.innerText = '$' + new Intl.NumberFormat('en').format(Math.floor(mauPrice));

document.querySelector(`div[data-plan=${this.plan}]`).style.border = '2px solid #f58320';
} else {
this.planPrice = 0;
this.planPriceDiv.innerText = '-';
}

if (this.hosting && this.plan) {
this.purchaseButton.removeAttribute('disabled');
this.purchaseButton.classList.remove('grayed-out');
this.purchaseButton.setAttribute('href', `https://account.fusionauth.io/account/purchase/start?hosting=${this.hosting}&plan=${this.plan}`)
document.getElementById('annual-discount-label').style.display = 'block';
document.getElementById('annual-discount-label').innerText = `Saves ${discount}%`;
} else {
this.purchaseButton.setAttribute('disabled', 'disabled');
this.purchaseButton.classList.add('grayed-out');
this.planPriceDiv.innerText = '-';
document.getElementById('annual-discount-label').style.display = 'none';
}

if ((!this.hosting || this.hosting === 'self-hosting' || this.hosting === 'basic-cloud') && (!this.plan || this.plan === 'Community' || this.plan === 'Starter')) {
this.sumDiv.innerText = 'Free trial';
this.sumDiv.nextElementSibling.style.display = 'none';
this.purchaseButton.innerHTML = 'Start trial';
} else if (this.hostingPrice !== 0 || this.planPrice !== 0) {
this.sumDiv.innerText = '$' + new Intl.NumberFormat('en').format(Math.floor(this.hostingPrice + this.planPrice));
} else if (hostingPrice !== 0 || planPrice !== 0) {
this.sumDiv.innerText = '$' + new Intl.NumberFormat('en').format(Math.floor(hostingPrice + planPrice + mauPrice));
this.sumDiv.nextElementSibling.style.display = 'inline';
this.purchaseButton.innerHTML = 'Buy online';
} else {
this.sumDiv.innerText = '-';
this.sumDiv.nextElementSibling.style.display = 'inline';
this.purchaseButton.innerHTML = 'Buy online';
}
}
}

FusionAuthPriceCalculator.names = {
'basic-cloud': 'Basic',
'business-cloud': 'Business',
'ha-cloud': 'HA',
'ha-cloud': 'High Availability',
'self-hosting': 'Self-hosting'
}

document.addEventListener('DOMContentLoaded', () => new FusionAuthPriceCalculator());
FusionAuthPriceCalculator.plans = {
'community': 'Community',
'starter': 'Starter',
'essentials': 'Essentials',
'enterprise': 'Enterprise'
}

document.addEventListener('DOMContentLoaded', () => new FusionAuthPriceCalculator());
Loading

0 comments on commit 2a55557

Please sign in to comment.