new filters
This commit is contained in:
@@ -6,8 +6,8 @@ let filterCustomer = localStorage.getItem('inv_filterCustomer') || '';
|
||||
let filterStatus = localStorage.getItem('inv_filterStatus') || 'unpaid';
|
||||
let groupBy = localStorage.getItem('inv_groupBy') || 'none';
|
||||
let filterWorker = localStorage.getItem('inv_filterWorker') || '';
|
||||
let filterParts = localStorage.getItem('inv_filterParts') === 'true';
|
||||
let filterEmptyCost = localStorage.getItem('inv_filterEmptyCost') === 'true';
|
||||
let filterCategory = localStorage.getItem('inv_filterCategory') || '';
|
||||
let filterItemSearch = localStorage.getItem('inv_filterItemSearch') || '';
|
||||
|
||||
const OVERDUE_DAYS = 30;
|
||||
|
||||
@@ -198,8 +198,8 @@ function saveSettings() {
|
||||
localStorage.setItem('inv_groupBy', groupBy);
|
||||
localStorage.setItem('inv_filterCustomer', filterCustomer);
|
||||
localStorage.setItem('inv_filterWorker', filterWorker);
|
||||
localStorage.setItem('inv_filterParts', filterParts);
|
||||
localStorage.setItem('inv_filterEmptyCost', filterEmptyCost);
|
||||
localStorage.setItem('inv_filterCategory', filterCategory);
|
||||
localStorage.setItem('inv_filterItemSearch', filterItemSearch);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
@@ -209,10 +209,8 @@ function saveSettings() {
|
||||
export async function loadInvoices() {
|
||||
try {
|
||||
const params = new URLSearchParams();
|
||||
if (filterParts) {
|
||||
params.set('has_parts', 'true');
|
||||
if (filterEmptyCost) params.set('empty_cost_only', 'true');
|
||||
}
|
||||
if (filterCategory) params.set('category', filterCategory);
|
||||
if (filterItemSearch) params.set('item_search', filterItemSearch);
|
||||
const qs = params.toString();
|
||||
const url = qs ? `/api/invoices?${qs}` : '/api/invoices';
|
||||
const response = await fetch(url);
|
||||
@@ -610,11 +608,20 @@ export function injectToolbar() {
|
||||
</select>
|
||||
</div>
|
||||
<div class="w-px h-8 bg-gray-300"></div>
|
||||
<div class="flex items-center gap-1 border border-gray-300 rounded-lg p-1 bg-gray-100">
|
||||
<button id="filter-item-type" onclick="window.invoiceView.toggleParts()"
|
||||
class="px-3 py-1.5 text-xs font-medium rounded-md transition-colors ${filterParts ? 'bg-blue-500 text-white' : 'bg-white text-gray-600'}">Cost Items</button>
|
||||
<button id="filter-empty-cost" onclick="window.invoiceView.toggleEmptyCost()" style="${filterParts ? '' : 'display:none'}"
|
||||
class="px-3 py-1.5 text-xs font-medium rounded-md transition-colors ${filterEmptyCost ? 'bg-blue-500 text-white' : 'bg-white text-gray-600'}">Empty cost only</button>
|
||||
<div class="flex items-center gap-2">
|
||||
<label class="text-sm font-medium text-gray-700">Category:</label>
|
||||
<select id="invoice-filter-category" class="px-3 py-1.5 border border-gray-300 rounded-md text-sm bg-white">
|
||||
<option value="">All</option>
|
||||
<option value="9" ${filterCategory === '9' ? 'selected' : ''}>Parts</option>
|
||||
<option value="115" ${filterCategory === '115' ? 'selected' : ''}>Subscription</option>
|
||||
<option value="5" ${filterCategory === '5' ? 'selected' : ''}>Labor</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="w-px h-8 bg-gray-300"></div>
|
||||
<div class="flex items-center gap-2">
|
||||
<label class="text-sm font-medium text-gray-700">Item:</label>
|
||||
<input type="text" id="invoice-filter-item-search" placeholder="Search descriptions..." value="${filterItemSearch}"
|
||||
class="px-3 py-1.5 border border-gray-300 rounded-md text-sm w-48 focus:ring-blue-500 focus:border-blue-500">
|
||||
</div>
|
||||
<div class="w-px h-8 bg-gray-300"></div>
|
||||
<div class="ml-auto flex items-center gap-4">
|
||||
@@ -636,6 +643,12 @@ export function injectToolbar() {
|
||||
populateWorkerFilter();
|
||||
document.getElementById('invoice-filter-worker').addEventListener('change', (e) => {
|
||||
filterWorker = e.target.value; saveSettings(); renderInvoiceView();
|
||||
});
|
||||
document.getElementById('invoice-filter-category').addEventListener('change', (e) => {
|
||||
filterCategory = e.target.value; saveSettings(); loadInvoices();
|
||||
});
|
||||
document.getElementById('invoice-filter-item-search').addEventListener('input', (e) => {
|
||||
filterItemSearch = e.target.value; saveSettings(); loadInvoices();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -644,37 +657,6 @@ export function injectToolbar() {
|
||||
// ============================================================
|
||||
|
||||
export function setStatus(s) { filterStatus = s; saveSettings(); renderInvoiceView(); }
|
||||
export function toggleParts() {
|
||||
filterParts = !filterParts;
|
||||
if (!filterParts) filterEmptyCost = false;
|
||||
saveSettings();
|
||||
const itemBtn = document.getElementById('filter-item-type');
|
||||
const emptyBtn = document.getElementById('filter-empty-cost');
|
||||
if (itemBtn) {
|
||||
itemBtn.className = filterParts
|
||||
? 'px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-blue-500 text-white'
|
||||
: 'px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-white text-gray-600';
|
||||
}
|
||||
if (emptyBtn) {
|
||||
emptyBtn.style.display = filterParts ? '' : 'none';
|
||||
emptyBtn.className = filterEmptyCost
|
||||
? 'px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-blue-500 text-white'
|
||||
: 'px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-white text-gray-600';
|
||||
}
|
||||
loadInvoices();
|
||||
}
|
||||
export function toggleEmptyCost() {
|
||||
if (!filterParts) return;
|
||||
filterEmptyCost = !filterEmptyCost;
|
||||
saveSettings();
|
||||
const btn = document.getElementById('filter-empty-cost');
|
||||
if (btn) {
|
||||
btn.className = filterEmptyCost
|
||||
? 'px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-blue-500 text-white'
|
||||
: 'px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-white text-gray-600';
|
||||
}
|
||||
loadInvoices();
|
||||
}
|
||||
export function viewPDF(id) { window.open(`/api/invoices/${id}/pdf`, '_blank'); }
|
||||
export function viewHTML(id) { window.open(`/api/invoices/${id}/html`, '_blank'); }
|
||||
|
||||
@@ -915,5 +897,5 @@ async function populateWorkerFilter() {
|
||||
|
||||
window.invoiceView = {
|
||||
viewPDF, viewHTML, syncFromQBO, resetQbo, markPaid, setEmailStatus, edit, remove,
|
||||
loadInvoices, renderInvoiceView, setStatus, toggleParts, toggleEmptyCost, checkStripePayment, editSentDates ,_addSentDateRow, _saveSentDates
|
||||
loadInvoices, renderInvoiceView, setStatus, checkStripePayment, editSentDates ,_addSentDateRow, _saveSentDates
|
||||
};
|
||||
Reference in New Issue
Block a user