Deal Stage Dashboard

Deal Stage Dashboard

Deal Overview

All Deals

Deal Name Stage Value ($) Close Date Notes Actions

${winRate.toFixed(2)}%

`; // Order of stages for display const orderedStages = ['Prospecting', 'Qualification', 'Proposal', 'Negotiation', 'Closed Won', 'Closed Lost']; orderedStages.forEach(stage => { const data = stageSummary[stage] || { count: 0, totalValue: 0 }; const valueFormatted = data.totalValue.toLocaleString('en-US', { style: 'currency', currency: 'USD' }); summaryHtml += `

${stage}

${data.count} Deals

Value: ${valueFormatted}

`; }); dealSummaryDiv.innerHTML = summaryHtml; } /** * Renders the table of all deals. */ function renderDealsTable() { if (!dealsTableBody) return; // Null check dealsTableBody.innerHTML = ''; // Clear existing rows deals.forEach(deal => { const row = dealsTableBody.insertRow(); row.innerHTML = ` ${deal.dealName} ${deal.stage} ${deal.value.toLocaleString('en-US', { style: 'currency', currency: 'USD' })} ${deal.closeDate || 'N/A'} ${deal.notes || 'N/A'} `; }); } /** * Renders the entire dashboard content. */ function renderDashboard() { renderDealSummary(); renderDealsTable(); } // --- Data Configuration Logic --- /** * Generates a unique ID for a new deal. * @returns {string} A unique ID. */ function generateUniqueId() { return 'd' + Date.now() + Math.floor(Math.random() * 1000); } // Add Deal Form Submission if (addDealForm) { addDealForm.addEventListener('submit', function(event) { event.preventDefault(); // Prevent default form submission const newDeal = { id: generateUniqueId(), dealName: document.getElementById('dealName').value, stage: document.getElementById('dealStage').value, value: parseFloat(document.getElementById('dealValue').value), closeDate: document.getElementById('dealCloseDate').value, notes: document.getElementById('dealNotes').value }; deals.push(newDeal); // Add new deal to the array renderDashboard(); // Re-render dashboard with new data addDealForm.reset(); // Clear the form switchTab('dashboard'); // Switch back to dashboard to see changes }); } // --- Edit Deal Modal Logic --- /** * Opens the edit modal and populates it with deal data. * @param {string} id - The ID of the deal to edit. */ window.openEditModal = function(id) { const dealToEdit = deals.find(deal => deal.id === id); if (!dealToEdit || !editDealModal || !editDealForm) return; // Null check document.getElementById('editDealId').value = dealToEdit.id; document.getElementById('editDealName').value = dealToEdit.dealName; document.getElementById('editDealStage').value = dealToEdit.stage; document.getElementById('editDealValue').value = dealToEdit.value; document.getElementById('editDealCloseDate').value = dealToEdit.closeDate; document.getElementById('editDealNotes').value = dealToEdit.notes; editDealModal.style.display = 'flex'; // Show the modal }; /** * Closes the specified modal. * @param {string} modalId - The ID of the modal to close. */ window.closeModal = function(modalId) { const modal = document.getElementById(modalId); if (modal) { modal.style.display = 'none'; } }; // Close modal when clicking outside of it window.onclick = function(event) { if (event.target === editDealModal) { closeModal('editDealModal'); } }; // Edit Deal Form Submission if (editDealForm) { editDealForm.addEventListener('submit', function(event) { event.preventDefault(); // Prevent default form submission const updatedDealId = document.getElementById('editDealId').value; const dealIndex = deals.findIndex(deal => deal.id === updatedDealId); if (dealIndex > -1) { deals[dealIndex] = { id: updatedDealId, dealName: document.getElementById('editDealName').value, stage: document.getElementById('editDealStage').value, value: parseFloat(document.getElementById('editDealValue').value), closeDate: document.getElementById('editDealCloseDate').value, notes: document.getElementById('editDealNotes').value }; renderDashboard(); // Re-render dashboard with updated data closeModal('editDealModal'); // Close the modal } else { console.error('Deal not found for update:', updatedDealId); } }); } /** * Deletes a deal from the array. * @param {string} id - The ID of the deal to delete. */ window.deleteDeal = function(id) { // Using a custom message box instead of alert/confirm const confirmDelete = window.confirm('Are you sure you want to delete this deal?'); if (confirmDelete) { deals = deals.filter(deal => deal.id !== id); renderDashboard(); // Re-render dashboard } }; // --- PDF Download Logic --- /** * Downloads the dashboard content as a PDF. */ if (downloadPdfBtn) { downloadPdfBtn.addEventListener('click', function() { const input = document.getElementById('dashboardTabContent'); // Target the dashboard content if (!input) { console.error('Dashboard content element not found for PDF generation.'); return; } // Temporarily hide elements that should not be in the PDF const elementsToHide = input.querySelectorAll('.no-print'); elementsToHide.forEach(el => el.style.display = 'none'); // Use html2canvas to capture the content as an image html2canvas(input, { scale: 2, // Increase scale for better quality useCORS: true, // Needed if external images are used (not in this case, but good practice) logging: false // Disable logging for cleaner console }).then(canvas => { const imgData = canvas.toDataURL('image/png'); const pdf = new window.jspdf.jsPDF('p', 'mm', 'a4'); // 'p' for portrait, 'mm' for units, 'a4' for size const imgWidth = 210; // A4 width in mm const pageHeight = 297; // A4 height in mm const imgHeight = canvas.height * imgWidth / canvas.width; let heightLeft = imgHeight; let position = 0; // Add image to PDF pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight); heightLeft -= pageHeight; // If content spans multiple pages, add new pages while (heightLeft >= 0) { position = heightLeft - imgHeight; pdf.addPage(); pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight); heightLeft -= pageHeight; } pdf.save('Deal_Stage_Dashboard.pdf'); // Restore visibility of hidden elements elementsToHide.forEach(el => el.style.display = ''); }).catch(error => { console.error('Error generating PDF:', error); // Restore visibility of hidden elements in case of error elementsToHide.forEach(el => el.style.display = ''); }); }); } // Initial render of the dashboard when the page loads renderDashboard(); });
Scroll to Top