mpchil's picture
**Role:** Act as a Senior Full-Stack Developer and Data Engineer.
00d2b79 verified
Raw
History Blame Contribute Delete
9.19 kB
// Simulated vendor configuration data
const vendorConfig = [
{"Vendor_Carrier": "Lenovo", "Method": "Pallet", "CUSTPONBR": "Customer PO", "SKU": "Product ID", "SHIPQTY": "Product Quantity", "PACKAGEID": "Pallet ID"},
{"Vendor_Carrier": "HP", "Method": "Pallet", "CUSTPONBR": "PO", "SKU": "VPN", "SHIPQTY": "UNITS", "PACKAGEID": "PACKAHE"},
{"Vendor_Carrier": "Microsoft", "Method": "VPN", "CUSTPONBR": "PONum", "SKU": "PARTID", "SHIPQTY": "SHPQTY", "PACKAGEID": "PARTID"}
];
// DOM Elements
const vendorSelect = document.getElementById('vendor-select');
const fileInput = document.getElementById('file-input');
const dropZone = document.getElementById('drop-zone');
const fileInfo = document.getElementById('file-info');
const fileName = document.getElementById('file-name');
const processBtn = document.getElementById('process-btn');
const resultsContainer = document.getElementById('results-container');
const errorContainer = document.getElementById('error-container');
const errorMessage = document.getElementById('error-message');
const jobInfo = document.getElementById('job-info');
const timestampEl = document.getElementById('timestamp');
const headerRowEl = document.getElementById('header-row');
const columnIndicesEl = document.getElementById('column-indices');
const resultsTableBody = document.querySelector('#results-table tbody');
const downloadBtn = document.getElementById('download-btn');
let currentFile = null;
let transformedData = [];
// Initialize vendor dropdown
function initVendorDropdown() {
vendorConfig.forEach(vendor => {
const option = document.createElement('option');
option.value = vendor.Vendor_Carrier;
option.textContent = vendor.Vendor_Carrier;
vendorSelect.appendChild(option);
});
}
// Handle file selection
function handleFileSelection(file) {
if (!file) return;
const validTypes = ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-excel',
'text/csv',
'text/plain'];
if (!validTypes.includes(file.type)) {
showError('Invalid file type. Please upload an Excel or CSV file.');
return;
}
currentFile = file;
fileName.textContent = file.name;
fileInfo.classList.remove('hidden');
processBtn.disabled = false;
}
// Drag and drop handlers
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
['dragenter', 'dragover'].forEach(eventName => {
dropZone.addEventListener(eventName, highlight, false);
});
['dragleave', 'drop'].forEach(eventName => {
dropZone.addEventListener(eventName, unhighlight, false);
});
function highlight() {
dropZone.classList.add('dragover');
}
function unhighlight() {
dropZone.classList.remove('dragover');
}
dropZone.addEventListener('drop', handleDrop, false);
function handleDrop(e) {
const dt = e.dataTransfer;
const file = dt.files[0];
handleFileSelection(file);
}
// Click on drop zone triggers file input
dropZone.addEventListener('click', () => {
fileInput.click();
});
fileInput.addEventListener('change', (e) => {
handleFileSelection(e.target.files[0]);
});
// Process file button handler
processBtn.addEventListener('click', processFile);
// Download CSV handler
downloadBtn.addEventListener('click', downloadCSV);
// Initialize the app
initVendorDropdown();
// Main processing function
async function processFile() {
if (!currentFile || !vendorSelect.value) {
showError('Please select a vendor and upload a file.');
return;
}
// Show loading state
processBtn.disabled = true;
processBtn.innerHTML = '<i data-feather="loader" class="mr-2 animate-spin"></i>Processing...';
feather.replace();
try {
// In a real app, this would be an API call to the backend
// For this demo, we'll simulate the processing
await new Promise(resolve => setTimeout(resolve, 1500));
// Get selected vendor config
const vendor = vendorConfig.find(v => v.Vendor_Carrier === vendorSelect.value);
if (!vendor) throw new Error('Vendor configuration not found');
// Simulate data transformation
const result = simulateDataTransformation(vendor);
// Display results
displayResults(result.data, result.jobInfo);
} catch (error) {
showError(error.message);
} finally {
processBtn.disabled = false;
processBtn.innerHTML = '<i data-feather="play" class="mr-2"></i>Process File';
feather.replace();
}
}
// Simulate data transformation (in a real app, this would be server-side)
function simulateDataTransformation(vendorConfig) {
// Build mapping dictionary
const mapping = {};
const requiredHeaders = [];
['CUSTPONBR', 'SKU', 'SHIPQTY', 'PACKAGEID'].forEach(internal => {
const external = vendorConfig[internal];
if (external && external.trim() !== '') {
mapping[external] = internal;
requiredHeaders.push(external);
}
});
// Simulate finding header row (in a real app, this would parse the file)
const headerRowIndex = Math.floor(Math.random() * 3); // Random row 0-2
// Validate headers (simulated)
const missingHeaders = [];
const foundHeaders = Object.keys(mapping);
requiredHeaders.forEach(header => {
if (!foundHeaders.includes(header)) {
missingHeaders.push(header);
}
});
if (missingHeaders.length > 0) {
throw new Error(`Missing required headers: ${missingHeaders.join(', ')}`);
}
// Simulate transformed data
const data = [];
const rowCount = 5 + Math.floor(Math.random() * 10);
for (let i = 0; i < rowCount; i++) {
data.push({
CUSTPONBR: `PO-${Math.floor(Math.random() * 10000)}`,
SKU: `SKU-${Math.floor(Math.random() * 1000)}`,
SHIPQTY: Math.floor(Math.random() * 100),
PACKAGEID: `PKG-${Math.floor(Math.random() * 100)}`
});
}
// Generate job info
const now = new Date();
const jobInfo = {
timestamp: now.toISOString().replace('T', ' ').substring(0, 19),
headerRow: headerRowIndex,
columnIndices: generateColumnIndices(Object.keys(mapping).length)
};
return { data, jobInfo };
}
// Generate fake column indices (A, B, C, etc.)
function generateColumnIndices(count) {
const indices = [];
for (let i = 0; i < count; i++) {
indices.push(String.fromCharCode(65 + i)); // ASCII 'A' is 65
}
return indices.join(', ');
}
// Display results in the table
function displayResults(data, jobInfoData) {
// Clear previous results
resultsTableBody.innerHTML = '';
// Populate table with data
transformedData = data;
data.forEach(row => {
const tr = document.createElement('tr');
tr.innerHTML = `
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${row.CUSTPONBR}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${row.SKU}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${row.SHIPQTY}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${row.PACKAGEID}</td>
`;
resultsTableBody.appendChild(tr);
});
// Update job info
timestampEl.textContent = jobInfoData.timestamp;
headerRowEl.textContent = jobInfoData.headerRow;
columnIndicesEl.textContent = jobInfoData.columnIndices;
// Show results and job info
resultsContainer.classList.remove('hidden');
jobInfo.classList.remove('hidden');
// Hide error if visible
errorContainer.classList.add('hidden');
// Scroll to results
resultsContainer.scrollIntoView({ behavior: 'smooth' });
}
// Show error message
function showError(message) {
errorMessage.innerHTML = `<p>${message}</p>`;
errorContainer.classList.remove('hidden');
resultsContainer.classList.add('hidden');
jobInfo.classList.add('hidden');
// Scroll to error
errorContainer.scrollIntoView({ behavior: 'smooth' });
}
// Download CSV
function downloadCSV() {
if (transformedData.length === 0) return;
// Create CSV content
let csvContent = "CUSTPONBR,SKU,SHIPQTY,PACKAGEID\n";
transformedData.forEach(row => {
csvContent += `${row.CUSTPONBR},${row.SKU},${row.SHIPQTY},${row.PACKAGEID}\n`;
});
// Create download link
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.setAttribute('href', url);
link.setAttribute('download', `transformed_data_${new Date().toISOString().slice(0, 10)}.csv`);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}