Mobile Commerce Dashboard

Mobile Commerce Dashboard

Mobile Commerce Overview

Transaction Details

Order ID Product Name Quantity Price ($) Total ($) Device Type Transaction Date Customer Location

Configure Your Commerce Data

Manually input or edit your mobile commerce transaction data below. All changes will automatically update the dashboard.

Order ID Product Name Quantity Price ($) Device Type Transaction Date Customer Location Actions

${overallMetrics.totalOrders.toLocaleString()}

Total Sales

${formatCurrency(overallMetrics.totalSales)}

Average Order Value

${formatCurrency(overallMetrics.averageOrderValue)}

Mobile Sales Share

${formatPercentage(overallMetrics.mobileSalesShare)}

Desktop Sales Share

${formatPercentage(overallMetrics.desktopSalesShare)}

Tablet Sales Share

${formatPercentage(overallMetrics.tabletSalesShare)}

`; } /** * Renders the transaction details table in the Dashboard tab. */ function renderTransactionDetailsTable() { // Null check for the transaction details table body if (!transactionDetailsTableBody) { console.error("Transaction details table body not found."); return; } transactionDetailsTableBody.innerHTML = ''; // Clear existing rows commerceData.forEach(transaction => { const total = calculateItemTotal(transaction); const row = document.createElement('tr'); row.innerHTML = ` ${transaction.orderId} ${transaction.productName} ${transaction.quantity.toLocaleString()} ${formatCurrency(transaction.price)} ${formatCurrency(total)} ${transaction.deviceType} ${transaction.transactionDate || 'N/A'} ${transaction.customerLocation || 'N/A'} `; transactionDetailsTableBody.appendChild(row); }); } /** * Renders the data input table in the Data Configuration tab. */ function renderDataInputTable() { // Null check for the data input table body if (!dataInputTableBody) { console.error("Data input table body not found."); return; } dataInputTableBody.innerHTML = ''; // Clear existing rows commerceData.forEach(transaction => { const row = document.createElement('tr'); row.innerHTML = ` `; dataInputTableBody.appendChild(row); }); // Attach event listeners to newly created input fields and delete buttons document.querySelectorAll('.transaction-input').forEach(input => { input.addEventListener('change', handleInputChange); }); document.querySelectorAll('.delete-row-btn').forEach(button => { button.addEventListener('click', handleDeleteRow); }); } /** * Updates all dashboard and data configuration views. */ function updateViews() { renderCommerceSummary(); renderTransactionDetailsTable(); renderDataInputTable(); } // --- Event Handlers --- /** * Handles tab button clicks to switch between tabs. * @param {Event} event - The click event. */ function handleTabClick(event) { // Null check for event target if (!event.target) { console.error("Event target is null."); return; } const targetTab = event.target.dataset.tab; // Remove 'active' class from all tab buttons and content tabButtons.forEach(button => button.classList.remove('active')); tabContents.forEach(content => content.classList.remove('active')); // Add 'active' class to the clicked tab button and corresponding content event.target.classList.add('active'); const activeTabContent = document.getElementById(`${targetTab}-tab`); if (activeTabContent) { // Null check for activeTabContent activeTabContent.classList.add('active'); } else { console.error(`Tab content for ${targetTab} not found.`); } updateViews(); // Update views whenever tab changes } /** * Handles changes in data input fields. * @param {Event} event - The change event. */ function handleInputChange(event) { // Null check for event target if (!event.target) { console.error("Event target is null."); return; } const input = event.target; const id = parseInt(input.dataset.id); const field = input.dataset.field; let value = input.value; // Convert numeric fields to numbers and apply constraints if (['quantity', 'price'].includes(field)) { value = parseFloat(value) || 0; // Default to 0 if parsing fails if (value < 0) value = 0; // Ensure non-negative values input.value = value; // Update input field with sanitized value } const transactionIndex = commerceData.findIndex(d => d.id === id); if (transactionIndex !== -1) { commerceData[transactionIndex][field] = value; updateViews(); // Re-render dashboard and data input tables } else { console.error(`Transaction with ID ${id} not found.`); } } /** * Adds a new empty row to the data input table. */ function handleAddTransaction() { const newTransaction = { id: nextId++, orderId: `ORD-${String(nextId - 1).padStart(3, '0')}-MOB`, productName: 'New Product', quantity: 1, price: 0.00, deviceType: 'Mobile', transactionDate: new Date().toISOString().slice(0, 10), // Default to today's date customerLocation: 'USA' }; commerceData.push(newTransaction); updateViews(); // Re-render data input table } /** * Deletes a row from the data input table. * @param {Event} event - The click event. */ function handleDeleteRow(event) { // Null check for event target if (!event.target) { console.error("Event target is null."); return; } const idToDelete = parseInt(event.target.dataset.id); commerceData = commerceData.filter(d => d.id !== idToDelete); updateViews(); // Re-render data input table } /** * Handles navigation to the previous tab. */ function handlePrevTab() { const currentActiveTab = document.querySelector('.tab-button.active'); if (!currentActiveTab) { console.error("No active tab found."); return; } const currentIndex = Array.from(tabButtons).indexOf(currentActiveTab); if (currentIndex > 0) { tabButtons[currentIndex - 1].click(); // Simulate click on previous tab } } /** * Handles navigation to the next tab. */ function handleNextTab() { const currentActiveTab = document.querySelector('.tab-button.active'); if (!currentActiveTab) { console.error("No active tab found."); return; } const currentIndex = Array.from(tabButtons).indexOf(currentActiveTab); if (currentIndex < tabButtons.length - 1) { tabButtons[currentIndex + 1].click(); // Simulate click on next tab } } /** * Handles the PDF download functionality. * It uses html2canvas to capture the dashboard content and jsPDF to generate the PDF. */ async function handleDownloadPdf() { const dashboardContent = document.querySelector('.dashboard-content-for-pdf'); if (!dashboardContent) { console.error("Dashboard content for PDF not found."); return; } // Add a temporary title for the PDF const tempTitle = document.createElement('h1'); tempTitle.textContent = "Mobile Commerce Dashboard"; tempTitle.style.textAlign = 'center'; tempTitle.style.marginBottom = '20px'; tempTitle.style.fontSize = '2em'; tempTitle.style.fontWeight = 'bold'; tempTitle.style.color = '#333'; dashboardContent.prepend(tempTitle); // Prepend to capture // Temporarily hide tab navigation and buttons for PDF capture const elementsToHide = document.querySelectorAll('.tab-nav, .tab-navigation-buttons, .add-row-btn, .delete-row-btn, .pdf-download-section .btn-primary'); elementsToHide.forEach(el => el.style.display = 'none'); // Ensure the dashboard tab is active before capturing for PDF const dashboardTabButton = document.querySelector('.tab-button[data-tab="dashboard"]'); if (dashboardTabButton && !dashboardTabButton.classList.contains('active')) { dashboardTabButton.click(); // Activate dashboard tab if not already active // A small delay might be needed here if content takes time to render after tab switch await new Promise(resolve => setTimeout(resolve, 100)); } try { const canvas = await html2canvas(dashboardContent, { scale: 2, // Increase scale for better resolution useCORS: true, // Required if images are from different origin (though we don't use external images) windowWidth: dashboardContent.scrollWidth, windowHeight: dashboardContent.scrollHeight }); const imgData = canvas.toDataURL('image/png'); const { jsPDF } = window.jspdf; const pdf = new jsPDF({ orientation: 'landscape', // Landscape for wider tables unit: 'px', format: 'a4' }); const imgWidth = pdf.internal.pageSize.getWidth(); const pageHeight = pdf.internal.pageSize.getHeight(); const imgHeight = canvas.height * imgWidth / canvas.width; let heightLeft = imgHeight; let position = 0; pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight); heightLeft -= pageHeight; while (heightLeft >= 0) { position = heightLeft - imgHeight; pdf.addPage(); pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight); heightLeft -= pageHeight; } pdf.save('mobile_commerce_dashboard.pdf'); } catch (error) { console.error("Error generating PDF:", error); // Using alert as a fallback for critical error feedback, as per standard specification alert("Failed to generate PDF. Please try again."); } finally { // Restore hidden elements and remove temporary title elementsToHide.forEach(el => el.style.display = ''); if (tempTitle.parentNode) { tempTitle.parentNode.removeChild(tempTitle); } } } // --- Event Listener Attachments --- tabButtons.forEach(button => { // Null check for button if (button) { button.addEventListener('click', handleTabClick); } }); // Null checks before attaching listeners if (addTransactionBtn) { addTransactionBtn.addEventListener('click', handleAddTransaction); } else { console.error("Add Transaction button not found."); } if (downloadPdfBtn) { downloadPdfBtn.addEventListener('click', handleDownloadPdf); } else { console.error("Download PDF button not found."); } if (prevTabBtn) { prevTabBtn.addEventListener('click', handlePrevTab); } else { console.error("Previous Tab button not found."); } if (nextTabBtn) { nextTabBtn.addEventListener('click', handleNextTab); } else { console.error("Next Tab button not found."); } // Initial render of the dashboard and data input table updateViews(); });
Scroll to Top