robustness review of price calc js
This commit is contained in:
parent
e7c6a53a17
commit
27c41a6187
7 changed files with 143 additions and 24 deletions
|
|
@ -53,12 +53,16 @@ class DOMManager {
|
|||
this.elements.serviceLevelGroup = document.getElementById('serviceLevelGroup');
|
||||
}
|
||||
|
||||
// Get element by key
|
||||
// Get element by key with error handling
|
||||
get(key) {
|
||||
return this.elements[key];
|
||||
const element = this.elements[key];
|
||||
if (!element && key !== 'addonsContainer') {
|
||||
console.warn(`DOM element '${key}' not found`);
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
// Check if element exists
|
||||
// Check if element exists and is valid
|
||||
has(key) {
|
||||
return this.elements[key] && this.elements[key] !== null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,15 @@ class OrderManager {
|
|||
messageField.value = configMessage;
|
||||
}
|
||||
|
||||
// Store configuration details in hidden field
|
||||
// Find and fill alternative message field if the first one doesn't exist
|
||||
if (!messageField) {
|
||||
const altMessageField = document.querySelector('textarea[name="message"]');
|
||||
if (altMessageField) {
|
||||
altMessageField.value = configMessage;
|
||||
}
|
||||
}
|
||||
|
||||
// Store configuration details in hidden field if it exists
|
||||
const detailsField = document.querySelector('#order-form input[name="details"]');
|
||||
if (detailsField) {
|
||||
detailsField.value = JSON.stringify({
|
||||
|
|
|
|||
|
|
@ -64,7 +64,11 @@ class PlanManager {
|
|||
if (!planSelect) return;
|
||||
|
||||
const serviceLevel = domManager.getSelectedServiceLevel();
|
||||
if (!serviceLevel) return;
|
||||
if (!serviceLevel) {
|
||||
// Clear dropdown if no service level is selected
|
||||
planSelect.innerHTML = '<option value="">Select a service level first</option>';
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear existing options
|
||||
planSelect.innerHTML = '<option value="">Auto-select best matching plan</option>';
|
||||
|
|
@ -72,6 +76,11 @@ class PlanManager {
|
|||
// Get plans for the selected service level
|
||||
const availablePlans = this.pricingDataManager.getPlansForServiceLevel(serviceLevel);
|
||||
|
||||
if (!availablePlans || availablePlans.length === 0) {
|
||||
planSelect.innerHTML = '<option value="">No plans available for this service level</option>';
|
||||
return;
|
||||
}
|
||||
|
||||
// Add plans to dropdown
|
||||
availablePlans.forEach(plan => {
|
||||
const option = document.createElement('option');
|
||||
|
|
|
|||
|
|
@ -4,17 +4,27 @@
|
|||
*/
|
||||
class PriceCalculator {
|
||||
constructor() {
|
||||
// Initialize managers
|
||||
this.domManager = new DOMManager();
|
||||
this.currentOffering = this.extractOfferingFromURL();
|
||||
this.pricingDataManager = new PricingDataManager(this.currentOffering);
|
||||
this.planManager = new PlanManager(this.pricingDataManager);
|
||||
this.addonManager = new AddonManager(this.pricingDataManager);
|
||||
this.uiManager = new UIManager();
|
||||
this.orderManager = new OrderManager();
|
||||
try {
|
||||
// Initialize managers
|
||||
this.domManager = new DOMManager();
|
||||
this.currentOffering = this.extractOfferingFromURL();
|
||||
|
||||
// Initialize the calculator
|
||||
this.init();
|
||||
if (!this.currentOffering) {
|
||||
throw new Error('Unable to extract offering information from URL');
|
||||
}
|
||||
|
||||
this.pricingDataManager = new PricingDataManager(this.currentOffering);
|
||||
this.planManager = new PlanManager(this.pricingDataManager);
|
||||
this.addonManager = new AddonManager(this.pricingDataManager);
|
||||
this.uiManager = new UIManager();
|
||||
this.orderManager = new OrderManager();
|
||||
|
||||
// Initialize the calculator
|
||||
this.init();
|
||||
} catch (error) {
|
||||
console.error('Error initializing PriceCalculator:', error);
|
||||
this.showInitializationError(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Extract offering info from URL
|
||||
|
|
@ -41,11 +51,24 @@ class PriceCalculator {
|
|||
this.orderManager.setupOrderButton(this.domManager);
|
||||
this.updateCalculator();
|
||||
} else {
|
||||
console.warn('No current offering found, calculator not initialized');
|
||||
throw new Error('No current offering found');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error initializing price calculator:', error);
|
||||
this.uiManager.showError(this.domManager, 'Failed to load pricing information');
|
||||
this.showInitializationError(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Show initialization error to user
|
||||
showInitializationError(message) {
|
||||
const planMatchStatus = this.domManager?.get('planMatchStatus');
|
||||
if (planMatchStatus) {
|
||||
planMatchStatus.innerHTML = `
|
||||
<i class="bi bi-exclamation-triangle me-2 text-danger"></i>
|
||||
<span class="text-danger">Failed to load pricing calculator: ${message}</span>
|
||||
`;
|
||||
planMatchStatus.className = 'alert alert-danger mb-3';
|
||||
planMatchStatus.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -130,6 +153,23 @@ class PriceCalculator {
|
|||
window.addEventListener('addon-changed', () => {
|
||||
this.updatePricing();
|
||||
});
|
||||
|
||||
// Service level change listener
|
||||
const serviceLevelInputs = this.domManager.get('serviceLevelInputs');
|
||||
if (serviceLevelInputs) {
|
||||
serviceLevelInputs.forEach(input => {
|
||||
input.addEventListener('change', () => {
|
||||
// Update plan dropdown for new service level
|
||||
this.planManager.populatePlanDropdown(this.domManager);
|
||||
|
||||
// Update addons for new service level
|
||||
this.addonManager.updateAddons(this.domManager);
|
||||
|
||||
// Update pricing
|
||||
this.updatePricing();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Update calculator (initial setup)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ class PricingDataManager {
|
|||
// Load pricing data from API endpoint
|
||||
async loadPricingData() {
|
||||
try {
|
||||
const response = await fetch(`/offering/${this.currentOffering.provider_slug}/${this.currentOffering.service_slug}/?pricing=json`);
|
||||
const url = `/offering/${this.currentOffering.provider_slug}/${this.currentOffering.service_slug}/?pricing=json`;
|
||||
const response = await fetch(url);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load pricing data: ${response.status} ${response.statusText}`);
|
||||
|
|
@ -21,8 +22,17 @@ class PricingDataManager {
|
|||
|
||||
const data = await response.json();
|
||||
|
||||
if (!data || typeof data !== 'object') {
|
||||
throw new Error('Invalid pricing data received from server');
|
||||
}
|
||||
|
||||
this.pricingData = data.pricing || data;
|
||||
|
||||
// Validate that we have usable pricing data
|
||||
if (!this.pricingData || Object.keys(this.pricingData).length === 0) {
|
||||
throw new Error('No pricing data available for this offering');
|
||||
}
|
||||
|
||||
// Extract addons data from the plans - addons are embedded in each plan
|
||||
this.extractAddonsData();
|
||||
|
||||
|
|
|
|||
|
|
@ -89,18 +89,18 @@ class UIManager {
|
|||
const managedServiceIncludesContainer = domManager.get('managedServiceIncludesContainer');
|
||||
const managedServiceIncludes = domManager.get('managedServiceIncludes');
|
||||
const managedServiceToggleButton = domManager.get('managedServiceToggleButton');
|
||||
|
||||
|
||||
if (managedServiceIncludesContainer) {
|
||||
// Clear existing content
|
||||
managedServiceIncludesContainer.innerHTML = '';
|
||||
|
||||
// Show/hide the entire managed service includes section based on mandatory addons
|
||||
const hasMandatoryAddons = mandatoryAddons && mandatoryAddons.length > 0;
|
||||
|
||||
|
||||
if (managedServiceIncludes) {
|
||||
managedServiceIncludes.style.display = hasMandatoryAddons ? 'block' : 'none';
|
||||
}
|
||||
|
||||
|
||||
if (managedServiceToggleButton) {
|
||||
managedServiceToggleButton.style.display = hasMandatoryAddons ? 'inline-block' : 'none';
|
||||
}
|
||||
|
|
@ -218,7 +218,7 @@ class UIManager {
|
|||
|
||||
// Update the serviceLevelInputs reference
|
||||
domManager.elements.serviceLevelInputs = document.querySelectorAll('input[name="serviceLevel"]');
|
||||
|
||||
|
||||
// Set up event listeners for the dynamically created service level inputs
|
||||
this.setupServiceLevelEventListeners(domManager, pricingDataManager);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue