Real-Time Supplier & Product Matching System

Real-Time Supplier & Product Matching System

Find the best suppliers based on your specific product needs.

Product Requirements

Comma-separated values.

Top Supplier Matches

Enter your requirements to see matched suppliers.

Est. Cost

$${s.cost.toFixed(2)}

Match Score

${s.score}

`).join(''); }; const renderSupplierConfig = () => { supplierTableBody.innerHTML = state.suppliers.map(s => ` ${s.name} ${s.category} $${s.cost.toFixed(2)} ${s.rating}/5 `).join(''); }; // --- INITIALIZATION & EVENT HANDLERS --- function initialize() { loadInitialData(); const populateSelect = (el, options) => { el.innerHTML = options.map(o => ``).join(''); }; populateSelect(reqCategory, state.categories); populateSelect(supplierCategory, state.categories); matchingForm.addEventListener('submit', (e) => { e.preventDefault(); state.requirements = { category: reqCategory.value, cost: parseFloat(reqCost.value) || 0, keywords: reqKeywords.value }; runMatching(); renderResults(); }); supplierForm.addEventListener('submit', handleSupplierSubmit); cancelEditBtn.addEventListener('click', resetSupplierForm); supplierTableBody.addEventListener('click', handleTableClick); downloadPdfBtn.addEventListener('click', generatePdf); render(); } function handleSupplierSubmit(e) { e.preventDefault(); const supplier = { id: state.editingSupplierId || Date.now(), name: supplierName.value, category: supplierCategory.value, cost: parseFloat(supplierCost.value), rating: parseFloat(supplierRating.value), keywords: supplierKeywords.value }; if(state.editingSupplierId) { state.suppliers = state.suppliers.map(s => s.id === supplier.id ? supplier : s); } else { state.suppliers.push(supplier); } resetSupplierForm(); render(); } function handleTableClick(e) { const row = e.target.closest('tr'); if (!row) return; const id = parseInt(row.dataset.id); if (e.target.classList.contains('edit-btn')) { const s = state.suppliers.find(s => s.id === id); if(!s) return; state.editingSupplierId = id; supplierId.value = s.id; supplierName.value = s.name; supplierCategory.value = s.category; supplierCost.value = s.cost; supplierRating.value = s.rating; supplierKeywords.value = s.keywords; supplierFormTitle.textContent = "Edit Supplier"; submitSupplierBtn.textContent = "Update Supplier"; cancelEditBtn.classList.remove('hidden'); } else if (e.target.classList.contains('delete-btn')) { state.suppliers = state.suppliers.filter(s => s.id !== id); render(); } } function resetSupplierForm() { supplierForm.reset(); state.editingSupplierId = null; supplierFormTitle.textContent = "Add New Supplier"; submitSupplierBtn.textContent = "Add Supplier"; cancelEditBtn.classList.add('hidden'); } // --- TAB NAVIGATION --- const switchTab = (tabName) => { state.currentTab = tabName; Object.values(tabButtons).forEach(b => b.classList.remove('active')); Object.values(tabContents).forEach(c => c.classList.add('hidden')); if(tabButtons[tabName]) tabButtons[tabName].classList.add('active'); if(tabContents[tabName]) tabContents[tabName].classList.remove('hidden'); updateNavButtons(); }; const updateNavButtons = () => { prevBtn.disabled = state.currentTab === 'dashboard'; prevBtn.classList.toggle('opacity-50', prevBtn.disabled); nextBtn.disabled = state.currentTab === 'config'; nextBtn.classList.toggle('opacity-50', nextBtn.disabled); }; Object.keys(tabButtons).forEach(k => tabButtons[k]?.addEventListener('click', () => switchTab(k))); nextBtn.addEventListener('click', () => { if (state.currentTab === 'dashboard') switchTab('config'); }); prevBtn.addEventListener('click', () => { if (state.currentTab === 'config') switchTab('dashboard'); }); // --- PDF GENERATION --- async function generatePdf() { if (!state.requirements || state.results.length === 0) return; const { jsPDF } = window.jspdf; document.getElementById('report-date').textContent = `Generated: ${new Date().toLocaleDateString()}`; document.getElementById('pdf-category').textContent = state.requirements.category; document.getElementById('pdf-cost').textContent = `$${state.requirements.cost.toFixed(2)}`; document.getElementById('pdf-keywords').textContent = state.requirements.keywords || 'N/A'; document.getElementById('pdf-results-list').innerHTML = state.results.map(s => `

${s.name} (Score: ${s.score})

Category: ${s.category} | Est. Cost: $${s.cost.toFixed(2)} | Rating: ${s.rating}/5

Keywords: ${s.keywords}

`).join(''); const pdfContainer = document.getElementById('pdf-container'); pdfContainer.classList.remove('invisible', '-left-[9999px]'); try { const canvas = await html2canvas(document.getElementById('pdf-report'), { scale: 2 }); const imgData = canvas.toDataURL('image/jpeg', 0.9); const pdf = new jsPDF({ orientation: 'p', unit: 'px', format: [canvas.width, canvas.height] }); pdf.addImage(imgData, 'JPEG', 0, 0, canvas.width, canvas.height); pdf.save('Supplier_Match_Report.pdf'); } catch (error) { console.error("PDF generation failed:", error); } finally { pdfContainer.classList.add('invisible', '-left-[9999px]'); } } initialize(); });
Scroll to Top