invoices
This commit is contained in:
@@ -21,6 +21,8 @@ const CHAT_URL = `${API_BASE}/etc/chat`; // POST {message,sessionId,email}
|
||||
const REFERRAL_URL = `${API_BASE}/etc/referral`; // POST {referrer,friend_name,friend_email,uuid}
|
||||
// WIZZARD=false is written via AGENT_INFO_URL (POST { uuid, key, value })
|
||||
const CREDITS_URL = `${API_BASE}/payment/credits`; // hidden form POST → 302 Stripe redirect
|
||||
const INVOICES_URL = `${API_BASE}/invoices`; // GET ?email=
|
||||
const INVOICE_EMAIL_URL = `${API_BASE}/account/invoice-email`; // POST {email, invoice_email}
|
||||
const CONTRACT_EXTEND_URL = "https://derez.ai"; // ← replace with Stripe payment link
|
||||
const CONTRACT_CANCEL_URL = "https://derez.ai"; // ← replace with Stripe cancellation link
|
||||
|
||||
@@ -95,9 +97,11 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
if (e.target === e.currentTarget) confirmClose(false);
|
||||
});
|
||||
|
||||
// Close user panel when clicking outside of it
|
||||
// Close user panel when clicking outside of it (skip while modal is open)
|
||||
document.addEventListener("click", (e) => {
|
||||
const wrap = document.getElementById("user-panel-wrap");
|
||||
const modal = document.getElementById("account-backdrop");
|
||||
if (modal && modal.classList.contains("open")) return;
|
||||
if (wrap && !wrap.contains(e.target)) closeUserPanel();
|
||||
});
|
||||
});
|
||||
@@ -1008,25 +1012,23 @@ async function savePassword() {
|
||||
ACCOUNT / USER PANEL
|
||||
═══════════════════════════════════════════════════════════════ */
|
||||
function toggleUserPanel() {
|
||||
const panel = document.getElementById("user-panel");
|
||||
if (!panel) return;
|
||||
if (panel.style.display === "none" || panel.style.display === "") {
|
||||
document.getElementById("user-panel-email-val").textContent =
|
||||
currentEmail || "—";
|
||||
panel.style.display = "block";
|
||||
} else {
|
||||
closeUserPanel();
|
||||
}
|
||||
const backdrop = document.getElementById("account-backdrop");
|
||||
document.getElementById("acct-email-display").textContent =
|
||||
currentEmail || "—";
|
||||
const invInput = document.getElementById("invoice-email-input");
|
||||
if (invInput) invInput.value = localStorage.getItem("al_invoice_email") || "";
|
||||
backdrop.classList.add("open");
|
||||
loadInvoices();
|
||||
}
|
||||
|
||||
function closeUserPanel() {
|
||||
const panel = document.getElementById("user-panel");
|
||||
if (!panel) return;
|
||||
panel.style.display = "none";
|
||||
document.getElementById("account-backdrop").classList.remove("open");
|
||||
const inp = document.getElementById("acct-pw-input");
|
||||
if (inp) inp.value = "";
|
||||
const btn = document.getElementById("acct-pw-save-btn");
|
||||
if (btn) btn.style.display = "none";
|
||||
const invBtn = document.getElementById("invoice-email-save-btn");
|
||||
if (invBtn) invBtn.style.display = "none";
|
||||
}
|
||||
|
||||
function toggleAccountPwSave(value) {
|
||||
@@ -1079,6 +1081,84 @@ async function saveAccountPassword() {
|
||||
}
|
||||
}
|
||||
|
||||
function toggleInvoiceEmailSave(value) {
|
||||
const btn = document.getElementById("invoice-email-save-btn");
|
||||
if (btn) btn.style.display = value ? "flex" : "none";
|
||||
}
|
||||
|
||||
async function saveInvoiceEmail() {
|
||||
const input = document.getElementById("invoice-email-input");
|
||||
const btn = document.getElementById("invoice-email-save-btn");
|
||||
const email = input.value.trim();
|
||||
|
||||
if (!email || !isValidEmail(email)) {
|
||||
toast("Please enter a valid email address.", "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
btnLoad(btn, "");
|
||||
try {
|
||||
const res = await apiFetch(INVOICE_EMAIL_URL, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ email: currentEmail, invoice_email: email }),
|
||||
});
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
localStorage.setItem("al_invoice_email", email);
|
||||
toast("Invoice email saved.", "success");
|
||||
btn.style.display = "none";
|
||||
} catch (err) {
|
||||
toast(err.message, "error");
|
||||
} finally {
|
||||
btnReset(btn);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadInvoices() {
|
||||
const body = document.getElementById("invoices-body");
|
||||
body.innerHTML = '<div class="loading-row"><div class="spinner"></div></div>';
|
||||
try {
|
||||
const res = await apiFetch(
|
||||
`${INVOICES_URL}?email=${encodeURIComponent(currentEmail || "")}`,
|
||||
);
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
const data = await res.json();
|
||||
renderInvoices(Array.isArray(data) ? data : []);
|
||||
} catch (err) {
|
||||
body.innerHTML =
|
||||
'<p class="text-muted" style="font-size:13px;padding:4px 0;">Could not load invoices.</p>';
|
||||
}
|
||||
}
|
||||
|
||||
function renderInvoices(data) {
|
||||
const body = document.getElementById("invoices-body");
|
||||
if (!data.length) {
|
||||
body.innerHTML =
|
||||
'<p class="text-muted" style="font-size:13px;padding:4px 0;">No invoices yet.</p>';
|
||||
return;
|
||||
}
|
||||
body.innerHTML = `
|
||||
<div class="invoice-list">
|
||||
<div class="invoice-row invoice-row--head">
|
||||
<span>Date</span>
|
||||
<span>Agent</span>
|
||||
<span>Product</span>
|
||||
<span>Price</span>
|
||||
</div>
|
||||
${data
|
||||
.map(
|
||||
(inv) => `
|
||||
<div class="invoice-row">
|
||||
<span class="invoice-date">${escHtml(inv.date || "—")}</span>
|
||||
<span class="invoice-uuid">${escHtml(inv.uuid || "—")}</span>
|
||||
<span class="invoice-product">${escHtml(inv.product || "—")}</span>
|
||||
<span class="invoice-price">€ ${escHtml(String(inv.price ?? "—"))}</span>
|
||||
</div>`,
|
||||
)
|
||||
.join("")}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
RESTART
|
||||
═══════════════════════════════════════════════════════════════ */
|
||||
|
||||
Reference in New Issue
Block a user