favicon, filter update
This commit is contained in:
parent
6b05917352
commit
326c45cca0
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 850 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
|
|
@ -8,6 +8,9 @@
|
||||||
<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
|
<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
|
||||||
<script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
|
<script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
|
||||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||||
|
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="/favicon.png">
|
||||||
|
<link rel="apple-touch-icon" sizes="192x192" href="/favicon-192.png">
|
||||||
<style>
|
<style>
|
||||||
.modal {
|
.modal {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,12 @@ function isPartiallyPaid(inv) {
|
||||||
const balance = parseFloat(inv.balance) ?? ((parseFloat(inv.total) || 0) - amountPaid);
|
const balance = parseFloat(inv.balance) ?? ((parseFloat(inv.total) || 0) - amountPaid);
|
||||||
return !inv.paid_date && amountPaid > 0 && balance > 0;
|
return !inv.paid_date && amountPaid > 0 && balance > 0;
|
||||||
}
|
}
|
||||||
|
function isSent(inv) {
|
||||||
|
return !!inv.qbo_id && !isPaid(inv) && !isPartiallyPaid(inv) && !isOverdue(inv) && inv.email_status === 'sent';
|
||||||
|
}
|
||||||
|
function isOpen(inv) {
|
||||||
|
return !!inv.qbo_id && !isPaid(inv) && !isPartiallyPaid(inv) && !isOverdue(inv) && inv.email_status !== 'sent';
|
||||||
|
}
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
localStorage.setItem('inv_filterStatus', filterStatus);
|
localStorage.setItem('inv_filterStatus', filterStatus);
|
||||||
|
|
@ -117,8 +123,9 @@ function getFilteredInvoices() {
|
||||||
if (filterStatus === 'unpaid') f = f.filter(i => !isPaid(i));
|
if (filterStatus === 'unpaid') f = f.filter(i => !isPaid(i));
|
||||||
else if (filterStatus === 'paid') f = f.filter(i => isPaid(i));
|
else if (filterStatus === 'paid') f = f.filter(i => isPaid(i));
|
||||||
else if (filterStatus === 'overdue') f = f.filter(i => isOverdue(i));
|
else if (filterStatus === 'overdue') f = f.filter(i => isOverdue(i));
|
||||||
else if (filterStatus === 'draft') f = f.filter(i => isDraft(i) && !isPaid(i));
|
|
||||||
else if (filterStatus === 'partial') f = f.filter(i => isPartiallyPaid(i));
|
else if (filterStatus === 'partial') f = f.filter(i => isPartiallyPaid(i));
|
||||||
|
else if (filterStatus === 'sent') f = f.filter(i => isSent(i));
|
||||||
|
else if (filterStatus === 'open') f = f.filter(i => isOpen(i));
|
||||||
|
|
||||||
if (filterCustomer.trim()) {
|
if (filterCustomer.trim()) {
|
||||||
const s = filterCustomer.toLowerCase();
|
const s = filterCustomer.toLowerCase();
|
||||||
|
|
@ -321,21 +328,22 @@ function updateStatusButtons() {
|
||||||
btn.classList.toggle('text-gray-600', s !== filterStatus);
|
btn.classList.toggle('text-gray-600', s !== filterStatus);
|
||||||
});
|
});
|
||||||
|
|
||||||
const overdueCount = invoices.filter(i => isOverdue(i)).length;
|
const counts = {
|
||||||
const ob = document.getElementById('overdue-badge');
|
unpaid: invoices.filter(i => !isPaid(i)).length,
|
||||||
if (ob) { ob.textContent = overdueCount; ob.classList.toggle('hidden', overdueCount === 0); }
|
open: invoices.filter(i => isOpen(i)).length,
|
||||||
|
sent: invoices.filter(i => isSent(i)).length,
|
||||||
|
partial: invoices.filter(i => isPartiallyPaid(i)).length,
|
||||||
|
paid: invoices.filter(i => isPaid(i)).length,
|
||||||
|
overdue: invoices.filter(i => isOverdue(i)).length
|
||||||
|
};
|
||||||
|
|
||||||
const draftCount = invoices.filter(i => isDraft(i) && !isPaid(i)).length;
|
['unpaid', 'open', 'sent', 'partial', 'paid', 'overdue'].forEach(key => {
|
||||||
const db = document.getElementById('draft-badge');
|
const el = document.getElementById(`${key}-badge`);
|
||||||
if (db) { db.textContent = draftCount; db.classList.toggle('hidden', draftCount === 0); }
|
if (el) {
|
||||||
|
el.textContent = counts[key];
|
||||||
const unpaidCount = invoices.filter(i => !isPaid(i)).length;
|
el.classList.toggle('hidden', counts[key] === 0);
|
||||||
const ub = document.getElementById('unpaid-badge');
|
}
|
||||||
if (ub) ub.textContent = unpaidCount;
|
});
|
||||||
|
|
||||||
const partialCount = invoices.filter(i => isPartiallyPaid(i)).length;
|
|
||||||
const pb = document.getElementById('partial-badge');
|
|
||||||
if (pb) { pb.textContent = partialCount; pb.classList.toggle('hidden', partialCount === 0); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
@ -351,19 +359,23 @@ export function injectToolbar() {
|
||||||
<button data-status-filter="all" onclick="window.invoiceView.setStatus('all')"
|
<button data-status-filter="all" onclick="window.invoiceView.setStatus('all')"
|
||||||
class="px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-white text-gray-600">All</button>
|
class="px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-white text-gray-600">All</button>
|
||||||
<button data-status-filter="unpaid" onclick="window.invoiceView.setStatus('unpaid')"
|
<button data-status-filter="unpaid" onclick="window.invoiceView.setStatus('unpaid')"
|
||||||
class="px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-white text-gray-600">
|
class="relative px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-white text-gray-600">Unpaid
|
||||||
Unpaid <span id="unpaid-badge" class="ml-1 text-xs opacity-80"></span></button>
|
<span id="unpaid-badge" class="hidden absolute -top-1.5 -right-1.5 bg-gray-500 text-white text-xs rounded-full w-4 h-4 flex items-center justify-center">0</span></button>
|
||||||
|
<button data-status-filter="open" onclick="window.invoiceView.setStatus('open')"
|
||||||
|
class="relative px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-white text-gray-600">Open
|
||||||
|
<span id="open-badge" class="hidden absolute -top-1.5 -right-1.5 bg-orange-500 text-white text-xs rounded-full w-4 h-4 flex items-center justify-center">0</span></button>
|
||||||
|
<button data-status-filter="sent" onclick="window.invoiceView.setStatus('sent')"
|
||||||
|
class="relative px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-white text-gray-600">Sent
|
||||||
|
<span id="sent-badge" class="hidden absolute -top-1.5 -right-1.5 bg-cyan-500 text-white text-xs rounded-full w-4 h-4 flex items-center justify-center">0</span></button>
|
||||||
<button data-status-filter="partial" onclick="window.invoiceView.setStatus('partial')"
|
<button data-status-filter="partial" onclick="window.invoiceView.setStatus('partial')"
|
||||||
class="relative px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-white text-gray-600">Partial
|
class="relative px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-white text-gray-600">Partial
|
||||||
<span id="partial-badge" class="hidden absolute -top-1.5 -right-1.5 bg-yellow-500 text-white text-xs rounded-full w-4 h-4 flex items-center justify-center">0</span></button>
|
<span id="partial-badge" class="hidden absolute -top-1.5 -right-1.5 bg-yellow-500 text-white text-xs rounded-full w-4 h-4 flex items-center justify-center">0</span></button>
|
||||||
<button data-status-filter="paid" onclick="window.invoiceView.setStatus('paid')"
|
<button data-status-filter="paid" onclick="window.invoiceView.setStatus('paid')"
|
||||||
class="px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-white text-gray-600">Paid</button>
|
class="relative px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-white text-gray-600">Paid
|
||||||
|
<span id="paid-badge" class="hidden absolute -top-1.5 -right-1.5 bg-green-500 text-white text-xs rounded-full w-4 h-4 flex items-center justify-center">0</span></button>
|
||||||
<button data-status-filter="overdue" onclick="window.invoiceView.setStatus('overdue')"
|
<button data-status-filter="overdue" onclick="window.invoiceView.setStatus('overdue')"
|
||||||
class="relative px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-white text-gray-600">Overdue
|
class="relative px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-white text-gray-600">Overdue
|
||||||
<span id="overdue-badge" class="hidden absolute -top-1.5 -right-1.5 bg-red-500 text-white text-xs rounded-full w-4 h-4 flex items-center justify-center">0</span></button>
|
<span id="overdue-badge" class="hidden absolute -top-1.5 -right-1.5 bg-red-500 text-white text-xs rounded-full w-4 h-4 flex items-center justify-center">0</span></button>
|
||||||
<button data-status-filter="draft" onclick="window.invoiceView.setStatus('draft')"
|
|
||||||
class="relative px-3 py-1.5 text-xs font-medium rounded-md transition-colors bg-white text-gray-600">Draft
|
|
||||||
<span id="draft-badge" class="hidden absolute -top-1.5 -right-1.5 bg-gray-500 text-white text-xs rounded-full w-4 h-4 flex items-center justify-center">0</span></button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="w-px h-8 bg-gray-300"></div>
|
<div class="w-px h-8 bg-gray-300"></div>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue