Cross-Border Shipping Dashboard

Cross-Border Shipping Dashboard

Analyzing International Logistics and Delivery Performance

Total Shipments

0

Avg. Shipping Cost

$0

Avg. Delivery Time

0 Days

Shipments by Destination

Customs Status

Shipment ID: ${s.id}

`; elements.shippingConfigContainer.appendChild(shipmentEl); }); } // --- EVENT HANDLERS --- // function handleConfigChange(e) { if (!e.target.classList.contains('shipment-input')) return; const target = e.target; const id = parseInt(target.dataset.id); const field = target.dataset.field; const value = target.type === 'number' ? parseFloat(target.value) || 0 : target.value; const shipment = shippingData.shipments.find(s => s.id === id); if (shipment) { shipment[field] = value; updateDashboardUI(); } } function handleAddShipment() { const newId = shippingData.shipments.length > 0 ? Math.max(...shippingData.shipments.map(s => s.id)) + 1 : 1; const today = new Date().toISOString().slice(0,10); shippingData.shipments.unshift({ id: newId, destination: 'New Destination', carrier: 'UPS', cost: 0, shipDate: today, deliveryDate: '', customsStatus: 'In Progress' }); populateConfigForm(); updateDashboardUI(); } function handleRemoveShipment(e) { if (!e.target.classList.contains('remove-shipment-btn')) return; const id = parseInt(e.target.dataset.id); shippingData.shipments = shippingData.shipments.filter(s => s.id !== id); populateConfigForm(); updateDashboardUI(); } async function handlePdfDownload() { if (typeof html2canvas === 'undefined' || typeof window.jspdf === 'undefined') return; const { jsPDF } = window.jspdf; const pdfExportElement = elements.pdfExportArea; if (!pdfExportElement) return; const originalBg = pdfExportElement.style.backgroundColor; pdfExportElement.style.backgroundColor = 'white'; try { const canvas = await html2canvas(pdfExportElement, { scale: 2, useCORS: true, logging: false }); pdfExportElement.style.backgroundColor = originalBg; const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'landscape', unit: 'px', format: [canvas.width, canvas.height] }); pdf.addImage(imgData, 'PNG', 0, 0, canvas.width, canvas.height); pdf.save('Cross-Border-Shipping-Dashboard.pdf'); } catch (error) { console.error("Error generating PDF:", error); pdfExportElement.style.backgroundColor = originalBg; } } // --- INITIALIZATION --- // if (elements.shippingConfigContainer) { elements.shippingConfigContainer.addEventListener('input', handleConfigChange); elements.shippingConfigContainer.addEventListener('click', handleRemoveShipment); } if (elements.addShipmentBtn) { elements.addShipmentBtn.addEventListener('click', handleAddShipment); } if (elements.downloadPdfBtn) { elements.downloadPdfBtn.addEventListener('click', handlePdfDownload); } updateDashboardUI(); populateConfigForm(); window.updateNavButtons(); }); // --- GLOBAL FUNCTIONS FOR TAB NAVIGATION --- // function switchTab(tabName) { const tabDashboard = document.getElementById('tab-panel-dashboard'); const tabConfig = document.getElementById('tab-panel-config'); const btnDashboard = document.getElementById('tab-btn-dashboard'); const btnConfig = document.getElementById('tab-btn-config'); if (!tabDashboard || !tabConfig || !btnDashboard || !btnConfig) return; const isDashboard = tabName === 'dashboard'; tabDashboard.classList.toggle('hidden', !isDashboard); tabConfig.classList.toggle('hidden', isDashboard); btnDashboard.classList.toggle('active', isDashboard); btnConfig.classList.toggle('active', !isDashboard); updateNavButtons(); } function updateNavButtons() { const btnDashboard = document.getElementById('tab-btn-dashboard'); const prevBtn = document.getElementById('prev-btn'); const nextBtn = document.getElementById('next-btn'); if (!btnDashboard || !prevBtn || !nextBtn) return; const isDashboardActive = btnDashboard.classList.contains('active'); prevBtn.disabled = isDashboardActive; nextBtn.disabled = !isDashboardActive; prevBtn.classList.toggle('opacity-50', isDashboardActive); prevBtn.classList.toggle('cursor-not-allowed', isDashboardActive); nextBtn.classList.toggle('opacity-50', !isDashboardActive); nextBtn.classList.toggle('cursor-not-allowed', !isDashboardActive); } function navigateTabs(direction) { const isDashboardActive = document.getElementById('tab-btn-dashboard').classList.contains('active'); if (direction === 'next' && isDashboardActive) { switchTab('config'); } else if (direction === 'prev' && !isDashboardActive) { switchTab('dashboard'); } }
Scroll to Top