diff --git a/hub/services/static/js/price-calculator/price-calculator.js b/hub/services/static/js/price-calculator/price-calculator.js index 34ee6c1..156e6cc 100644 --- a/hub/services/static/js/price-calculator/price-calculator.js +++ b/hub/services/static/js/price-calculator/price-calculator.js @@ -88,6 +88,9 @@ class PriceCalculator { // Initialize instances slider this.uiManager.updateInstancesSlider(this.domManager, this.pricingDataManager); + + // Setup service level event listeners after UI is created + this.setupServiceLevelEventListeners(); } // Setup event listeners for calculator controls @@ -166,20 +169,81 @@ class PriceCalculator { window.addEventListener('addon-changed', () => { this.updatePricing(); }); + } + // Setup service level event listeners (called after UI setup) + setupServiceLevelEventListeners() { // Service level change listener const serviceLevelInputs = this.domManager.get('serviceLevelInputs'); + if (serviceLevelInputs) { - serviceLevelInputs.forEach(input => { + serviceLevelInputs.forEach((input, index) => { input.addEventListener('change', () => { - // Update plan dropdown for new service level - this.planManager.populatePlanDropdown(this.domManager); + try { + // Check if a plan is currently selected before updating + const planSelect = this.domManager.get('planSelect'); + const currentlySelectedPlan = planSelect?.value ? JSON.parse(planSelect.value) : null; - // Update addons for new service level - this.addonManager.updateAddons(this.domManager); + // Update instances slider for the new service level (functionality from UIManager) + this.uiManager.updateInstancesSlider(this.domManager, this.pricingDataManager); - // Update pricing - this.updatePricing(); + // Update plan dropdown for new service level + this.planManager.populatePlanDropdown(this.domManager); + + // Update addons for new service level first + this.addonManager.updateAddons(this.domManager); + + // If a plan was previously selected, try to maintain selection + if (currentlySelectedPlan && planSelect) { + // Find the same plan in the new dropdown options + const options = planSelect.querySelectorAll('option'); + let planFound = false; + let matchingPlan = null; + + for (const option of options) { + if (option.value) { + try { + const optionPlan = JSON.parse(option.value); + + // First, try to match by exact plan name + if (optionPlan.compute_plan === currentlySelectedPlan.compute_plan) { + matchingPlan = optionPlan; + planFound = true; + break; + } + } catch (e) { + console.warn('Error parsing plan option:', e); + } + } + } + + if (planFound && matchingPlan) { + // Set the plan selection + planSelect.value = JSON.stringify(matchingPlan); + + // Maintain the UI state for manually selected plan + this.planManager.updateSlidersForPlan(matchingPlan, this.domManager); + this.uiManager.fadeOutSliders(this.domManager, ['cpu', 'memory']); + + // Update pricing with the selected plan + this.updatePricingWithPlan(matchingPlan); + } else { + planSelect.value = ''; + // Reset sliders to smart defaults and fade them back in + this.domManager.setSmartDefaults(this.pricingDataManager); + this.uiManager.fadeInSliders(this.domManager, ['cpu', 'memory']); + // Update pricing in auto-select mode + this.updatePricing(); + } + } else { + // No plan was previously selected, just update pricing + this.updatePricing(); + } + } catch (error) { + console.error('Error in service level change handler:', error); + // Fallback to basic functionality if there's an error + this.updatePricing(); + } }); }); } @@ -301,7 +365,7 @@ class PriceCalculator { // Snap CPU to nearest available value first const { cpuValues } = this.pricingDataManager.getAvailableSliderValues(); const snappedCpu = this.findNearestValue(targetCpu, cpuValues); - + // Update CPU slider to snapped value if different if (snappedCpu !== targetCpu) { const cpuRange = this.domManager.get('cpuRange'); @@ -344,7 +408,7 @@ class PriceCalculator { if (bestPlan) { const memoryRange = this.domManager.get('memoryRange'); const memoryValue = this.domManager.get('memoryValue'); - + if (memoryRange && memoryValue) { memoryRange.value = bestPlan.ram; memoryValue.textContent = bestPlan.ram; @@ -364,7 +428,7 @@ class PriceCalculator { // Snap memory to nearest available value first const { memoryValues } = this.pricingDataManager.getAvailableSliderValues(); const snappedMemory = this.findNearestValue(targetMemory, memoryValues); - + // Update memory slider to snapped value if different if (snappedMemory !== targetMemory) { const memoryRange = this.domManager.get('memoryRange'); @@ -407,7 +471,7 @@ class PriceCalculator { if (bestPlan) { const cpuRange = this.domManager.get('cpuRange'); const cpuValue = this.domManager.get('cpuValue'); - + if (cpuRange && cpuValue) { cpuRange.value = bestPlan.vcpus; cpuValue.textContent = bestPlan.vcpus; @@ -418,10 +482,10 @@ class PriceCalculator { // Find the nearest value in an array to a target value findNearestValue(target, availableValues) { if (!availableValues || availableValues.length === 0) return target; - + let nearest = availableValues[0]; let minDifference = Math.abs(target - nearest); - + for (let i = 1; i < availableValues.length; i++) { const difference = Math.abs(target - availableValues[i]); if (difference < minDifference) { @@ -429,7 +493,7 @@ class PriceCalculator { nearest = availableValues[i]; } } - + return nearest; } } diff --git a/hub/services/static/js/price-calculator/ui-manager.js b/hub/services/static/js/price-calculator/ui-manager.js index 47ded07..5d86e3d 100644 --- a/hub/services/static/js/price-calculator/ui-manager.js +++ b/hub/services/static/js/price-calculator/ui-manager.js @@ -215,8 +215,9 @@ 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); + // Note: Event listeners are now handled in price-calculator.js setupEventListeners method + // to properly preserve plan selection when service level changes + // this.setupServiceLevelEventListeners(domManager, pricingDataManager); } // Setup event listeners for service level inputs