From f4c1a5cf960a436062b94784ecec35b8d5dc879e Mon Sep 17 00:00:00 2001 From: oliver Date: Sun, 14 Jun 2026 20:20:36 -0300 Subject: [PATCH] design --- app.js | 149 ++++++++++++++++++++++++-------- index.html | 243 +++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 341 insertions(+), 51 deletions(-) diff --git a/app.js b/app.js index fd65232..1101630 100644 --- a/app.js +++ b/app.js @@ -1399,27 +1399,40 @@ async function crmLoadRecords() { /* ─── CRM — Render table ────────────────────────────────────────── */ function crmRender() { - const search = ( - document.getElementById("crm-search")?.value ?? "" + const searchName = ( + document.getElementById("crm-search-name")?.value ?? "" + ).toLowerCase(); + const searchCompany = ( + document.getElementById("crm-search-company")?.value ?? "" + ).toLowerCase(); + const searchEmail = ( + document.getElementById("crm-search-email")?.value ?? "" + ).toLowerCase(); + const searchStage = ( + document.getElementById("crm-search-stage")?.value ?? "" + ).toLowerCase(); + const searchStrategy = ( + document.getElementById("crm-search-strategy")?.value ?? "" + ).toLowerCase(); + const searchCategory = ( + document.getElementById("crm-search-category")?.value ?? "" ).toLowerCase(); const filtered = crmRecords.filter((r) => { - if (!search) return true; - const haystack = [ - r.Name, - r.Company, - r.email, - r.Stage, - r.strategy, - r.category, - r.affiliate, - r.History, - r.Number, - ] - .filter((v) => v != null) - .join(" ") - .toLowerCase(); - return haystack.includes(search); + const name = (r.Name ?? "").toLowerCase(); + const company = (r.Company ?? "").toLowerCase(); + const email = (r.email ?? "").toLowerCase(); + const stage = (r.Stage ?? "").toLowerCase(); + const strategy = (r.strategy ?? "").toLowerCase(); + const category = (r.category ?? "").toLowerCase(); + return ( + (!searchName || name.includes(searchName)) && + (!searchCompany || company.includes(searchCompany)) && + (!searchEmail || email.includes(searchEmail)) && + (!searchStage || stage.includes(searchStage)) && + (!searchStrategy || strategy.includes(searchStrategy)) && + (!searchCategory || category.includes(searchCategory)) + ); }); const total = crmRecords.length; @@ -1435,7 +1448,7 @@ function crmRender() { const tbody = document.getElementById("crm-table-body"); if (filtered.length === 0) { - tbody.innerHTML = `
+ tbody.innerHTML = `
@@ -1460,27 +1473,16 @@ function crmRender() { const dateNext = r.date_next_contact ? formatDate(r.date_next_contact) : "—"; - return `
- + // Prevent row click when clicking the checkbox + return `
+
${name || "—"} ${company || "—"} - ${email || "—"} + ${email || "—"} ${stage || "—"} ${strategy || "—"} ${category ? escHtml(category) : "—"} ${dateNext} - - - `; }) .join(""); @@ -1493,8 +1495,7 @@ function crmUpdateDeleteBtn() { const checked = document.querySelectorAll(".crm-select:checked").length; const btn = document.getElementById("crm-delete-selected-btn"); btn.disabled = checked === 0; - const label = - checked > 0 ? `Delete Selected (${checked})` : "Delete Selected"; + const label = checked > 0 ? `Delete Checked (${checked})` : "Delete Checked"; btn.innerHTML = ` @@ -1575,6 +1576,82 @@ async function crmDeleteSelected() { await crmLoadRecords(); } +/* ─── CRM — Edit modal ──────────────────────────────────────────── */ +function crmOpenEdit(id) { + const r = crmRecords.find((c) => c.id === id); + if (!r) return; + + document.getElementById("crm-edit-id").value = r.id; + document.getElementById("crm-edit-name").value = r.Name ?? ""; + document.getElementById("crm-edit-company").value = r.Company ?? ""; + document.getElementById("crm-edit-email").value = r.email ?? ""; + document.getElementById("crm-edit-stage").value = r.Stage ?? ""; + document.getElementById("crm-edit-strategy").value = r.strategy ?? ""; + document.getElementById("crm-edit-category").value = r.category ?? ""; + document.getElementById("crm-edit-affiliate").value = r.affiliate ?? ""; + document.getElementById("crm-edit-number").value = r.Number ?? ""; + document.getElementById("crm-edit-date-next").value = r.date_next_contact + ? r.date_next_contact.split("T")[0] + : ""; + document.getElementById("crm-edit-history").value = r.History ?? ""; + + document.getElementById("crm-edit-title").textContent = + `Edit Contact — ${r.Name || r.email || `#${r.id}`}`; + document.getElementById("crm-edit-backdrop").classList.add("open"); + setTimeout(() => document.getElementById("crm-edit-name").focus(), 80); +} + +function crmCloseEdit() { + document.getElementById("crm-edit-backdrop").classList.remove("open"); +} + +document.getElementById("crm-edit-backdrop")?.addEventListener("click", (e) => { + if (e.target === e.currentTarget) crmCloseEdit(); +}); + +async function crmSaveEdit() { + const id = Number(document.getElementById("crm-edit-id").value); + const payload = { + id, + Name: document.getElementById("crm-edit-name").value.trim(), + Company: document.getElementById("crm-edit-company").value.trim(), + email: document.getElementById("crm-edit-email").value.trim(), + Stage: document.getElementById("crm-edit-stage").value, + strategy: document.getElementById("crm-edit-strategy").value.trim(), + category: document.getElementById("crm-edit-category").value.trim(), + affiliate: document.getElementById("crm-edit-affiliate").value.trim(), + Number: document.getElementById("crm-edit-number").value.trim(), + date_next_contact: + document.getElementById("crm-edit-date-next").value || null, + History: document.getElementById("crm-edit-history").value.trim(), + }; + + const btn = document.getElementById("crm-save-btn"); + btn.disabled = true; + const orig = btn.innerHTML; + btn.innerHTML = `
Saving…`; + + try { + const res = await apiFetch(apiUrl(ROUTES.crm), { + method: "PUT", + headers: apiHeaders(), + body: JSON.stringify(payload), + }); + if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`); + toast( + `Contact “${payload.Name || payload.email || `#${id}`}” updated`, + "success", + ); + crmCloseEdit(); + await crmLoadRecords(); + } catch (err) { + toast("Save failed: " + err.message, "error"); + } finally { + btn.disabled = false; + btn.innerHTML = orig; + } +} + /* ─── Init ────────────────────────────────────────────────────────── */ settingsLoad(); const _boot = getCookie("al_session"); diff --git a/index.html b/index.html index b600c07..249f714 100644 --- a/index.html +++ b/index.html @@ -730,22 +730,11 @@
-
- -
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
@@ -826,7 +881,6 @@ Strategy Category Date Next Contact - Actions @@ -1032,6 +1086,165 @@
+ + +