filter, export
This commit is contained in:
@@ -46,7 +46,8 @@ let wizardSelectedSkills = new Set();
|
|||||||
let wizardSelectedIntegrations = new Set();
|
let wizardSelectedIntegrations = new Set();
|
||||||
let wizardFieldValues = {}; // { stepIndex: { fieldKey: value } }
|
let wizardFieldValues = {}; // { stepIndex: { fieldKey: value } }
|
||||||
let wizardIntegrationStep = 0; // current index in fields phase
|
let wizardIntegrationStep = 0; // current index in fields phase
|
||||||
let wizardSelectedIntegrationList = []; // ordered list of selected integration objects
|
let wizardSelectedIntegrationList = [];
|
||||||
|
let invoicesData = []; // cached full invoice list for filtering/export
|
||||||
|
|
||||||
/* ─── Debug logger ─────────────────────────────────────────── */
|
/* ─── Debug logger ─────────────────────────────────────────── */
|
||||||
function dbg(label, data) {
|
function dbg(label, data) {
|
||||||
@@ -1196,7 +1197,10 @@ async function loadInvoices() {
|
|||||||
} else {
|
} else {
|
||||||
data = [];
|
data = [];
|
||||||
}
|
}
|
||||||
renderInvoices(data);
|
invoicesData = data;
|
||||||
|
applyInvoiceFilter();
|
||||||
|
const filterInput = document.getElementById("invoice-filter");
|
||||||
|
if (filterInput) filterInput.value = "";
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
dbg("\u2190 Invoices error", err.message);
|
dbg("\u2190 Invoices error", err.message);
|
||||||
body.innerHTML =
|
body.innerHTML =
|
||||||
@@ -1204,6 +1208,22 @@ async function loadInvoices() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function applyInvoiceFilter() {
|
||||||
|
const q = (
|
||||||
|
document.getElementById("invoice-filter").value || ""
|
||||||
|
).toLowerCase();
|
||||||
|
const filtered = q
|
||||||
|
? invoicesData.filter(
|
||||||
|
(inv) =>
|
||||||
|
(inv.date || "").toLowerCase().includes(q) ||
|
||||||
|
(inv.uuid || "").toLowerCase().includes(q) ||
|
||||||
|
(inv.product || "").toLowerCase().includes(q) ||
|
||||||
|
(inv.price || "").toLowerCase().includes(q),
|
||||||
|
)
|
||||||
|
: invoicesData;
|
||||||
|
renderInvoices(filtered);
|
||||||
|
}
|
||||||
|
|
||||||
function renderInvoices(data) {
|
function renderInvoices(data) {
|
||||||
const body = document.getElementById("invoices-body");
|
const body = document.getElementById("invoices-body");
|
||||||
if (!data.length) {
|
if (!data.length) {
|
||||||
@@ -1233,6 +1253,42 @@ function renderInvoices(data) {
|
|||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function exportInvoicesCSV() {
|
||||||
|
const q = (
|
||||||
|
document.getElementById("invoice-filter").value || ""
|
||||||
|
).toLowerCase();
|
||||||
|
const filtered = q
|
||||||
|
? invoicesData.filter(
|
||||||
|
(inv) =>
|
||||||
|
(inv.date || "").toLowerCase().includes(q) ||
|
||||||
|
(inv.uuid || "").toLowerCase().includes(q) ||
|
||||||
|
(inv.product || "").toLowerCase().includes(q) ||
|
||||||
|
(inv.price || "").toLowerCase().includes(q),
|
||||||
|
)
|
||||||
|
: invoicesData;
|
||||||
|
if (!filtered.length) {
|
||||||
|
toast("No invoices to export.", "warning");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const rows = ["Date,Agent,Product,Price"];
|
||||||
|
for (const inv of filtered) {
|
||||||
|
rows.push(
|
||||||
|
[inv.date || "", inv.uuid || "", inv.product || "", inv.price || ""].join(
|
||||||
|
",",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const blob = new Blob([rows.join("\n")], { type: "text/csv" });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = url;
|
||||||
|
a.download = "invoices.csv";
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
|
|
||||||
/* ═══════════════════════════════════════════════════════════════
|
/* ═══════════════════════════════════════════════════════════════
|
||||||
RESTART
|
RESTART
|
||||||
═══════════════════════════════════════════════════════════════ */
|
═══════════════════════════════════════════════════════════════ */
|
||||||
|
|||||||
+18
@@ -937,7 +937,25 @@
|
|||||||
<div class="account-col-divider"></div>
|
<div class="account-col-divider"></div>
|
||||||
<!-- ── Right: invoices ──────────────────────── -->
|
<!-- ── Right: invoices ──────────────────────── -->
|
||||||
<div class="account-col account-col--invoices">
|
<div class="account-col account-col--invoices">
|
||||||
|
<div class="acct-invoices-toolbar">
|
||||||
<div class="acct-invoices-title">Invoices</div>
|
<div class="acct-invoices-title">Invoices</div>
|
||||||
|
<div class="acct-invoices-actions">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="invoice-filter"
|
||||||
|
class="invoice-filter-input"
|
||||||
|
placeholder="Filter invoices…"
|
||||||
|
oninput="applyInvoiceFilter()"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-ghost btn-sm"
|
||||||
|
onclick="exportInvoicesCSV()"
|
||||||
|
>
|
||||||
|
Export CSV
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div id="invoices-body"></div>
|
<div id="invoices-body"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user