Compare commits
2
Commits
69a9370104
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80a52ed790 | ||
|
|
b299bf3627 |
@@ -7,7 +7,8 @@ let allData = [];
|
|||||||
let filteredData = [];
|
let filteredData = [];
|
||||||
let currentSort = { column: null, direction: null };
|
let currentSort = { column: null, direction: null };
|
||||||
let filters = {};
|
let filters = {};
|
||||||
let globalSearch = '';
|
let columnTextFilters = {};
|
||||||
|
let hideOkFilter = false;
|
||||||
let apiCredentials = null;
|
let apiCredentials = null;
|
||||||
|
|
||||||
// API Configuration
|
// API Configuration
|
||||||
@@ -140,14 +141,21 @@ async function loadData() {
|
|||||||
// ===================================
|
// ===================================
|
||||||
|
|
||||||
function applyFilters() {
|
function applyFilters() {
|
||||||
let result = filteredData.filter(item => {
|
let result = [...filteredData];
|
||||||
if (!globalSearch) return true;
|
|
||||||
const searchLower = globalSearch.toLowerCase();
|
// Apply column text filters
|
||||||
return Object.values(item).some(value =>
|
Object.entries(columnTextFilters).forEach(([column, searchText]) => {
|
||||||
value !== null && value.toString().toLowerCase().includes(searchLower)
|
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]) => {
|
Object.entries(filters).forEach(([column, selectedValues]) => {
|
||||||
if (selectedValues.length > 0) {
|
if (selectedValues.length > 0) {
|
||||||
result = result.filter(item =>
|
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);
|
renderTable(result);
|
||||||
updateStats(result.length);
|
updateStats(result.length);
|
||||||
|
|
||||||
console.group('%c Table View', 'background: #06b6d4; color: white; padding: 4px 8px; border-radius: 4px; font-weight: bold;');
|
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 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();
|
console.groupEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,9 +313,9 @@ function getRemarkIcon(remark) {
|
|||||||
// Recheck Action
|
// 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.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');
|
console.log('%c Status:', isChecked ? 'color: #10b981' : 'color: #94a3b8', isChecked ? 'Checked' : 'Unchecked');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -307,7 +328,7 @@ async function handleRecheck(orderId, isChecked) {
|
|||||||
} : {})
|
} : {})
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
Order_ID: orderId,
|
ID: id,
|
||||||
recheck: isChecked
|
recheck: isChecked
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@@ -461,11 +482,63 @@ function setupClickOutside() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleGlobalSearch(search) {
|
function handleColumnFilter(input) {
|
||||||
globalSearch = search;
|
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();
|
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
|
// Statistics
|
||||||
// ===================================
|
// ===================================
|
||||||
@@ -519,7 +592,7 @@ function showCredentialPrompt() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<button type="button" class="btn-secondary" onclick="closeCredentialPrompt()">Cancel</button>
|
<button type="button" class="btn-secondary" id="cancelAuthBtn">Cancel</button>
|
||||||
<button type="submit" class="btn-primary">Connect</button>
|
<button type="submit" class="btn-primary">Connect</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -533,12 +606,22 @@ function showCredentialPrompt() {
|
|||||||
`;
|
`;
|
||||||
document.body.appendChild(prompt);
|
document.body.appendChild(prompt);
|
||||||
|
|
||||||
document.getElementById('credentialForm').addEventListener('submit', handleCredentials);
|
const form = document.getElementById('credentialForm');
|
||||||
document.querySelector('.credential-overlay').addEventListener('click', function(e) {
|
form.addEventListener('submit', handleCredentials);
|
||||||
if (e.target === this) {
|
|
||||||
|
const cancelBtn = document.getElementById('cancelAuthBtn');
|
||||||
|
if (cancelBtn) {
|
||||||
|
cancelBtn.addEventListener('click', closeCredentialPrompt);
|
||||||
|
}
|
||||||
|
|
||||||
|
const overlay = document.querySelector('#credentialPrompt .credential-overlay');
|
||||||
|
if (overlay) {
|
||||||
|
overlay.addEventListener('click', function(e) {
|
||||||
|
if (e.target === overlay) {
|
||||||
closeCredentialPrompt();
|
closeCredentialPrompt();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeCredentialPrompt() {
|
function closeCredentialPrompt() {
|
||||||
|
|||||||
+66
-11
@@ -39,10 +39,12 @@
|
|||||||
<button class="refresh-btn" id="authBtn" onclick="toggleAuth()" style="background: var(--secondary);">
|
<button class="refresh-btn" id="authBtn" onclick="toggleAuth()" style="background: var(--secondary);">
|
||||||
<i class="fas fa-key"></i> <span id="authBtnText">Enter Credentials</span>
|
<i class="fas fa-key"></i> <span id="authBtnText">Enter Credentials</span>
|
||||||
</button>
|
</button>
|
||||||
<div class="search-box">
|
<button class="refresh-btn" id="hideOkBtn" onclick="toggleHideOkFilter()" style="background: var(--success);">
|
||||||
<i class="fas fa-search"></i>
|
<i class="fas fa-check-circle"></i> <span>Hide OK Remarks</span>
|
||||||
<input type="text" id="globalSearch" placeholder="Search orders, countries, VAT numbers..." oninput="handleGlobalSearch(this.value)">
|
</button>
|
||||||
</div>
|
<button class="refresh-btn" onclick="clearAllFilters()" style="background: var(--warning);">
|
||||||
|
<i class="fas fa-filter"></i> <span>Clear Filters</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="table-container">
|
<div class="table-container">
|
||||||
@@ -58,7 +60,14 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
Month
|
<div class="th-label">Month</div>
|
||||||
|
<div class="th-controls">
|
||||||
|
<input type="text"
|
||||||
|
class="column-filter"
|
||||||
|
placeholder="Filter Month"
|
||||||
|
data-column="Month"
|
||||||
|
oninput="handleColumnFilter(this)">
|
||||||
|
<div class="th-actions">
|
||||||
<div class="filter-indicator" onclick="toggleFilter('Month')">
|
<div class="filter-indicator" onclick="toggleFilter('Month')">
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</div>
|
</div>
|
||||||
@@ -66,9 +75,18 @@
|
|||||||
<i class="fas fa-arrow-up"></i>
|
<i class="fas fa-arrow-up"></i>
|
||||||
<i class="fas fa-arrow-down"></i>
|
<i class="fas fa-arrow-down"></i>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
Odoo AR Nr
|
<div class="th-label">Odoo AR Nr</div>
|
||||||
|
<div class="th-controls">
|
||||||
|
<input type="text"
|
||||||
|
class="column-filter"
|
||||||
|
placeholder="Filter Odoo AR Nr"
|
||||||
|
data-column="Odoo_AR_Nr"
|
||||||
|
oninput="handleColumnFilter(this)">
|
||||||
|
<div class="th-actions">
|
||||||
<div class="filter-indicator" onclick="toggleFilter('Odoo_AR_Nr')">
|
<div class="filter-indicator" onclick="toggleFilter('Odoo_AR_Nr')">
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</div>
|
</div>
|
||||||
@@ -76,9 +94,18 @@
|
|||||||
<i class="fas fa-arrow-up"></i>
|
<i class="fas fa-arrow-up"></i>
|
||||||
<i class="fas fa-arrow-down"></i>
|
<i class="fas fa-arrow-down"></i>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
Order ID
|
<div class="th-label">Order ID</div>
|
||||||
|
<div class="th-controls">
|
||||||
|
<input type="text"
|
||||||
|
class="column-filter"
|
||||||
|
placeholder="Filter Order ID"
|
||||||
|
data-column="Order_ID"
|
||||||
|
oninput="handleColumnFilter(this)">
|
||||||
|
<div class="th-actions">
|
||||||
<div class="filter-indicator" onclick="toggleFilter('Order_ID')">
|
<div class="filter-indicator" onclick="toggleFilter('Order_ID')">
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</div>
|
</div>
|
||||||
@@ -86,9 +113,18 @@
|
|||||||
<i class="fas fa-arrow-up"></i>
|
<i class="fas fa-arrow-up"></i>
|
||||||
<i class="fas fa-arrow-down"></i>
|
<i class="fas fa-arrow-down"></i>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
Country
|
<div class="th-label">Country</div>
|
||||||
|
<div class="th-controls">
|
||||||
|
<input type="text"
|
||||||
|
class="column-filter"
|
||||||
|
placeholder="Filter Country"
|
||||||
|
data-column="Country_Name"
|
||||||
|
oninput="handleColumnFilter(this)">
|
||||||
|
<div class="th-actions">
|
||||||
<div class="filter-indicator" onclick="toggleFilter('Country_Name')">
|
<div class="filter-indicator" onclick="toggleFilter('Country_Name')">
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</div>
|
</div>
|
||||||
@@ -96,9 +132,13 @@
|
|||||||
<i class="fas fa-arrow-up"></i>
|
<i class="fas fa-arrow-up"></i>
|
||||||
<i class="fas fa-arrow-down"></i>
|
<i class="fas fa-arrow-down"></i>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
VAT
|
<div class="th-label">VAT</div>
|
||||||
|
<div class="th-controls">
|
||||||
|
<div class="th-actions">
|
||||||
<div class="filter-indicator" onclick="toggleFilter('VAT')">
|
<div class="filter-indicator" onclick="toggleFilter('VAT')">
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</div>
|
</div>
|
||||||
@@ -106,9 +146,18 @@
|
|||||||
<i class="fas fa-arrow-up"></i>
|
<i class="fas fa-arrow-up"></i>
|
||||||
<i class="fas fa-arrow-down"></i>
|
<i class="fas fa-arrow-down"></i>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
Remark
|
<div class="th-label">Remark</div>
|
||||||
|
<div class="th-controls">
|
||||||
|
<input type="text"
|
||||||
|
class="column-filter"
|
||||||
|
placeholder="Filter Remark"
|
||||||
|
data-column="Remark"
|
||||||
|
oninput="handleColumnFilter(this)">
|
||||||
|
<div class="th-actions">
|
||||||
<div class="filter-indicator" onclick="toggleFilter('Remark')">
|
<div class="filter-indicator" onclick="toggleFilter('Remark')">
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</div>
|
</div>
|
||||||
@@ -116,9 +165,13 @@
|
|||||||
<i class="fas fa-arrow-up"></i>
|
<i class="fas fa-arrow-up"></i>
|
||||||
<i class="fas fa-arrow-down"></i>
|
<i class="fas fa-arrow-down"></i>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
Recheck
|
<div class="th-label">Recheck</div>
|
||||||
|
<div class="th-controls">
|
||||||
|
<div class="th-actions">
|
||||||
<div class="filter-indicator" onclick="toggleFilter('recheck')">
|
<div class="filter-indicator" onclick="toggleFilter('recheck')">
|
||||||
<i class="fas fa-filter"></i>
|
<i class="fas fa-filter"></i>
|
||||||
</div>
|
</div>
|
||||||
@@ -126,6 +179,8 @@
|
|||||||
<i class="fas fa-arrow-up"></i>
|
<i class="fas fa-arrow-up"></i>
|
||||||
<i class="fas fa-arrow-down"></i>
|
<i class="fas fa-arrow-down"></i>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|||||||
@@ -211,8 +211,7 @@ thead {
|
|||||||
}
|
}
|
||||||
|
|
||||||
th {
|
th {
|
||||||
padding: 1rem 1.5rem;
|
padding: 0.5rem;
|
||||||
text-align: left;
|
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: var(--dark);
|
color: var(--dark);
|
||||||
border-bottom: 2px solid var(--border);
|
border-bottom: 2px solid var(--border);
|
||||||
@@ -220,10 +219,62 @@ th {
|
|||||||
top: 0;
|
top: 0;
|
||||||
background: var(--light);
|
background: var(--light);
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
min-width: 130px;
|
||||||
|
vertical-align: top;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: table-cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
th:hover {
|
th .th-controls {
|
||||||
background: var(--hover);
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.35rem;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
th .th-label {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--dark);
|
||||||
|
white-space: nowrap;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 0.35rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-filter {
|
||||||
|
width: 90px;
|
||||||
|
padding: 0.35rem 0.5rem;
|
||||||
|
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-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.35rem;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
th .sort-indicator {
|
th .sort-indicator {
|
||||||
|
|||||||
Reference in New Issue
Block a user