Manage token auth, licenses, and calculator behavior from a single control panel.
Not authenticated
Admin Token
Token is stored in sessionStorage (browser session only).
Calculator Origin
Used for embed + Open Calculator.
License Management
Store hostnames only (no protocol, paths, or trailing slashes).
Embed Code Per-license
The iframe will auto-resize based on the calculator's content height.
Configuration JSON
Locations
Fee is optional for “other”; leave blank to omit.
Line Items
Edits below immediately update the Configuration JSON.
Calculator Inputs
End-users enter the amount at runtime. Do not set a default fee here.
License Dashboard
License Key Status Firm Firm Phone Contact Name Contact Phone Contact Email Valid Through Actions
Response
No response yet
`; } function parseConfigJsonOrThrow() { const raw = (configJsonEl.value || "").trim(); if (!raw) return {}; try { return ensureBrokerConfig(JSON.parse(raw)); } catch { throw new Error("Config JSON is invalid."); } } function prettifyConfigJson() { const obj = parseConfigJsonOrThrow(); configJsonEl.value = JSON.stringify(obj, null, 2); } function getRecordFromUI() { const key = (licenseKeyEl.value || "").trim(); if (!key) throw new Error("Missing license key."); const status = String(statusEl.value || "active").trim().toLowerCase(); if (!["active","inactive"].includes(status)) throw new Error("Status must be active or inactive."); const allowNoReferer = !!allowNoRefererEl.checked; const configObj = parseConfigJsonOrThrow(); return { key, record: { status, allowedDomains: getDomainsFromUI(), allowNoReferer, config: configObj } }; } function fillUIFromRecord(key, record) { licenseKeyEl.value = key || ""; statusEl.value = record?.status === "inactive" ? "inactive" : "active"; allowNoRefererEl.checked = record?.allowNoReferer === true; setDomainsUI(record?.allowedDomains || []); const cfg = record?.config ? ensureBrokerConfig(record.config) : null; configJsonEl.value = cfg ? JSON.stringify(cfg, null, 2) : ""; updateEmbedBox(); loadLocationsFromConfig(); loadBrokerSettingsFromConfig(); renderQuickEditor(); } // -------------------- Locations editor -------------------- function setLocationsStatus(msg) { if (locationsStatusEl) locationsStatusEl.textContent = msg || ""; } function loadLocationsFromConfig() { let cfg; try { cfg = parseConfigJsonOrThrow(); } catch (e) { setLocationsStatus(e.message || "Invalid JSON"); return; } const counties = cfg.ui?.labels?.county || {}; const countyLines = Object.keys(counties).map((k) => `${k} = ${counties[k]}`); if (countyListInput) countyListInput.value = countyLines.join("\n"); const muniLabels = cfg.ui?.labels?.muni || {}; const muniFees = cfg.municipalFees || {}; const muniLines = Object.keys(muniLabels).map((k) => { const fee = muniFees[k]; const feePart = Number.isFinite(fee) ? ` | ${fee}` : ""; return `${k} = ${muniLabels[k]}${feePart}`; }); if (muniListInput) muniListInput.value = muniLines.join("\n"); setLocationsStatus("Loaded"); } function parseKeyLabelFee(line) { const [left, feePart] = line.split("|").map(s => s.trim()); if (!left) return null; const [keyRaw, ...labelParts] = left.split("="); const key = (keyRaw || "").trim(); const label = labelParts.join("=").trim(); if (!key || !label) return null; const fee = feePart ? Number(feePart) : NaN; return { key, label, fee: Number.isFinite(fee) ? fee : null }; } function applyLocationsToConfig() { let cfg; try { cfg = parseConfigJsonOrThrow(); } catch (e) { setLocationsStatus(e.message || "Invalid JSON"); return; } const countyLines = (countyListInput?.value || "").split(/\n+/).map(l => l.trim()).filter(Boolean); const muniLines = (muniListInput?.value || "").split(/\n+/).map(l => l.trim()).filter(Boolean); const countyMap = {}; const countyOrder = []; countyLines.forEach((line) => { const [keyRaw, ...labelParts] = line.split("="); const key = (keyRaw || "").trim(); const label = labelParts.join("=").trim(); if (key && label) { countyMap[key] = label; countyOrder.push(key); } }); if (!Object.keys(countyMap).length) { setLocationsStatus("No counties parsed."); return; } const muniLabels = {}; const muniFees = {}; muniLines.forEach((line) => { const parsed = parseKeyLabelFee(line); if (!parsed) return; muniLabels[parsed.key] = parsed.label; if (parsed.fee !== null) muniFees[parsed.key] = parsed.fee; }); if (!Object.keys(muniLabels).length) { setLocationsStatus("No municipal entries parsed."); return; } cfg.ui = cfg.ui || {}; cfg.ui.labels = cfg.ui.labels || {}; cfg.ui.labels.county = countyMap; cfg.ui.countyOrder = countyOrder; cfg.ui.labels.muni = muniLabels; cfg.municipalFees = muniFees; configJsonEl.value = JSON.stringify(cfg, null, 2); setLocationsStatus("Applied"); renderQuickEditor(); } // -------------------- Broker fee visibility -------------------- function setBrokerStatus(msg) { if (brokerStatusEl) brokerStatusEl.textContent = msg || ""; } function loadBrokerSettingsFromConfig() { try { const cfg = parseConfigJsonOrThrow(); const show = cfg.ui?.showBrokerTransactionFee !== false; const payer = (cfg.ui?.defaults?.brokerTransactionFeePayer === "seller") ? "seller" : "buyer"; if (brokerFeeEnabledEl) brokerFeeEnabledEl.checked = show; if (brokerFeeDefaultPayerEl) brokerFeeDefaultPayerEl.value = payer; setBrokerStatus("Loaded"); } catch (e) { setBrokerStatus(e.message || "Invalid JSON"); } } function applyBrokerSettingsToConfig() { try { const cfg = parseConfigJsonOrThrow(); cfg.ui = cfg.ui || {}; cfg.ui.defaults = cfg.ui.defaults || {}; cfg.ui.showBrokerTransactionFee = brokerFeeEnabledEl ? !!brokerFeeEnabledEl.checked : true; cfg.ui.defaults.brokerTransactionFeePayer = (brokerFeeDefaultPayerEl?.value === "seller") ? "seller" : "buyer"; configJsonEl.value = JSON.stringify(cfg, null, 2); setBrokerStatus("Applied"); renderQuickEditor(); } catch (e) { setBrokerStatus(e.message || "Invalid JSON"); } } // -------------------- Quick line item editor -------------------- let quickWorkingConfig = null; function setQuickStatus(msg) { if (quickStatusEl) quickStatusEl.textContent = msg || ""; } function normalizePaidBy(p) { if (!p || typeof p !== "object") return { type: "buyer" }; if (p.type === "seller") return { type: "seller" }; if (p.type === "split") { const b = Number.isFinite(p.buyerPct) ? p.buyerPct : 50; const s = Number.isFinite(p.sellerPct) ? p.sellerPct : 50; return { type: "split", buyerPct: b, sellerPct: s }; } return { type: "buyer" }; } function writeQuickConfig() { if (!quickWorkingConfig) return; configJsonEl.value = JSON.stringify(quickWorkingConfig, null, 2); setQuickStatus("Updated JSON"); } function resolveAmountField(calc) { const t = calc?.type; if (t === "flat") return { field: "amount", label: "Amount" }; if (t === "perUnit") return { field: "unitAmount", label: "Unit" }; if (t === "eRecordingPerDocument") return { field: "perDocument", label: "Per doc" }; return null; } function renderQuickEditor() { if (!quickEditorEl) return; let cfg; try { cfg = parseConfigJsonOrThrow(); } catch (e) { quickEditorEl.innerHTML = ""; setQuickStatus(e.message || "Invalid JSON"); return; } quickWorkingConfig = cfg; const items = Array.isArray(cfg.lineItems) ? cfg.lineItems : []; quickEditorEl.innerHTML = ""; if (!items.length) { setQuickStatus("No lineItems"); return; } items.forEach((item, idx) => { const box = document.createElement("div"); box.className = "lineitem"; const head = document.createElement("div"); head.className = "lineitem-head"; const left = document.createElement("div"); const title = document.createElement("div"); title.className = "lineitem-title"; title.textContent = item.label || item.id || `Line ${idx+1}`; const idLine = document.createElement("div"); idLine.className = "lineitem-id mono"; idLine.textContent = item.id || ""; left.appendChild(title); left.appendChild(idLine); const right = document.createElement("div"); right.className = "pill"; right.innerHTML = ` Enabled`; const enabledChk = right.querySelector("input"); enabledChk.addEventListener("change", () => { item.enabled = !!enabledChk.checked; writeQuickConfig(); }); head.appendChild(left); head.appendChild(right); box.appendChild(head); // Payor const paid = normalizePaidBy(item.paidBy); const payRow = document.createElement("div"); payRow.className = "radioRow"; const makeRadio = (val, text) => { const wrap = document.createElement("label"); const r = document.createElement("input"); r.type = "radio"; r.name = `payor-${idx}`; r.value = val; r.checked = paid.type === val; wrap.appendChild(r); wrap.appendChild(document.createTextNode(text)); r.addEventListener("change", () => { if (val === "split") { // preserve existing split values if available const b = Number.isFinite(item.paidBy?.buyerPct) ? item.paidBy.buyerPct : 50; const s = Number.isFinite(item.paidBy?.sellerPct) ? item.paidBy.sellerPct : 50; item.paidBy = { type: "split", buyerPct: b, sellerPct: s }; splitWrap.classList.remove("hidden"); } else { item.paidBy = { type: val }; splitWrap.classList.add("hidden"); } writeQuickConfig(); }); return wrap; }; payRow.appendChild(makeRadio("buyer", "buyer")); payRow.appendChild(makeRadio("seller", "seller")); payRow.appendChild(makeRadio("split", "split")); box.appendChild(payRow); const splitWrap = document.createElement("div"); splitWrap.className = "miniGrid"; const buyerPct = document.createElement("div"); const sellerPct = document.createElement("div"); buyerPct.innerHTML = ``; sellerPct.innerHTML = ``; const bInp = buyerPct.querySelector("input"); const sInp = sellerPct.querySelector("input"); bInp.value = Number.isFinite(paid.buyerPct) ? String(paid.buyerPct) : "50"; sInp.value = Number.isFinite(paid.sellerPct) ? String(paid.sellerPct) : "50"; function setSplitFromInputs() { item.paidBy = { type: "split", buyerPct: Number(bInp.value || 0), sellerPct: Number(sInp.value || 0) }; // force split radio on const splitRadio = box.querySelector(`input[type="radio"][value="split"]`); if (splitRadio) splitRadio.checked = true; splitWrap.classList.remove("hidden"); writeQuickConfig(); } bInp.addEventListener("input", setSplitFromInputs); sInp.addEventListener("input", setSplitFromInputs); splitWrap.appendChild(buyerPct); splitWrap.appendChild(sellerPct); if (paid.type === "split") splitWrap.classList.remove("hidden"); else splitWrap.classList.add("hidden"); box.appendChild(splitWrap); // Amount control (when applicable) const amountInfo = resolveAmountField(item.calc || {}); if (amountInfo) { const amt = document.createElement("div"); amt.className = "field-group"; amt.innerHTML = ``; const inp = amt.querySelector("input"); inp.value = Number(item.calc?.[amountInfo.field] ?? 0); inp.addEventListener("input", () => { if (!item.calc) item.calc = {}; item.calc[amountInfo.field] = Number(inp.value || 0); writeQuickConfig(); }); box.appendChild(amt); } else { const hint = document.createElement("div"); hint.className = "hint"; hint.textContent = "Auto"; box.appendChild(hint); } quickEditorEl.appendChild(box); }); setQuickStatus(`Loaded ${items.length}`); } // -------------------- Dashboard helpers -------------------- function csvEscape(s) { const v = String(s ?? ""); if (/[",\n]/.test(v)) return `"${v.replace(/"/g, '""')}"`; return v; } function downloadCsv(filename, rows) { const csv = rows.map(r => r.map(csvEscape).join(",")).join("\n"); const blob = new Blob([csv], { type: "text/csv;charset=utf-8" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url); } function renderDashboard(licenses) { dashBody.innerHTML = ""; for (const row of licenses) { const tr = document.createElement("tr"); const td = (content) => { const c = document.createElement("td"); if (content instanceof Node) c.appendChild(content); else c.textContent = String(content ?? ""); return c; }; tr.appendChild(td(row.key || "")); tr.appendChild(td((row.status || "").toLowerCase() || "")); tr.appendChild(td(row.firmName || "")); tr.appendChild(td(row.firmPhone || "")); const mkInput = (field, value, placeholder="") => { const inp = document.createElement("input"); inp.className = "mono"; inp.setAttribute("data-field", field); inp.value = value || ""; if (placeholder) inp.placeholder = placeholder; return inp; }; tr.appendChild(td(mkInput("contactName", row.contactName || ""))); tr.appendChild(td(mkInput("contactPhone", row.contactPhone || ""))); tr.appendChild(td(mkInput("contactEmail", row.contactEmail || ""))); tr.appendChild(td(mkInput("validThrough", row.validThrough || "", "YYYY-MM-DD"))); const actionsCell = document.createElement("td"); const group = document.createElement("div"); group.className = "btn-group"; const saveBtn = document.createElement("button"); saveBtn.className = "btn btn-primary"; saveBtn.textContent = "Save"; const loadBtn = document.createElement("button"); loadBtn.className = "btn"; loadBtn.textContent = "Load"; const getVal = (field) => (tr.querySelector(`input[data-field="${field}"]`)?.value || "").trim(); saveBtn.addEventListener("click", async () => { try { const patch = { contact: { name: getVal("contactName"), phone: getVal("contactPhone"), email: getVal("contactEmail") }, validThrough: getVal("validThrough") }; const data = await adminFetch(`/admin/license`, { method: "POST", body: JSON.stringify({ key: row.key, patch }) }); showResponse(true, { saved: row.key, result: data }, "Dashboard save"); setStatusIndicator(true, "Authenticated"); } catch (e) { showResponse(false, e.message || String(e), "Dashboard save error"); setStatusIndicator(false, "Error"); } }); loadBtn.addEventListener("click", async () => { try { const data = await adminFetch(`/admin/license?k=${encodeURIComponent(row.key)}`, { method: "GET" }); fillUIFromRecord(data.key, data.record); showResponse(true, data, "Dashboard load"); setStatusIndicator(true, "Authenticated"); setActiveTab("license"); } catch (e) { showResponse(false, e.message || String(e), "Dashboard load error"); setStatusIndicator(false, "Error"); } }); group.appendChild(saveBtn); group.appendChild(loadBtn); actionsCell.appendChild(group); tr.appendChild(actionsCell); dashBody.appendChild(tr); } } async function loadDashboard(status = "active") { const s = String(status || "active").trim(); const data = await adminFetch(`/admin/licenses?status=${encodeURIComponent(s)}`, { method: "GET" }); renderDashboard(data.licenses || []); return data; } // -------------------- Events -------------------- $("saveTokenBtn").addEventListener("click", async () => { try { const t = tokenEl.value.trim(); if (!t) throw new Error("Token empty."); setToken(t); tokenEl.value = ""; setStatusIndicator(true, "Authenticated"); showResponse(true, "Token saved.", "Auth"); // Auto-refresh dashboard when token is saved try { const status = (dashStatusEl.value || "active").trim(); const d = await loadDashboard(status); showResponse(true, { ok: true, loaded: (d.licenses || []).length, status }, "Dashboard"); } catch {} } catch (e) { setStatusIndicator(false, "Not authenticated"); showResponse(false, e.message || String(e), "Auth error"); } }); $("clearTokenBtn").addEventListener("click", () => { clearToken(); setStatusIndicator(false, "Not authenticated"); showResponse(true, "Token cleared.", "Auth"); }); calcOriginEl.addEventListener("change", () => { const v = String(calcOriginEl.value || "").trim() || DEFAULT_CALC_ORIGIN; setCalcOrigin(v); calcOriginEl.value = v; updateEmbedBox(); showResponse(true, { calcOrigin: v }, "Origin updated"); }); genKeyBtn.addEventListener("click", () => { licenseKeyEl.value = generateKey(); updateEmbedBox(); }); licenseKeyEl.addEventListener("input", updateEmbedBox); addDomainBtn.addEventListener("click", () => addDomainRow("")); normalizeDomainsBtn.addEventListener("click", () => { const uniq = [...new Set(getDomainsFromUI().map(normalizeHostname).filter(Boolean))]; setDomainsUI(uniq); showResponse(true, { normalizedDomains: uniq }, "Domains normalized"); }); fetchBtn.addEventListener("click", async () => { try { const key = (licenseKeyEl.value || "").trim(); if (!key) throw new Error("Enter a license key to fetch."); const data = await adminFetch(`/admin/license?k=${encodeURIComponent(key)}`, { method: "GET" }); fillUIFromRecord(data.key, data.record); showResponse(true, data, "License fetch"); setStatusIndicator(true, "Authenticated"); } catch (e) { showResponse(false, e.message || String(e), "License fetch error"); setStatusIndicator(false, "Error"); } }); saveLicenseBtn.addEventListener("click", async () => { try { prettifyConfigJson(); const payload = getRecordFromUI(); if (!payload.record.allowedDomains.length) throw new Error("allowedDomains cannot be empty."); const data = await adminFetch(`/admin/license`, { method: "POST", body: JSON.stringify(payload) }); showResponse(true, data, "License save"); setStatusIndicator(true, "Authenticated"); } catch (e) { showResponse(false, e.message || String(e), "License save error"); setStatusIndicator(false, "Error"); } }); revokeBtn.addEventListener("click", async () => { try { const key = (licenseKeyEl.value || "").trim(); if (!key) throw new Error("Missing license key."); if (!confirm(`Revoke license ${key}? This sets status=inactive.`)) return; const data = await adminFetch(`/admin/revoke`, { method: "POST", body: JSON.stringify({ key }) }); statusEl.value = "inactive"; showResponse(true, data, "Revoke"); setStatusIndicator(true, "Authenticated"); } catch (e) { showResponse(false, e.message || String(e), "Revoke error"); setStatusIndicator(false, "Error"); } }); activateBtn.addEventListener("click", async () => { try { const key = (licenseKeyEl.value || "").trim(); if (!key) throw new Error("Missing license key."); const data = await adminFetch(`/admin/activate`, { method: "POST", body: JSON.stringify({ key }) }); statusEl.value = "active"; showResponse(true, data, "Activate"); setStatusIndicator(true, "Authenticated"); } catch (e) { showResponse(false, e.message || String(e), "Activate error"); setStatusIndicator(false, "Error"); } }); copyEmbedBtn.addEventListener("click", async () => { const text = (embedCodeEl.textContent || "").trim(); if (!text) { showResponse(false, "No embed code to copy.", "Embed"); return; } try { await navigator.clipboard.writeText(text); showResponse(true, "Embed code copied to clipboard.", "Embed"); return; } catch {} try { const ta = document.createElement("textarea"); ta.value = text; ta.setAttribute("readonly", ""); ta.style.position = "fixed"; ta.style.top = "-9999px"; ta.style.left = "-9999px"; document.body.appendChild(ta); ta.select(); ta.setSelectionRange(0, ta.value.length); const ok = document.execCommand("copy"); document.body.removeChild(ta); showResponse(ok, ok ? "Embed code copied to clipboard." : "Copy failed. Copy manually from the embed box.", "Embed"); } catch { showResponse(false, "Copy failed. Copy manually from the embed box.", "Embed"); } }); openCalcBtn.addEventListener("click", () => { const key = (licenseKeyEl.value || "").trim(); if (!key) { showResponse(false, "Generate or enter a key first.", "Open"); return; } const origin = getCalcOrigin().replace(/\/+$/,""); window.open(`${origin}/?k=${encodeURIComponent(key)}`, "_blank"); }); loadDefaultsBtn.addEventListener("click", () => { configJsonEl.value = JSON.stringify(DEFAULT_CONFIG, null, 2); showResponse(true, "Loaded defaults.", "Config"); loadLocationsFromConfig(); loadBrokerSettingsFromConfig(); renderQuickEditor(); }); prettifyJsonBtn.addEventListener("click", () => { try { prettifyConfigJson(); showResponse(true, "JSON formatted.", "Config"); } catch (e) { showResponse(false, e.message || String(e), "Config error"); } }); clearConfigBtn.addEventListener("click", () => { configJsonEl.value = ""; showResponse(true, "Config cleared.", "Config"); if (quickEditorEl) quickEditorEl.innerHTML = ""; setQuickStatus(""); setLocationsStatus(""); }); renderQuickBtn.addEventListener("click", () => renderQuickEditor()); loadLocationsBtn.addEventListener("click", () => loadLocationsFromConfig()); applyLocationsBtn.addEventListener("click", () => applyLocationsToConfig()); loadBrokerSettingsBtn.addEventListener("click", () => loadBrokerSettingsFromConfig()); applyBrokerSettingsBtn.addEventListener("click", () => applyBrokerSettingsToConfig()); loadDashboardBtn.addEventListener("click", async () => { try { const status = (dashStatusEl.value || "active").trim(); const data = await loadDashboard(status); showResponse(true, { ok: true, loaded: (data.licenses || []).length, status }, "Dashboard"); setStatusIndicator(true, "Authenticated"); } catch (e) { showResponse(false, e.message || String(e), "Dashboard error"); setStatusIndicator(false, "Error"); } }); exportCsvBtn.addEventListener("click", async () => { try { const status = (dashStatusEl.value || "active").trim(); const data = await adminFetch(`/admin/licenses?status=${encodeURIComponent(status)}`, { method: "GET" }); const licenses = data.licenses || []; const header = ["License Key","Status","Firm Name","Firm Phone","Contact Name","Contact Phone","Contact Email","Valid Through"]; const rows = [ header, ...licenses.map(r => [ r.key, r.status || "", r.firmName || "", r.firmPhone || "", r.contactName || "", r.contactPhone || "", r.contactEmail || "", r.validThrough || "" ]) ]; downloadCsv(`licenses-${status}-${new Date().toISOString().slice(0,10)}.csv`, rows); showResponse(true, `Exported ${licenses.length} rows to CSV (${status}).`, "Export"); setStatusIndicator(true, "Authenticated"); } catch (e) { showResponse(false, e.message || String(e), "Export error"); setStatusIndicator(false, "Error"); } }); // -------------------- Init -------------------- // Origin calcOriginEl.value = getCalcOrigin(); // Defaults setDomainsUI([]); statusEl.value = "active"; allowNoRefererEl.checked = false; // Default config loaded configJsonEl.value = JSON.stringify(DEFAULT_CONFIG, null, 2); loadLocationsFromConfig(); loadBrokerSettingsFromConfig(); renderQuickEditor(); // Embed initial updateEmbedBox(); // Auth status if (getToken().trim()) { setStatusIndicator(true, "Token present"); // Auto-load dashboard if token already present (async () => { try { const status = (dashStatusEl.value || "active").trim(); const data = await loadDashboard(status); showResponse(true, { ok: true, loaded: (data.licenses || []).length, status }, "Dashboard"); } catch (e) { showResponse(false, e.message || String(e), "Dashboard error"); setStatusIndicator(false, "Error"); } })(); } else { setStatusIndicator(false, "Not authenticated"); } })();