// static/js/mold_calculator.js // Check if script is already initialized if (window.moldCalculatorInitialized) { console.log('Mold calculator already initialized, skipping...'); } else { window.moldCalculatorInitialized = true; // Wait for DOM to be fully loaded if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initializeCalculator); } else { initializeCalculator(); } } function initializeCalculator() { console.log('DOM Content Loaded - Initializing mold calculator'); // Get form elements const form = document.getElementById('calcForm'); const mainSelect = document.getElementById('mold_main_type'); const subSelect = document.getElementById('mold_sub_type'); const specificTypeSelect = document.getElementById('mold_specific_type'); const stageSelect = document.getElementById('stage'); const typeSelect = document.getElementById('type'); const toolingIdInput = document.getElementById('tooling_id'); const submitButton = document.getElementById('calculateBtn'); console.log('Main select element:', mainSelect); console.log('Sub select element:', subSelect); console.log('Specific type select element:', specificTypeSelect); console.log('Stage select element:', stageSelect); console.log('Type select element:', typeSelect); console.log('Tooling ID input:', toolingIdInput); console.log('Submit button:', submitButton); // Check if submit button exists if (!submitButton) { console.error('Submit button not found! Looking for element with ID "calculateBtn"'); // Try alternative selectors const alternativeButton = form.querySelector('button[type="submit"]'); if (alternativeButton) { console.log('Found submit button using alternative selector:', alternativeButton); } else { console.error('No submit button found with any selector!'); return; // Exit initialization if we can't find the submit button } } // Define mappings const moldTypeMapping = { 'Rubber': ['Flat Outsole', 'Cupsole', 'Rubber Sole'], 'CMEVA': ['2 Plates Mold', '3 Plates Mold', '2 Plates with in-mold channel', 'Breathable + in-mold channel'], 'IMEVA': ['2 Plates Mold', '3 Plates Mold'], 'Sandal': ['Sandal with Upper Bandage', '2 Plate without Upper Bandage'], 'Co-shot mold': ['Co-shot mold', 'Foaming mold'], 'PU': ['2 Plates Mold', '3 Plates Mold'] }; const specificTypeOptions = { 'Flat Outsole': ['Flat', 'Flat with Top/Heel Tip'], 'Cupsole': ['Top PL', 'Visible PL'], 'Rubber Sole': ['Top PL', 'Short PL (Heel/Forefoot)', 'Visible PL', 'Wave PL'] }; const stageTypeMapping = { 'CR0': ['Sample'], 'CR1': ['Sample'], 'CR2': ['Sample'], 'SMS': ['A Set'], 'commercialization': ['A Set'], 'production': ['Additional'] }; // Function to update sub-type options function updateSubTypeOptions() { console.log('Populating sub-types'); const selectedType = mainSelect.value; console.log('Selected type:', selectedType); // Clear current options subSelect.innerHTML = ''; if (selectedType && moldTypeMapping[selectedType]) { console.log('Found mapping for type:', selectedType); const options = moldTypeMapping[selectedType]; console.log('Adding options:', options); options.forEach(option => { const opt = document.createElement('option'); opt.value = option; opt.textContent = option; subSelect.appendChild(opt); }); } // Reset specific type specificTypeSelect.innerHTML = ''; specificTypeSelect.disabled = true; } // Function to update specific type options function updateSpecificTypeOptions() { const selectedSubType = subSelect.value; console.log('Selected sub-type:', selectedSubType); // Clear current options specificTypeSelect.innerHTML = ''; if (selectedSubType && specificTypeOptions[selectedSubType]) { console.log('Found specific type options for:', selectedSubType); const options = specificTypeOptions[selectedSubType]; console.log('Adding specific type options:', options); options.forEach(option => { const opt = document.createElement('option'); opt.value = option; opt.textContent = option; specificTypeSelect.appendChild(opt); }); specificTypeSelect.disabled = false; } else { specificTypeSelect.disabled = true; } } // Function to update type options based on stage function updateTypeOptions() { const selectedStage = stageSelect.value; console.log('Selected stage:', selectedStage); // Clear current options typeSelect.innerHTML = ''; if (selectedStage && stageTypeMapping[selectedStage]) { const options = stageTypeMapping[selectedStage]; console.log('Adding type options:', options); options.forEach(option => { const opt = document.createElement('option'); opt.value = option; opt.textContent = option; typeSelect.appendChild(opt); }); // Enable the type select typeSelect.disabled = false; } else { // Disable the type select if no stage is selected typeSelect.disabled = true; } } // Add event listeners mainSelect.addEventListener('change', function() { console.log('Main type changed:', this.value); updateSubTypeOptions(); }); subSelect.addEventListener('change', function() { console.log('Sub type changed:', this.value); updateSpecificTypeOptions(); }); stageSelect.addEventListener('change', function() { console.log('Stage changed:', this.value); updateTypeOptions(); }); // Add tooling ID validation if (toolingIdInput) { console.log('Tooling ID input found, adding validation'); toolingIdInput.addEventListener('input', function(e) { console.log('Tooling ID input event triggered, value:', this.value); // Remove any non-numeric characters let value = this.value.replace(/\D/g, ''); // Limit to 5 digits if (value.length > 5) { value = value.substring(0, 5); } this.value = value; console.log('Tooling ID value after validation:', this.value); }); toolingIdInput.addEventListener('paste', function(e) { console.log('Tooling ID paste event triggered'); e.preventDefault(); const pastedText = (e.clipboardData || window.clipboardData).getData('text'); const numericOnly = pastedText.replace(/\D/g, '').substring(0, 5); this.value = numericOnly; console.log('Tooling ID value after paste validation:', this.value); }); } else { console.error('Tooling ID input element not found!'); // Try alternative selectors const alternativeSelectors = [ 'input[name="tooling_id"]', 'input[placeholder*="tooling"]', 'input[placeholder*="Tooling"]' ]; for (let selector of alternativeSelectors) { const element = document.querySelector(selector); if (element) { console.log('Found tooling ID input using selector:', selector, element); break; } } } // Initialize options updateSubTypeOptions(); updateTypeOptions(); // Function to reset form function resetForm(form) { console.log('Resetting form...'); // Reset all select elements to their first option const selects = form.querySelectorAll('select'); selects.forEach(select => { select.selectedIndex = 0; select.dispatchEvent(new Event('change')); }); // Reset all input elements const inputs = form.querySelectorAll('input'); inputs.forEach(input => { input.value = ''; }); // Reset all checkboxes and radio buttons const checkboxes = form.querySelectorAll('input[type="checkbox"], input[type="radio"]'); checkboxes.forEach(checkbox => { checkbox.checked = false; }); // Disable dependent dropdowns if (subSelect) subSelect.disabled = true; if (specificTypeSelect) specificTypeSelect.disabled = true; if (typeSelect) typeSelect.disabled = true; // Show reset notification const notification = document.createElement('div'); notification.className = 'alert alert-info alert-dismissible fade show mt-3'; notification.innerHTML = ` Form has been reset. You can now create a new quotation. `; form.insertBefore(notification, form.firstChild); console.log('Form reset complete'); } // Handle form submission form.addEventListener('submit', async function(e) { e.preventDefault(); console.log('Form submitted'); // Get submit button robustly let submitButton = document.getElementById('calculateBtn') || form.querySelector('button[type="submit"]'); if (!submitButton) { console.error('Submit button not found during form submission!'); alert('Error: Submit button not found. Please refresh the page and try again.'); return; } // Check if submission is already in progress if (submitButton.disabled || form.dataset.submitting === 'true') { console.log('Form submission already in progress or cooldown active, ignoring duplicate click'); return; } // Set submission state form.dataset.submitting = 'true'; // Disable submit button and show loading state submitButton.disabled = true; const originalButtonText = submitButton.innerHTML; submitButton.innerHTML = 'Calculating...'; submitButton.classList.add('btn-secondary'); submitButton.classList.remove('btn-primary'); submitButton.title = 'Please wait while calculating...'; try { // Log all form fields console.log('Form fields:'); for (let [key, value] of new FormData(form).entries()) { console.log(`${key}: ${value}`); } // Validate required fields const mainType = mainSelect.value; const subType = subSelect.value; const specificType = specificTypeSelect.value; const stage = stageSelect.value; const type = typeSelect.value; const toolingId = toolingIdInput ? toolingIdInput.value : ''; console.log('Required fields:', { mainType, subType, specificType, stage, type, toolingId }); if (!mainType) { alert('Please select a main type'); return; } if (!subType) { alert('Please select a sub type'); return; } if (!stage) { alert('Please select a stage'); return; } if (!type) { alert('Please select a type'); return; } // Validate tooling ID if (!toolingId) { alert('Please enter a Tooling ID'); return; } if (!/^\d{5}$/.test(toolingId)) { alert('Tooling ID must be exactly 5 digits'); return; } // Check if specific type is required const validSpecificTypes = specificTypeOptions[subType] || []; if (validSpecificTypes.length > 0 && !specificType) { alert('Please select a specific type'); return; } // Create form data const formData = new FormData(form); // Add CSRF token to form data const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content'); formData.append('csrf_token', csrfToken); // Remove specific type if it's not needed if (validSpecificTypes.length === 0) { formData.delete('mold_specific_type'); } // Log the final form data being sent console.log('Final form data being sent:'); for (let [key, value] of formData.entries()) { console.log(`${key}: ${value}`); } const response = await fetch('/calculate', { method: 'POST', body: formData }); console.log('Response status:', response.status); const responseText = await response.text(); console.log('Response text:', responseText); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}, body: ${responseText}`); } const data = JSON.parse(responseText); console.log('Calculation result:', data); // Get the result element const resultElement = document.getElementById('result'); // Update the result display updateResultsDisplay(data); // Save the quotation to the database try { console.log('Saving quotation to database...'); const saveResponse = await fetch('/save-quotation', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken }, body: JSON.stringify(data) }); const saveResult = await saveResponse.json(); console.log('Save result:', saveResult); if (saveResult.success) { console.log('Quotation saved successfully with ID:', saveResult.quotation_id); // Show success message const successMessage = document.createElement('div'); successMessage.className = 'alert alert-success alert-dismissible fade show'; successMessage.innerHTML = ` Quotation saved successfully! ID: ${saveResult.quotation_id} `; resultElement.insertBefore(successMessage, resultElement.firstChild); // Reset form after successful save resetForm(form); // Refresh quote history setTimeout(() => { refreshQuoteHistory(); }, 1000); } else if (saveResult.duplicate) { console.log('Duplicate submission detected:', saveResult.message); const duplicateMessage = document.createElement('div'); duplicateMessage.className = 'alert alert-warning alert-dismissible fade show'; duplicateMessage.innerHTML = ` ${saveResult.message} `; resultElement.insertBefore(duplicateMessage, resultElement.firstChild); // Reset form even on duplicate to prevent repeated attempts resetForm(form); } } catch (saveError) { console.error('Error saving quotation:', saveError); const errorMessage = document.createElement('div'); errorMessage.className = 'alert alert-danger alert-dismissible fade show'; errorMessage.innerHTML = ` Error saving quotation. Please try again later. `; resultElement.insertBefore(errorMessage, resultElement.firstChild); } } catch (error) { console.error('Error:', error); alert('An error occurred while calculating. Please check the console for details.'); } finally { // Re-enable submit button and restore original state after a delay setTimeout(() => { let submitButton = document.getElementById('calculateBtn') || form.querySelector('button[type="submit"]'); if (submitButton) { submitButton.disabled = false; submitButton.innerHTML = originalButtonText; submitButton.classList.remove('btn-secondary'); submitButton.classList.add('btn-primary'); submitButton.title = 'Calculate mold cost'; } // Reset submission state form.dataset.submitting = 'false'; }, 2000); // 2 second cooldown before allowing new submission } }); } // Function to update results display function updateResultsDisplay(data) { const resultElement = document.getElementById('result'); if (!resultElement) { console.error('Result element not found'); return; } // Format the results to match the provided screenshot const formattedResults = `
| Base Price | $${Number(data.base_price).toFixed(2)} |
| Complexity Adjustment | $${Number(data.complexity_cost).toFixed(2)} |
| Digital Texture Cost | $${Number(data.texture_cost).toFixed(2)} |
| Total Cost | $${Number(data.total_cost).toFixed(2)} |