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;
|