vpn-btcpay-provisioner/app/static/js/pricing.js

116 lines
3.6 KiB
JavaScript
Raw Normal View History

2024-12-30 07:07:53 +00:00
// Utility functions for duration formatting
function formatDuration(hours) {
if (hours < 24) {
return `${hours} hour${hours === 1 ? '' : 's'}`;
}
if (hours < 168) {
return `${hours / 24} day${hours === 24 ? '' : 's'}`;
}
if (hours < 720) {
return `${Math.floor(hours / 168)} week${hours === 168 ? '' : 's'}`;
}
return `${Math.floor(hours / 720)} month${hours === 720 ? '' : 's'}`;
}
2024-12-30 06:03:07 +00:00
2024-12-30 07:07:53 +00:00
// Price calculation with volume discounts
async function calculatePrice(hours) {
try {
const response = await fetch('/api/calculate-price', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ hours: parseInt(hours) })
});
2024-12-30 06:03:07 +00:00
2024-12-30 07:07:53 +00:00
if (!response.ok) {
throw new Error('Failed to calculate price');
}
2024-12-30 06:03:07 +00:00
2024-12-30 07:07:53 +00:00
const data = await response.json();
return {
price: data.price,
formattedDuration: formatDuration(hours)
};
} catch (error) {
console.error('Price calculation failed:', error);
throw error;
}
2024-12-30 06:03:07 +00:00
}
2024-12-30 07:07:53 +00:00
// Form initialization and event handling
function initializeForm(config) {
const {
formId = 'subscription-form',
sliderId = 'duration-slider',
priceDisplayId = 'price-display',
durationDisplayId = 'duration-display',
presetButtonClass = 'duration-preset'
} = config;
2024-12-30 06:03:07 +00:00
2024-12-30 07:07:53 +00:00
const form = document.getElementById(formId);
const slider = document.getElementById(sliderId);
const priceDisplay = document.getElementById(priceDisplayId);
const durationDisplay = document.getElementById(durationDisplayId);
const presetButtons = document.querySelectorAll(`.${presetButtonClass}`);
2024-12-13 09:57:12 +00:00
2024-12-30 07:07:53 +00:00
if (!form || !slider || !priceDisplay || !durationDisplay) {
throw new Error('Required elements not found');
2024-12-13 09:57:12 +00:00
}
2024-12-30 07:07:53 +00:00
return {
form,
slider,
priceDisplay,
durationDisplay,
presetButtons
};
}
// Main pricing interface
export const Pricing = {
async init(config = {}) {
2024-12-30 06:03:07 +00:00
try {
2024-12-30 07:07:53 +00:00
const elements = initializeForm(config);
const { form, slider, priceDisplay, durationDisplay, presetButtons } = elements;
// Update price when duration changes
const updateDisplay = async (hours) => {
try {
const { price, formattedDuration } = await calculatePrice(hours);
priceDisplay.textContent = price;
durationDisplay.textContent = formattedDuration;
} catch (error) {
console.error('Failed to update price display:', error);
priceDisplay.textContent = 'Error';
durationDisplay.textContent = 'Error calculating duration';
}
2024-12-30 06:03:07 +00:00
};
2024-12-30 07:07:53 +00:00
// Set up event listeners
slider.addEventListener('input', () => updateDisplay(slider.value));
2024-12-30 06:03:07 +00:00
2024-12-30 07:07:53 +00:00
presetButtons.forEach(button => {
button.addEventListener('click', (e) => {
const hours = e.target.dataset.hours;
slider.value = hours;
updateDisplay(hours);
});
2024-12-13 09:57:12 +00:00
});
2024-12-30 06:03:07 +00:00
2024-12-30 07:07:53 +00:00
// Initial price calculation
await updateDisplay(slider.value);
2024-12-30 06:03:07 +00:00
2024-12-30 07:07:53 +00:00
return {
updatePrice: updateDisplay,
getCurrentDuration: () => parseInt(slider.value)
};
2024-12-13 09:57:12 +00:00
} catch (error) {
2024-12-30 07:07:53 +00:00
console.error('Failed to initialize pricing:', error);
throw error;
2024-12-13 09:57:12 +00:00
}
2024-12-30 07:07:53 +00:00
},
formatDuration,
calculatePrice
};
2024-12-13 09:57:12 +00:00
2024-12-30 07:07:53 +00:00
export default Pricing;