/** * Enhanced Export Configuration JavaScript with Drag & Drop * Handles column selection, preview updates, drag & drop reordering, and preference management */ // Default column configuration const DEFAULT_COLUMN_ORDER = [ 'employee_id', // ID 'device_info', // Platform 'check_in_date', // Date 'check_in_time', // Time 'location_name', // Location Name 'status', // Action Description 'qr_address', // Event Description 'address', // Recorded Address 'location_accuracy' // Distance ]; const DEFAULT_COLUMNS = { 'employee_id': { selected: true, name: 'ID' }, 'location_name': { selected: true, name: 'Location Name' }, 'status': { selected: true, name: 'Action Description' }, 'check_in_date': { selected: true, name: 'Date' }, 'check_in_time': { selected: true, name: 'Time' }, 'qr_address': { selected: true, name: 'Event Description' }, 'address': { selected: true, name: 'Recorded Address' }, 'device_info': { selected: true, name: 'Platform' }, 'location_accuracy': { selected: true, name: 'Distance' } }; // Global variables let availableColumns = []; let sortableInstance = null; let savedColumnOrder = []; function toggleSection(sectionId) { try { const section = document.getElementById(sectionId); const icon = document.getElementById(sectionId + 'Icon'); if (!section) return; if (section.classList.contains('collapsed')) { section.classList.remove('collapsed'); if (icon) icon.classList.remove('rotated'); } else { section.classList.add('collapsed'); if (icon) icon.classList.add('rotated'); } // Save state try { const collapsedSections = JSON.parse(localStorage.getItem('collapsedSections') || '{}'); collapsedSections[sectionId] = section.classList.contains('collapsed'); localStorage.setItem('collapsedSections', JSON.stringify(collapsedSections)); } catch (e) {} } catch (error) { console.error('Error toggling section:', error); } } function restoreCollapsedState() { try { const collapsedSections = JSON.parse(localStorage.getItem('collapsedSections') || '{}'); Object.keys(collapsedSections).forEach(sectionId => { if (collapsedSections[sectionId]) { const section = document.getElementById(sectionId); const icon = document.getElementById(sectionId + 'Icon'); if (section) { section.classList.add('collapsed'); if (icon) icon.classList.add('rotated'); } } }); } catch (error) {} } // Initialize when DOM is loaded document.addEventListener('DOMContentLoaded', function() { console.log('Enhanced Export Configuration with Drag & Drop initialized'); // Initialize available columns data initializeColumnsData(); // Set up event listeners setupEventListeners(); // Load saved preferences if available loadSavedPreferences(); // Update preview on load updatePreview(); // Initialize drag & drop initializeDragDrop(); }); function initializeColumnsData() { try { // Extract column data from the form const checkboxes = document.querySelectorAll('input[name="selected_columns"]'); availableColumns = Array.from(checkboxes).map(cb => { const columnKey = cb.value; const label = cb.parentElement.querySelector('label').textContent.trim(); const nameInput = document.getElementById('name_' + columnKey); return { key: columnKey, label: label, defaultName: nameInput ? nameInput.value : label, enabled: cb.checked }; }); console.log('Initialized columns data:', availableColumns); } catch (error) { console.error('Error initializing columns data:', error); } } function setupEventListeners() { try { // Add change listeners to all column checkboxes const checkboxes = document.querySelectorAll('input[name="selected_columns"]'); checkboxes.forEach(checkbox => { checkbox.addEventListener('change', function() { toggleColumnName(this.value); updateSelectedColumnsList(); updatePreview(); // Add visual feedback const columnItem = this.closest('.column-item'); if (this.checked) { columnItem.classList.add('selected'); } else { columnItem.classList.remove('selected'); } }); }); // Add input listeners to all column name inputs const nameInputs = document.querySelectorAll('input[id^="name_"]'); nameInputs.forEach(input => { input.addEventListener('input', debounce(() => { updateSelectedColumnsList(); updatePreview(); }, 300)); }); // Form validation before submit const form = document.getElementById('exportForm'); if (form) { form.addEventListener('submit', function(e) { if (!validateForm()) { e.preventDefault(); } }); } } catch (error) { console.error('Error setting up event listeners:', error); } } function toggleColumnName(columnKey) { try { const checkbox = document.getElementById('col_' + columnKey); const nameGroup = document.getElementById('name_group_' + columnKey); if (checkbox && nameGroup) { if (checkbox.checked) { nameGroup.style.display = 'block'; nameGroup.style.opacity = '0'; setTimeout(() => { nameGroup.style.opacity = '1'; }, 10); } else { nameGroup.style.opacity = '0'; setTimeout(() => { nameGroup.style.display = 'none'; }, 300); } } } catch (error) { console.error('Error toggling column name:', error); } } function initializeDragDrop() { try { const selectedColumnsList = document.getElementById('selectedColumnsList'); if (selectedColumnsList) { sortableInstance = Sortable.create(selectedColumnsList, { animation: 200, ghostClass: 'sortable-ghost', chosenClass: 'sortable-chosen', dragClass: 'sortable-drag', handle: '.column-drag-handle', onStart: function(evt) { console.log('Drag started:', evt.oldIndex); }, onEnd: function(evt) { console.log('Drag ended:', evt.oldIndex, '->', evt.newIndex); updateColumnOrderNumbers(); updatePreview(); // Save the new order savePreferences(); } }); console.log('Drag & drop initialized successfully'); } } catch (error) { console.error('Error initializing drag & drop:', error); } } function updateSelectedColumnsList() { try { const selectedColumnsList = document.getElementById('selectedColumnsList'); const selectedColumnsSection = document.getElementById('selectedColumnsSection'); if (!selectedColumnsList || !selectedColumnsSection) return; // Get currently selected columns const selectedColumns = Array.from(document.querySelectorAll('input[name="selected_columns"]:checked')); if (selectedColumns.length === 0) { selectedColumnsSection.style.display = 'none'; return; } selectedColumnsSection.style.display = 'block'; selectedColumnsSection.classList.add('has-columns'); // Get current order if exists, otherwise use selection order let orderedColumns = []; if (savedColumnOrder.length > 0) { // Use saved order, but only include currently selected columns orderedColumns = savedColumnOrder.filter(key => selectedColumns.some(cb => cb.value === key) ); // Add any newly selected columns that weren't in saved order selectedColumns.forEach(cb => { if (!orderedColumns.includes(cb.value)) { orderedColumns.push(cb.value); } }); } else { orderedColumns = selectedColumns.map(cb => cb.value); } // Build the selected columns list HTML let listHTML = ''; orderedColumns.forEach((columnKey, index) => { const nameInput = document.getElementById('name_' + columnKey); const columnData = availableColumns.find(col => col.key === columnKey); const customName = nameInput ? nameInput.value : (columnData ? columnData.label : columnKey); listHTML += `
${columnData ? columnData.label : columnKey}
Export as: "${customName}"
${index + 1}
`; }); if (listHTML === '') { listHTML = `

