diff --git a/app.js b/app.js index 9a60c20..b1496ef 100644 --- a/app.js +++ b/app.js @@ -7,7 +7,8 @@ let allData = []; let filteredData = []; let currentSort = { column: null, direction: null }; let filters = {}; -let globalSearch = ''; +let columnTextFilters = {}; +let hideOkFilter = false; let apiCredentials = null; // API Configuration @@ -140,14 +141,21 @@ async function loadData() { // =================================== function applyFilters() { - let result = filteredData.filter(item => { - if (!globalSearch) return true; - const searchLower = globalSearch.toLowerCase(); - return Object.values(item).some(value => - value !== null && value.toString().toLowerCase().includes(searchLower) - ); + let result = [...filteredData]; + + // Apply column text filters + Object.entries(columnTextFilters).forEach(([column, searchText]) => { + if (searchText && searchText.trim()) { + const searchLower = searchText.toLowerCase().trim(); + result = result.filter(item => { + const value = item[column]; + return value !== null && value !== undefined && + String(value).toLowerCase().includes(searchLower); + }); + } }); + // Apply checkbox filters Object.entries(filters).forEach(([column, selectedValues]) => { if (selectedValues.length > 0) { result = result.filter(item => @@ -156,12 +164,25 @@ function applyFilters() { } }); + // Apply "hide OK" filter + if (hideOkFilter) { + result = result.filter(item => { + const remark = item.Remark || ''; + return !String(remark).trim().toLowerCase().includes('ok'); + }); + } + renderTable(result); updateStats(result.length); console.group('%c Table View', 'background: #06b6d4; color: white; padding: 4px 8px; border-radius: 4px; font-weight: bold;'); console.log('%c Rendering', 'font-weight: bold;', result.length, 'records'); - console.log('%c View range:', 'color: #64748b;', '1-', result.length); + console.log('%c Active text filters:', Object.entries(columnTextFilters) + .filter(([_, v]) => v && v.trim()) + .map(([k, v]) => `${k}: "${v}"`), 'color: #64748b;'); + if (hideOkFilter) { + console.log('%c Filter:', 'color: #10b981;', 'Hide OK remarks is ON'); + } console.groupEnd(); } @@ -292,9 +313,9 @@ function getRemarkIcon(remark) { // Recheck Action // =================================== -async function handleRecheck(orderId, isChecked) { +async function handleRecheck(id, isChecked) { console.group('%c Recheck', 'background: #6366f1; color: white; padding: 4px 8px; border-radius: 4px; font-weight: bold;'); - console.log('%c Order ID:', 'font-weight: bold;', orderId); + console.log('%c ID:', 'font-weight: bold;', id); console.log('%c Status:', isChecked ? 'color: #10b981' : 'color: #94a3b8', isChecked ? 'Checked' : 'Unchecked'); try { @@ -307,7 +328,7 @@ async function handleRecheck(orderId, isChecked) { } : {}) }, body: JSON.stringify({ - Order_ID: orderId, + ID: id, recheck: isChecked }) }); @@ -461,11 +482,63 @@ function setupClickOutside() { }); } -function handleGlobalSearch(search) { - globalSearch = search; +function handleColumnFilter(input) { + const column = input.dataset.column; + const value = input.value; + + if (value) { + columnTextFilters[column] = value; + input.parentElement.classList.add('filter-active'); + } else { + delete columnTextFilters[column]; + input.parentElement.classList.remove('filter-active'); + } + applyFilters(); } +function clearAllFilters() { + // Clear column text filters + columnTextFilters = {}; + + // Clear checkbox filters + filters = {}; + + // Reset hide OK filter + hideOkFilter = false; + updateHideOkButton(); + + // Clear all input fields + document.querySelectorAll('.column-filter').forEach(input => { + input.value = ''; + input.parentElement.classList.remove('filter-active'); + }); + + // Reset filter indicators + document.querySelectorAll('.filter-indicator').forEach(indicator => { + indicator.classList.remove('active'); + }); + + applyFilters(); +} + +function toggleHideOkFilter() { + hideOkFilter = !hideOkFilter; + updateHideOkButton(); + applyFilters(); +} + +function updateHideOkButton() { + const btn = document.getElementById('hideOkBtn'); + if (!btn) return; + + if (hideOkFilter) { + btn.style.boxShadow = '0 0 0 2px var(--danger)'; + } else { + btn.style.boxShadow = 'none'; + } +} + // =================================== // Statistics // =================================== diff --git a/index.html b/index.html index 50392fb..cebe907 100644 --- a/index.html +++ b/index.html @@ -39,10 +39,12 @@ - + +
@@ -59,6 +61,11 @@ Month +
@@ -69,6 +76,11 @@ Odoo AR Nr +
@@ -79,6 +91,11 @@ Order ID +
@@ -89,6 +106,11 @@ Country +
@@ -109,6 +131,11 @@ Remark +
diff --git a/style.css b/style.css index a2e4fd9..861f012 100644 --- a/style.css +++ b/style.css @@ -211,7 +211,7 @@ thead { } th { - padding: 1rem 1.5rem; + padding: 0.75rem 1rem; text-align: left; font-weight: 600; color: var(--dark); @@ -220,12 +220,40 @@ th { top: 0; background: var(--light); z-index: 10; + display: flex; + flex-direction: column; + gap: 0.5rem; } th:hover { background: var(--hover); } +.column-filter { + width: 100%; + padding: 0.4rem 0.6rem; + border: 1px solid var(--border); + border-radius: 4px; + font-size: 0.8rem; + transition: border-color 0.2s ease, box-shadow 0.2s ease; + background: white; +} + +.column-filter:focus { + outline: none; + border-color: var(--primary); + box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.1); +} + +.column-filter::placeholder { + color: #94a3b8; +} + +th.filter-active .column-filter { + border-color: var(--primary); + background-color: rgba(99, 102, 241, 0.05); +} + th .sort-indicator { display: inline-flex; flex-direction: column;