function showTab(id, event) { // Remove active class from all tabs document.querySelectorAll('.tab').forEach(tab => tab.classList.remove('active')); // Add active class to clicked tab event.target.classList.add('active'); // Hide all content divs document.querySelectorAll('.content > div').forEach(div => { div.classList.add('hidden'); div.classList.remove('slide-in'); }); // Show selected content with animation const targetDiv = document.getElementById(id); targetDiv.classList.remove('hidden'); setTimeout(() => targetDiv.classList.add('slide-in'), 10); // Load coupon list when "list" tab is shown if (id === 'list') { loadCodeList(); // Set up search functionality when list tab is shown setupSearchFunctionality(); } // Handle translation upload tab if (id === 'translation-upload') { renderTranslationUploadSection(); } } /** * Handles the logout process by showing confirmation modal */ async function handleLogout() { document.getElementById('logoutModal').classList.add('show'); } /** * Closes the logout confirmation modal */ function closeLogoutModal() { document.getElementById('logoutModal').classList.remove('show'); } /** * Confirms and executes the logout process * Makes API call to logout endpoint and redirects user */ async function confirmLogout() { const logoutBtn = document.querySelector('#logoutModal .btn-danger'); // Show loading state logoutBtn.classList.add('loading'); logoutBtn.innerHTML = ' Logging out...'; try { const response = await fetch('/admin/logout', { method: 'POST', headers: { 'Content-Type': 'application/json', } }); if (response.ok) { showNotification('Logged out successfully! Redirecting...', 'success'); setTimeout(() => { window.location.href = '/login'; }, 1500); } else { showNotification('Error during logout. Please try again.', 'error'); } } catch (error) { console.error('Logout error:', error); showNotification('Network error. Please try again.', 'error'); } finally { // Reset button logoutBtn.classList.remove('loading'); logoutBtn.innerHTML = ' Logout'; closeLogoutModal(); } } /** * Generates coupon codes based on selected mode (single or bulk) * Handles form validation and displays results */ async function generateCode() { const mode = document.querySelector('input[name="genMode"]:checked').value; const resultEl = document.getElementById('genResult'); const btn = event.target; // Show loading state btn.classList.add('loading'); btn.innerHTML = ' Generating...'; let payload = new FormData(); payload.append("mode", mode); if (mode === "bulk") { const count = parseInt(document.getElementById('bulkCount').value); if (!count || count <= 0) { resultEl.innerHTML = `
Warning! Please enter a valid number of codes to generate.
`; // Reset button btn.classList.remove('loading'); btn.innerHTML = ' Generate Codes'; return; } payload.append("count", count); } try { const res = await fetch('/generate', { method: 'POST', body: payload }); const data = await res.json(); if (mode === "single") { resultEl.innerHTML = `
Success! Generated Code: ${data.code}
`; } else { resultEl.innerHTML = `
Success! Generated ${data.codes.length} codes:
${data.codes.map(code => `
${code}
`).join('')}
`; } } catch (error) { resultEl.innerHTML = `
Error! Failed to generate codes. Please try again.
`; } finally { // Reset button btn.classList.remove('loading'); btn.innerHTML = ' Generate Codes'; } } // Pagination variables let currentPage = 1; let totalPages = 1; let totalCodes = 0; const codesPerPage = 20; /** * Loads and displays coupon code list with pagination */ async function loadCodeList(page = 1) { try { const res = await fetch(`/list?page=${page}&limit=${codesPerPage}`); const data = await res.json(); const tbody = document.querySelector('#codeTable tbody'); console.log("Loading coupon list..."); // Update pagination variables currentPage = data.page; totalPages = data.total_pages; totalCodes = data.total; if (data.codes.length === 0) { tbody.innerHTML = ` No coupon codes found `; updatePaginationInfo(); updatePaginationControls(); return; } // Render current page rows tbody.innerHTML = ''; data.codes.forEach(item => { const usedAtDisplay = item.usage_count > 0 ? (item.used_at ? item.used_at : '--') : '--'; const row = ` ${item.code} ${usedAtDisplay}
`; tbody.innerHTML += row; }); updatePaginationInfo(); updatePaginationControls(); } catch (error) { console.error("Error loading coupon list:", error); const tbody = document.querySelector('#codeTable tbody'); tbody.innerHTML = ` Error loading coupon codes `; updatePaginationInfo(); updatePaginationControls(); } } /** * Toggles between single code entry and Excel file upload modes */ function toggleUploadMode(mode) { const singleSection = document.getElementById("add-code-form"); const excelSection = document.getElementById("file-upload-section"); // Update radio option styling document.querySelectorAll('input[name="uploadMode"]').forEach(radio => { const option = radio.closest('.radio-option'); if (radio.checked) { option.classList.add('active'); } else { option.classList.remove('active'); } }); if (mode === "single") { singleSection.classList.remove("hidden"); singleSection.style.display = "block"; excelSection.classList.add("hidden"); excelSection.style.display = "none"; // Clear any existing file upload data clearFile(); } else if (mode === "excel") { singleSection.classList.add("hidden"); singleSection.style.display = "none"; excelSection.classList.remove("hidden"); excelSection.style.display = "block"; // Clear single code form document.getElementById('new-code').value = ''; document.getElementById('new-usage').value = ''; } } /** * Adds a new coupon code through the single entry form * Validates input and sends data to server */ async function addNewCode(event) { const codeInput = document.getElementById('new-code'); const usageInput = document.getElementById('new-usage'); const btn = event.target; const code = codeInput.value.trim().toUpperCase(); const usage = parseInt(usageInput.value) || 0; // Validation if (!code) { showNotification('Please enter a coupon code', 'error'); return; } if (code.length < 3) { showNotification('Code must be at least 3 characters long', 'error'); return; } if (usage < 0) { showNotification('Usage count cannot be negative', 'error'); return; } // Show loading state btn.classList.add('loading'); btn.innerHTML = ' Adding...'; try { const response = await fetch('/add-code', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ code: code, usage: usage }) }); if (response.ok) { showNotification('Code added successfully!', 'success'); // Clear inputs codeInput.value = ''; usageInput.value = ''; // Reload code list if on list tab if (typeof loadCodeList === 'function') { loadCodeList(currentPage || 1); } // DO NOT hide the form - keep it visible for more entries } else { const error = await response.json(); showNotification(error.detail || 'Failed to add code', 'error'); } } catch (error) { console.error('Error adding code:', error); showNotification('Network error. Please try again.', 'error'); } finally { // Reset button btn.classList.remove('loading'); btn.innerHTML = ' Add Code'; } } /** * Initiates the delete process for a coupon code * Shows confirmation modal */ function deleteCode(code) { currentDeleteCode = code; document.getElementById('deleteCodeName').textContent = code; document.getElementById('deleteModal').classList.add('show'); } /** * Confirms and executes coupon code deletion * Makes API call and updates the list */ async function confirmDeleteCode() { const btn = event.target; // Show loading state btn.classList.add('loading'); btn.innerHTML = ' Deleting...'; try { const response = await fetch(`/delete-code/${currentDeleteCode}`, { method: 'DELETE' }); if (response.ok) { showNotification('Code deleted successfully!', 'success'); closeDeleteModal(); loadCodeList(currentPage); } else { const error = await response.json(); showNotification(error.detail || 'Failed to delete code', 'error'); } } catch (error) { console.error('Error deleting code:', error); showNotification('Network error. Please try again.', 'error'); } finally { // Reset button btn.classList.remove('loading'); btn.innerHTML = ' Delete Code'; } } /** * Closes the delete confirmation modal and resets state */ function closeDeleteModal() { document.getElementById('deleteModal').classList.remove('show'); currentDeleteCode = null; } /** * Displays a notification message with specified type and auto-dismiss */ function showNotification(message, type = 'info') { // Remove existing notifications const existingNotification = document.querySelector('.notification'); if (existingNotification) { existingNotification.remove(); } // Create notification element const notification = document.createElement('div'); notification.className = `notification ${type}`; notification.innerHTML = `
${message}
`; document.body.appendChild(notification); // Auto-remove after 4 seconds setTimeout(() => { if (notification.parentNode) { notification.remove(); } }, 4000); } // Close modals when clicking outside document.addEventListener('click', function(event) { const deleteModal = document.getElementById('deleteModal'); if (event.target === deleteModal) { closeDeleteModal(); } }); // Close modals with Escape key document.addEventListener('keydown', function(event) { if (event.key === 'Escape') { closeDeleteModal(); } }); /** * Filters coupon codes based on search query * Makes API call to search endpoint and displays results */ async function filterCoupons(query) { console.log('filterCoupons called with query:', query); // Debug const tbody = document.querySelector('#codeTable tbody'); const searchResultInfo = document.getElementById('searchResultInfo'); const noResultsInfo = document.getElementById('noResultsInfo'); const searchResultText = document.getElementById('searchResultText'); console.log('Elements found:', { tbody, searchResultInfo, noResultsInfo, searchResultText }); // Debug if (!query.trim()) { console.log('Empty query, calling showAllCoupons'); // Debug showAllCoupons(); return; } try { console.log('Making fetch request to:', `/search-codes?query=${encodeURIComponent(query)}`); // Debug const res = await fetch(`/search-codes?query=${encodeURIComponent(query)}`); console.log('Response status:', res.status); // Debug const results = await res.json(); console.log('Search results:', results); // Debug tbody.innerHTML = ''; if (results.length === 0) { console.log('No results found, showing no results message'); // Debug noResultsInfo.classList.add('show'); searchResultInfo.classList.remove('show'); return; } // Show rows with action buttons results.forEach(item => { const row = ` ${item.code} ${item.used_at ? item.used_at : '-'}
`; tbody.innerHTML += row; }); console.log('Showing search results, hiding no results message'); // Debug noResultsInfo.classList.remove('show'); searchResultInfo.classList.add('show'); searchResultText.textContent = results.length === 1 ? `Found coupon code: ${results[0].code}` : `Found ${results.length} coupon codes matching "${query}"`; } catch (err) { console.error("Search failed:", err); noResultsInfo.classList.add('show'); searchResultInfo.classList.remove('show'); } } /** * Shows all coupon codes by clearing search filters * Restores the normal paginated view */ function showAllCoupons() { console.log('showAllCoupons called, currentPage:', currentPage); // Debug const searchResultInfo = document.getElementById('searchResultInfo'); const noResultsInfo = document.getElementById('noResultsInfo'); // Hide info messages searchResultInfo.classList.remove('show'); noResultsInfo.classList.remove('show'); // Reload the full coupon list to current page loadCodeList(currentPage); } /** * Clears the search input and shows all coupons */ function clearSearch() { const searchInput = document.getElementById('searchInput'); const searchClear = document.getElementById('searchClear'); searchInput.value = ''; searchClear.classList.remove('show'); showAllCoupons(); } /** * Changes the current page for pagination */ function changePage(direction) { const newPage = currentPage + direction; if (newPage >= 1 && newPage <= totalPages) { loadCodeList(newPage); } } /** * Navigates directly to a specific page */ function goToPage(page) { if (page >= 1 && page <= totalPages && page !== currentPage) { loadCodeList(page); } } /** * Updates the pagination information display */ function updatePaginationInfo() { const start = totalCodes === 0 ? 0 : (currentPage - 1) * codesPerPage + 1; const end = Math.min(currentPage * codesPerPage, totalCodes); document.getElementById('paginationInfo').textContent = `Showing ${start}-${end} of ${totalCodes} codes`; } /** * Updates the pagination control buttons and page numbers */ function updatePaginationControls() { const prevBtn = document.getElementById('prevPage'); const nextBtn = document.getElementById('nextPage'); const pageNumbers = document.getElementById('pageNumbers'); // Update prev/next buttons prevBtn.disabled = currentPage <= 1; nextBtn.disabled = currentPage >= totalPages; // Generate page numbers pageNumbers.innerHTML = ''; if (totalPages <= 7) { // Show all pages if 7 or fewer for (let i = 1; i <= totalPages; i++) { createPageButton(i, pageNumbers); } } else { // Show first page createPageButton(1, pageNumbers); if (currentPage > 4) { pageNumbers.innerHTML += '...'; } // Show pages around current page const start = Math.max(2, currentPage - 1); const end = Math.min(totalPages - 1, currentPage + 1); for (let i = start; i <= end; i++) { createPageButton(i, pageNumbers); } if (currentPage < totalPages - 3) { pageNumbers.innerHTML += '...'; } // Show last page if (totalPages > 1) { createPageButton(totalPages, pageNumbers); } } } /** * Creates a page button for pagination controls */ function createPageButton(pageNum, container) { const button = document.createElement('button'); button.className = `page-number ${pageNum === currentPage ? 'active' : ''}`; button.textContent = pageNum; button.onclick = () => goToPage(pageNum); container.appendChild(button); } // Upload functionality let previewData = []; let currentDeleteCode = null; /** * Handles file selection for Excel upload * Validates file type and size, then processes the file */ function handleFileSelect(event) { console.log("File select triggered"); // Debug const file = event.target.files[0]; if (!file) { console.log("No file selected"); // Debug return; } console.log("File selected:", file.name, file.size); // Debug const fileInfo = document.getElementById('fileInfo'); const fileName = document.getElementById('fileName'); const validationErrors = document.getElementById('validationErrors'); const previewSection = document.getElementById('previewSection'); const uploadResult = document.getElementById('uploadResult'); // Reset previous states validationErrors.style.display = 'none'; previewSection.style.display = 'none'; uploadResult.innerHTML = ''; // Validate file type if (!file.name.match(/\.(xlsx|xls)$/i)) { console.log("Invalid file type"); // Debug showValidationErrors(['Please select a valid Excel file (.xlsx or .xls)']); return; } // Validate file size (10MB limit) if (file.size > 10 * 1024 * 1024) { console.log("File too large"); // Debug showValidationErrors(['File size must be less than 10MB']); return; } // Show file info fileName.textContent = file.name; fileInfo.style.display = 'flex'; console.log("File info displayed"); // Debug // Read and process file const reader = new FileReader(); reader.onload = function(e) { console.log("File read complete, processing..."); // Debug try { const data = new Uint8Array(e.target.result); const workbook = XLSX.read(data, { type: 'array' }); console.log("Workbook read:", workbook.SheetNames); // Debug // Get first worksheet const worksheetName = workbook.SheetNames[0]; const worksheet = workbook.Sheets[worksheetName]; // Convert to JSON const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 }); console.log("JSON data:", jsonData); // Debug if (jsonData.length < 2) { console.log("Not enough data rows"); // Debug showValidationErrors(['Excel file must contain at least a header row and one data row']); return; } // Process data processExcelData(jsonData); } catch (error) { console.error('Error reading file:', error); showValidationErrors(['Error reading Excel file. Please check file format.']); } }; reader.onerror = function(error) { console.error('FileReader error:', error); // Debug }; console.log("Starting file read..."); // Debug reader.readAsArrayBuffer(file); } /** * Processes Excel data and validates coupon codes * Detects column headers and validates data format */ function processExcelData(data) { const errors = []; const processed = []; const duplicates = new Set(); const seen = new Set(); // Expected headers (case insensitive) const headers = data[0].map(h => String(h).toLowerCase().trim()); // Column index detection const codeIndex = headers.findIndex(h => h.includes('code')); const usageIndex = headers.findIndex(h => h.includes('usage') || h.includes('use')); // Check if code column exists if (codeIndex === -1) { errors.push(`Missing required column: code`); } if (errors.length === 0) { // Process data rows for (let i = 1; i < data.length; i++) { const row = data[i]; if (!row || row.length === 0) continue; // Skip empty rows const code = String(row[codeIndex] || '').trim().toUpperCase(); let usage = 0; // Handle usage column presence and validity if (usageIndex !== -1) { const rawUsage = row[usageIndex]; usage = isNaN(rawUsage) || rawUsage === null || rawUsage === "" ? 0 : parseInt(rawUsage); } // Validate code if (!code) { errors.push(`Row ${i + 1}: Code is required`); continue; } if (code.length < 3) { errors.push(`Row ${i + 1}: Code must be at least 3 characters`); continue; } // Check for duplicates within file if (seen.has(code)) { duplicates.add(code); continue; } seen.add(code); // Validate usage count if (usage < 0) { errors.push(`Row ${i + 1}: Usage count cannot be negative`); continue; } processed.push({ code, usage }); } } // Show results if (errors.length > 0) { showValidationErrors(errors); } if (processed.length > 0) { previewData = processed; showPreview(processed, duplicates.size); } } /** * Displays validation errors for Excel file processing */ function showValidationErrors(errors) { const validationErrors = document.getElementById('validationErrors'); const errorList = document.getElementById('errorList'); errorList.innerHTML = ''; errors.forEach(error => { const li = document.createElement('li'); li.textContent = error; errorList.appendChild(li); }); validationErrors.style.display = 'block'; } /** * Shows preview of processed Excel data before upload * Displays statistics and sample rows */ function showPreview(data, duplicateCount) { const previewSection = document.getElementById('previewSection'); const previewTableBody = document.getElementById('previewTableBody'); // Update stats document.getElementById('totalCodes').textContent = data.length + duplicateCount; document.getElementById('validCodes').textContent = data.length; document.getElementById('duplicateCodes').textContent = duplicateCount; // Show preview table (first 10 rows) - Fixed to match 2-column structure previewTableBody.innerHTML = ''; const previewRows = data.slice(0, 10); previewRows.forEach(item => { const row = document.createElement('tr'); row.innerHTML = ` ${item.code} ${item.usage} `; previewTableBody.appendChild(row); }); if (data.length > 10) { const moreRow = document.createElement('tr'); moreRow.innerHTML = ` ... and ${data.length - 10} more codes `; previewTableBody.appendChild(moreRow); } previewSection.style.display = 'block'; // Auto-upload to database uploadCodes(); } /** * Uploads processed coupon codes to the database * Makes API call with the validated coupon data */ async function uploadCodes() { if (previewData.length === 0) { return; } const uploadBtn = document.getElementById('uploadBtn'); if (uploadBtn) uploadBtn.style.display = 'none'; const uploadResult = document.getElementById('uploadResult'); try { const response = await fetch('/upload-codes', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ codes: previewData }) }); const result = await response.json(); if (response.ok) { uploadResult.innerHTML = `
Success! Successfully uploaded ${result.uploaded} coupon codes to database. ${result.skipped > 0 ? `
${result.skipped} codes were skipped (already exist).` : ''}
`; // Clear form after successful upload setTimeout(() => { clearFile(); }, 3000); } else { uploadResult.innerHTML = `
Error! ${result.error || 'Failed to upload codes. Please try again.'}
`; } } catch (error) { console.error('Upload error:', error); uploadResult.innerHTML = `
Error! Network error. Please check your connection and try again.
`; } finally { // Reset button uploadBtn.classList.remove('loading'); uploadBtn.innerHTML = ' Upload to Database'; } } /** * Clears the file upload form and resets all related UI elements */ function clearFile() { const fileInput = document.getElementById('excelFile'); const fileInfo = document.getElementById('fileInfo'); const validationErrors = document.getElementById('validationErrors'); const previewSection = document.getElementById('previewSection'); const uploadResult = document.getElementById('uploadResult'); fileInput.value = ''; fileInfo.style.display = 'none'; validationErrors.style.display = 'none'; previewSection.style.display = 'none'; uploadResult.innerHTML = ''; previewData = []; } /** * Sets up drag and drop functionality for file upload area */ function setupDragAndDrop() { const uploadArea = document.querySelector('.file-upload-area'); uploadArea.addEventListener('dragover', (e) => { e.preventDefault(); uploadArea.classList.add('dragover'); }); uploadArea.addEventListener('dragleave', (e) => { e.preventDefault(); uploadArea.classList.remove('dragover'); }); uploadArea.addEventListener('drop', (e) => { e.preventDefault(); uploadArea.classList.remove('dragover'); const files = e.dataTransfer.files; if (files.length > 0) { const fileInput = document.getElementById('excelFile'); fileInput.files = files; handleFileSelect({ target: { files } }); } }); } /** * Handles radio button styling changes for generation mode selection */ function handleRadioChange() { const radios = document.querySelectorAll('input[name="genMode"]'); const bulkCountWrapper = document.getElementById('bulkCountWrapper'); radios.forEach(radio => { const option = radio.closest('.radio-option'); if (radio.checked) { option.classList.add('active'); // Show/hide bulk count input if (radio.value === 'bulk') { bulkCountWrapper.classList.remove('hidden'); } else { bulkCountWrapper.classList.add('hidden'); } } else { option.classList.remove('active'); } }); } /** * Renders the translation upload section based on current file status * Checks if translation file exists and displays appropriate UI */ async function renderTranslationUploadSection() { const section = document.getElementById('translationUploadSection'); section.innerHTML = '
Checking translation file status...
'; let fileExists = false; let fileName = ''; try { const res = await fetch('/translations/status'); if (res.ok) { const data = await res.json(); fileExists = data.file_exists; fileName = data.file_name || ''; console.log('Translation status:', data); // Debug log } else { console.error('Status check failed:', res.status); fileExists = false; } } catch (e) { console.error('Error checking translation status:', e); fileExists = false; } if (fileExists) { section.innerHTML = `
Translation file is present
${fileName ? `
${fileName}
` : ''}
The extension will use this file for translations
`; } else { section.innerHTML = `
Click to select file
or drag and drop here
`; } } /** * Triggers the hidden file input element for translation file selection */ function triggerFileInput() { document.getElementById('translationFile').click(); } /** * Handles translation file selection and displays selected filename */ function handleTranslationFileSelect(event) { const file = event.target.files[0]; const fileNameDiv = document.getElementById('selectedFileName'); if (file) { fileNameDiv.innerHTML = ` Selected: ${file.name}`; fileNameDiv.style.color = '#059669'; } else { fileNameDiv.innerHTML = ''; } } /** * Uploads translation file to server * Validates file selection and handles upload process */ async function uploadTranslationFile() { const fileInput = document.getElementById('translationFile'); const resultDiv = document.getElementById('translationUploadResult'); const uploadBtn = document.getElementById('uploadTranslationBtn'); if (!fileInput || !fileInput.files.length) { resultDiv.innerHTML = '
Please select a file to upload.
'; return; } const file = fileInput.files[0]; const formData = new FormData(); formData.append('file', file); // Show loading state if (uploadBtn) { uploadBtn.classList.add('loading'); uploadBtn.innerHTML = ' Uploading...'; uploadBtn.disabled = true; } resultDiv.innerHTML = '
Uploading...
'; try { const response = await fetch('/upload-translations', { method: 'POST', body: formData }); const data = await response.json(); if (response.ok) { resultDiv.innerHTML = `
${data.message || 'Upload successful!'} - File: ${file.name}
`; // Wait a moment before refreshing the section to show the success message setTimeout(async () => { await renderTranslationUploadSection(); }, 2000); } else { resultDiv.innerHTML = `
Upload failed: ${data.detail || 'Unknown error'}
`; } } catch (err) { console.error('Upload error:', err); resultDiv.innerHTML = '
Upload failed. Please try again.
'; } finally { // Reset button if (uploadBtn) { uploadBtn.classList.remove('loading'); uploadBtn.innerHTML = ' Upload Translation File'; uploadBtn.disabled = false; } } } /** * Downloads the current translation file from server * Handles file download and user feedback */ async function downloadTranslationFile() { const resultDiv = document.getElementById('translationUploadResult'); try { // Show loading state resultDiv.innerHTML = '
Preparing download...
'; const response = await fetch('/download-translation', { method: 'GET' }); if (response.ok) { // Get the filename from response headers or use default const contentDisposition = response.headers.get('Content-Disposition'); let filename = 'translation.xlsx'; if (contentDisposition) { const filenameMatch = contentDisposition.match(/filename="?([^"]+)"?/); if (filenameMatch) { filename = filenameMatch[1]; } } // Create blob and download const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.style.display = 'none'; a.href = url; a.download = filename; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); resultDiv.innerHTML = `
Download started successfully!
`; // Clear success message after 3 seconds setTimeout(() => { resultDiv.innerHTML = ''; }, 3000); } else { const data = await response.json(); resultDiv.innerHTML = `
Download failed: ${data.detail || 'File not found'}
`; } } catch (err) { console.error('Download error:', err); resultDiv.innerHTML = '
Download failed. Please try again.
'; } } /** * Deletes the current translation file from server * Shows confirmation dialog and handles deletion process */ async function deleteTranslationFile() { const resultDiv = document.getElementById('translationUploadResult'); // Show confirmation if (!confirm('Are you sure you want to delete the translation file? This action cannot be undone.')) { return; } resultDiv.innerHTML = '
Deleting...
'; try { const response = await fetch('/delete-translation', { method: 'DELETE' }); const data = await response.json(); if (response.ok) { resultDiv.innerHTML = `
${data.message || 'Deleted successfully!'}
`; // Wait a moment before refreshing the section to show the success message setTimeout(async () => { await renderTranslationUploadSection(); }, 2000); } else { resultDiv.innerHTML = `
Delete failed: ${data.detail || 'Unknown error'}
`; } } catch (err) { console.error('Delete error:', err); resultDiv.innerHTML = '
Delete failed. Please try again.
'; } } /** * Initializes the dashboard when DOM content is loaded * Sets up event listeners, initial states, and functionality */ document.addEventListener('DOMContentLoaded', function() { // Set initial active states const firstTab = document.querySelector('.tab'); if (firstTab) { showTab('generate', { target: firstTab }); } // Add event listeners to radio buttons const radios = document.querySelectorAll('input[name="genMode"]'); radios.forEach(radio => { radio.addEventListener('change', handleRadioChange); }); // Initialize radio states handleRadioChange(); // Add click handlers to radio options for better UX document.querySelectorAll('.radio-option').forEach(option => { option.addEventListener('click', function() { const radio = this.querySelector('input[type="radio"]'); if (radio) { radio.checked = true; handleRadioChange(); } }); }); // Add upload mode toggle handlers const uploadRadios = document.querySelectorAll('input[name="uploadMode"]'); uploadRadios.forEach(radio => { radio.addEventListener('change', function() { toggleUploadMode(this.value); }); }); // Add click handlers to upload radio options document.querySelectorAll('.radio-option').forEach(option => { option.addEventListener('click', function() { const radioInput = this.querySelector('input[type="radio"]'); if (radioInput && radioInput.name === 'uploadMode') { radioInput.checked = true; toggleUploadMode(radioInput.value); } }); }); // Initialize upload mode toggleUploadMode("single"); // Setup drag and drop for file upload setupDragAndDrop(); }); /** * Sets up search functionality for coupon code filtering * Adds event listeners and handles search input changes */ function setupSearchFunctionality() { console.log('Setting up search functionality...'); // Debug const searchInput = document.getElementById('searchInput'); const searchClear = document.getElementById('searchClear'); console.log('Search input found:', searchInput); // Debug console.log('Search clear found:', searchClear); // Debug if (searchInput && searchClear) { // Remove existing event listeners to prevent duplicates searchInput.removeEventListener('input', searchInput.searchHandler); // Create the event handler function searchInput.searchHandler = function() { const query = this.value.trim(); console.log('Search query:', query); // Debug if (query) { searchClear.classList.add('show'); console.log('Calling filterCoupons with:', query); // Debug filterCoupons(query); } else { searchClear.classList.remove('show'); console.log('Calling showAllCoupons'); // Debug showAllCoupons(); } }; // Add the event listener searchInput.addEventListener('input', searchInput.searchHandler); console.log('Search event listener added successfully'); // Debug } else { console.error('Search elements not found!'); // Debug } }