Select columns above to see them here for reordering

`; } selectedColumnsList.innerHTML = listHTML; // Re-initialize sortable after updating content if (sortableInstance) { sortableInstance.destroy(); } initializeDragDrop(); console.log(`Updated selected columns list with ${orderedColumns.length} columns`); } catch (error) { console.error('Error updating selected columns list:', error); } } function updateColumnOrderNumbers() { try { const orderNumbers = document.querySelectorAll('.column-order-number'); orderNumbers.forEach((element, index) => { element.textContent = index + 1; }); } catch (error) { console.error('Error updating column order numbers:', error); } } function getCurrentColumnOrder() { try { const selectedItems = document.querySelectorAll('.selected-column-item'); return Array.from(selectedItems).map(item => item.dataset.columnKey); } catch (error) { console.error('Error getting current column order:', error); return []; } } function updateColumnOrderField() { try { const columnOrderField = document.getElementById('column_order'); const currentOrder = getCurrentColumnOrder(); if (columnOrderField) { columnOrderField.value = JSON.stringify(currentOrder); } } catch (error) { console.error('Error updating column order field:', error); } } function updatePreview() { try { const previewHeader = document.getElementById('previewHeader'); const previewTable = document.querySelector('.preview-table tbody'); if (!previewHeader || !previewTable) { console.warn('Preview elements not found'); return; } // Get selected columns in their current order const currentOrder = getCurrentColumnOrder(); if (currentOrder.length === 0) { // No columns selected previewHeader.innerHTML = ''; previewTable.innerHTML = ` No columns selected - please select at least one column to export `; updateGenerateButton(0); return; } // Build header with order numbers let headerHTML = ''; currentOrder.forEach((columnKey, index) => { const nameInput = document.getElementById('name_' + columnKey); const customName = nameInput ? nameInput.value : columnKey; headerHTML += `${customName}`; }); previewHeader.innerHTML = headerHTML; // Build sample data row let sampleRowHTML = ''; currentOrder.forEach(columnKey => { let sampleData = getSampleData(columnKey); // Special handling for address column to show the logic if (columnKey === 'address') { sampleData = `123 Business St, City*`; } sampleRowHTML += `${sampleData}`; }); sampleRowHTML += ''; // Add explanation row if address column is selected const hasAddressColumn = currentOrder.includes('address'); if (hasAddressColumn) { sampleRowHTML += ` * Check-in Address: Shows QR address when location accuracy ≤ 0.5 miles, otherwise shows actual GPS address `; } previewTable.innerHTML = sampleRowHTML; // Update generate button updateGenerateButton(currentOrder.length); console.log(`Preview updated with ${currentOrder.length} columns in order:`, currentOrder); } catch (error) { console.error('Error updating preview:', error); } } function getSampleData(columnKey) { // Return sample data for each column type const sampleData = { 'employee_id': 'EMP001', 'location_name': 'Main Office', 'status': 'Check In', 'check_in_date': '2025-08-14', 'check_in_time': '09:30:00', 'qr_address': '123 Business St, City', 'address': '123 Business St, City', 'device_info': 'iPhone 14 Pro', 'ip_address': '192.168.1.100', 'user_agent': 'Mobile Safari', 'latitude': '40.7128', 'longitude': '-74.0060', 'accuracy': '5.2', 'location_accuracy': '0.003' }; return sampleData[columnKey] || 'Sample Data'; } function selectAllColumns() { try { const checkboxes = document.querySelectorAll('input[name="selected_columns"]'); checkboxes.forEach(checkbox => { if (!checkbox.checked) { checkbox.checked = true; checkbox.closest('.column-item').classList.add('selected'); toggleColumnName(checkbox.value); } }); updateSelectedColumnsList(); updatePreview(); console.log('All columns selected'); } catch (error) { console.error('Error selecting all columns:', error); } } function deselectAllColumns() { try { const checkboxes = document.querySelectorAll('input[name="selected_columns"]'); checkboxes.forEach(checkbox => { if (checkbox.checked) { checkbox.checked = false; checkbox.closest('.column-item').classList.remove('selected'); toggleColumnName(checkbox.value); } }); updateSelectedColumnsList(); updatePreview(); console.log('All columns deselected'); } catch (error) { console.error('Error deselecting all columns:', error); } } function resetToDefaults() { try { console.log('🔄 Resetting to default settings...'); // First, deselect all columns and reset to defaults const allCheckboxes = document.querySelectorAll('input[name="selected_columns"]'); allCheckboxes.forEach(checkbox => { const key = checkbox.value; const nameInput = document.getElementById('name_' + key); const columnItem = checkbox.closest('.column-item'); // Check if this column should be selected by default const isDefaultSelected = DEFAULT_COLUMNS.hasOwnProperty(key) && DEFAULT_COLUMNS[key].selected; // Set checkbox state checkbox.checked = isDefaultSelected; // Update visual state if (isDefaultSelected) { columnItem?.classList.add('selected'); } else { columnItem?.classList.remove('selected'); } // Set the export name if (nameInput) { if (DEFAULT_COLUMNS[key]) { nameInput.value = DEFAULT_COLUMNS[key].name; } else { // Use the original default name from availableColumns if not in DEFAULT_COLUMNS const columnData = availableColumns.find(col => col.key === key); nameInput.value = columnData ? columnData.defaultName : nameInput.value; } } // Toggle visibility toggleColumnName(key); }); // Set the saved order to the default order savedColumnOrder = [...DEFAULT_COLUMN_ORDER]; // Update the display with the default order updateSelectedColumnsList(); // Apply the default order to the selected columns list applyDefaultOrder(); // Update preview updatePreview(); // Clear saved preferences from localStorage try { localStorage.removeItem('exportPreferences'); } catch (storageError) { console.warn('Could not clear saved preferences:', storageError); } console.log('✅ Reset to default settings complete'); } catch (error) { console.error('❌ Error resetting to defaults:', error); } } /** * Apply the default column order to the selected columns list */ function applyDefaultOrder() { try { const selectedList = document.getElementById('selectedColumnsList'); if (!selectedList) return; const items = Array.from(selectedList.children); if (items.length === 0) return; // Sort items based on DEFAULT_COLUMN_ORDER items.sort((a, b) => { const keyA = a.dataset.columnKey; const keyB = b.dataset.columnKey; const indexA = DEFAULT_COLUMN_ORDER.indexOf(keyA); const indexB = DEFAULT_COLUMN_ORDER.indexOf(keyB); // If key not in default order, put it at the end if (indexA === -1 && indexB === -1) return 0; if (indexA === -1) return 1; if (indexB === -1) return -1; return indexA - indexB; }); // Clear and re-append in sorted order selectedList.innerHTML = ''; items.forEach(item => selectedList.appendChild(item)); // Update order numbers updateColumnOrderNumbers(); // Update the hidden column order field updateColumnOrderField(); console.log('📋 Applied default column order'); } catch (error) { console.error('Error applying default order:', error); } } function updateGenerateButton(columnCount) { try { const generateBtn = document.getElementById('generateBtn'); if (!generateBtn) return; if (columnCount === 0) { generateBtn.disabled = true; generateBtn.innerHTML = ' Select columns to export'; generateBtn.classList.add('btn-disabled'); } else { generateBtn.disabled = false; generateBtn.innerHTML = ` Generate Excel Export (${columnCount} columns)`; generateBtn.classList.remove('btn-disabled'); } } catch (error) { console.error('Error updating generate button:', error); } } function validateForm() { try { const selectedColumns = document.querySelectorAll('input[name="selected_columns"]:checked'); if (selectedColumns.length === 0) { alert('Please select at least one column to export.'); return false; } // Validate that all selected columns have names let hasEmptyNames = false; selectedColumns.forEach(checkbox => { const nameInput = document.getElementById('name_' + checkbox.value); if (nameInput && nameInput.value.trim() === '') { hasEmptyNames = true; nameInput.style.borderColor = '#e53e3e'; nameInput.focus(); } else if (nameInput) { nameInput.style.borderColor = '#e2e8f0'; } }); if (hasEmptyNames) { alert('Please provide names for all selected columns.'); return false; } // Update column order field before submitting updateColumnOrderField(); // Save preferences before submitting savePreferences(); return true; } catch (error) { console.error('Error validating form:', error); return false; } } function savePreferences() { try { const selectedColumns = Array.from(document.querySelectorAll('input[name="selected_columns"]:checked')) .map(cb => cb.value); const columnNames = {}; selectedColumns.forEach(col => { const input = document.getElementById('name_' + col); if (input) { columnNames[col] = input.value.trim(); } }); // Get current column order const columnOrder = getCurrentColumnOrder(); const prefs = { selected_columns: selectedColumns, column_names: columnNames, column_order: columnOrder, timestamp: new Date().toISOString() }; localStorage.setItem('exportPreferences', JSON.stringify(prefs)); console.log('Preferences saved with column order:', prefs); } catch (e) { console.warn('Could not save preferences:', e); } } function loadSavedPreferences() { try { const savedPrefs = localStorage.getItem('exportPreferences'); if (!savedPrefs) { console.log('No saved preferences found'); // Check if there are already selected columns on page load and update preview const alreadySelected = document.querySelectorAll('input[name="selected_columns"]:checked'); if (alreadySelected.length > 0) { console.log('Found pre-selected columns, updating preview'); updateSelectedColumnsList(); updatePreview(); } return; } const prefs = JSON.parse(savedPrefs); // Check if preferences are not too old (30 days) const savedDate = new Date(prefs.timestamp || 0); const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); if (savedDate < thirtyDaysAgo) { localStorage.removeItem('exportPreferences'); console.log('Saved preferences are too old, removed'); // Check if there are already selected columns on page load and update preview const alreadySelected = document.querySelectorAll('input[name="selected_columns"]:checked'); if (alreadySelected.length > 0) { console.log('Found pre-selected columns, updating preview'); updateSelectedColumnsList(); updatePreview(); } return; } // Apply saved column selections if (prefs.selected_columns) { const checkboxes = document.querySelectorAll('input[name="selected_columns"]'); checkboxes.forEach(cb => { const shouldBeChecked = prefs.selected_columns.includes(cb.value); if (cb.checked !== shouldBeChecked) { cb.checked = shouldBeChecked; const columnItem = cb.closest('.column-item'); if (shouldBeChecked) { columnItem?.classList.add('selected'); } else { columnItem?.classList.remove('selected'); } toggleColumnName(cb.value); } }); } // Apply saved column names if (prefs.column_names) { Object.keys(prefs.column_names).forEach(key => { const input = document.getElementById('name_' + key); if (input && prefs.column_names[key]) { input.value = prefs.column_names[key]; } }); } // Save column order for later use if (prefs.column_order) { savedColumnOrder = prefs.column_order; } console.log('Preferences loaded:', prefs); // Update preview after loading preferences updateSelectedColumnsList(); updatePreview(); } catch (e) { console.warn('Could not load saved preferences:', e); try { localStorage.removeItem('exportPreferences'); } catch (removeError) { console.warn('Could not remove invalid preferences:', removeError); } // Check if there are already selected columns on page load and update preview const alreadySelected = document.querySelectorAll('input[name="selected_columns"]:checked'); if (alreadySelected.length > 0) { console.log('Found pre-selected columns after preference error, updating preview'); updateSelectedColumnsList(); updatePreview(); } } } // Utility function for debouncing function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } // Global functions for template usage window.selectAllColumns = selectAllColumns; window.deselectAllColumns = deselectAllColumns; window.resetToDefaults = resetToDefaults; window.toggleColumnName = toggleColumnName; window.updateSelectedColumnsList = updateSelectedColumnsList; window.getCurrentColumnOrder = getCurrentColumnOrder; window.updateColumnOrderField = updateColumnOrderField; window.savePreferences = savePreferences; // Add CSS for disabled button const style = document.createElement('style'); style.textContent = ` .btn-disabled { opacity: 0.6 !important; cursor: not-allowed !important; background: #a0aec0 !important; pointer-events: none; } .btn-disabled:hover { transform: none !important; box-shadow: none !important; } `; document.head.appendChild(style);