diff --git a/moldes/consolidado/96-publico-configmap.yaml b/moldes/consolidado/96-publico-configmap.yaml index 0ddd045..e07eb22 100644 --- a/moldes/consolidado/96-publico-configmap.yaml +++ b/moldes/consolidado/96-publico-configmap.yaml @@ -2415,6 +2415,20 @@ data: .termo-acoes { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-top: 10px; } .erro-termo { color: var(--perigo); font-size: 13px; } + /* ── produtos e precos ───────────────────────────────────────────────────── */ + .catalogo-tabela { width: 100%; border-collapse: collapse; font-size: 14px; } + .catalogo-tabela th, .catalogo-tabela td { padding: 8px 6px; border-bottom: 1px solid var(--line); text-align: left; } + .catalogo-tabela input[type="text"] { + width: 110px; padding: 6px 8px; border: 1px solid var(--line); border-radius: 8px; font: inherit; + } + .catalogo-pacote { border: 1px solid var(--line); border-radius: 12px; padding: 14px 16px; margin: 12px 0; } + .catalogo-pacote h3 { margin: 0 0 8px; font-size: 15px; display: flex; gap: 12px; align-items: center; flex-wrap: wrap; } + .catalogo-precos { display: flex; gap: 16px; flex-wrap: wrap; margin-bottom: 8px; font-size: 14px; } + .catalogo-precos input { width: 120px; padding: 6px 8px; border: 1px solid var(--line); border-radius: 8px; font: inherit; } + .catalogo-modulos { display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: 13px; } + .catalogo-acoes { display: flex; gap: 14px; align-items: center; margin: 4px 0 24px; } + .catalogo-acoes .erro { color: var(--perigo); } + painel.html: | @@ -2439,7 +2453,7 @@ data: `Cache-Control: immutable` por um ano. Suba o numero a cada publicacao. --> - + @@ -2499,6 +2513,7 @@ data: + @@ -2602,6 +2617,32 @@ data: + + +
@@ -2629,7 +2670,7 @@ data: - + @@ -2665,6 +2706,7 @@ data: var API = "/api/plataforma/painel/visao"; var API_ALERTAS = "/api/plataforma/painel/alertas-infra"; var API_TERMO = "/api/plataforma/painel/termo-de-dados"; + var API_CATALOGO = "/api/plataforma/painel/catalogo"; var CHAVE = "atm.painel.token"; var INTERVALO_SINO_MS = 60000; @@ -3273,6 +3315,118 @@ data: + item("Treinos (30 dias)", numeroOuTraco(d.treinos30Dias)); } + /* ── produtos e precos ──────────────────────────────────────────────────── */ + + var catalogo = null; + + function valorDoCampo(v) { return v === null || v === undefined ? "" : String(v); } + + function campoPreco(tipo, codigo, ciclo, valor, configurado) { + // Texto, e nao `number`: o campo numerico descarta "189,90" em silencio, e + // virgula e como se digita dinheiro aqui. + return ''; + } + + function pintarCatalogo() { + var modulos = catalogo.modulos || []; + $("catalogoPacotes").innerHTML = (catalogo.pacotes || []).map(function (p) { + var inclui = {}; + (p.modulos || []).forEach(function (m) { inclui[m] = true; }); + return '
' + + "

" + esc(p.nome) + + '" + + ((catalogo.naVitrine || []).indexOf(p.codigo) >= 0 ? 'na vitrine' : "") + + "

" + + '
" + + '
' + modulos.map(function (m) { + return '"; + }).join("") + "
"; + }).join(""); + $("catalogoModulos").innerHTML = '' + + "" + + modulos.map(function (m) { + return "" + + '" + + "" + + ""; + }).join("") + "
MóduloVende avulsoMensal (R$)Anual (R$)
" + esc(m.nome) + "" + campoPreco("modulo", m.codigo, "mensal", m.mensal, null) + "" + campoPreco("modulo", m.codigo, "anual", m.anual, null) + "
"; + } + + function lerPreco(tipo, codigo, ciclo) { + var el = document.querySelector('[data-cat-' + tipo + '="' + codigo + '"][data-ciclo="' + ciclo + '"]'); + var v = el ? el.value.trim().replace(/\s|R\$/g, "").replace(/\.(?=\d{3}(\D|$))/g, "").replace(",", ".") : ""; + if (v === "") return null; + var n = Number(v); + if (!isFinite(n) || n <= 0) throw new Error("Preço inválido: \"" + el.value + "\" (use, por exemplo, 189,90)."); + return Math.round(n * 100) / 100; + } + + function pedidoDoCatalogo() { + var marcado = function (codigo) { + var el = document.querySelector('[data-cat-venda="' + codigo + '"]'); + return !!(el && el.checked); + }; + return { + modulos: (catalogo.modulos || []).map(function (m) { + return { codigo: m.codigo, mensal: lerPreco("modulo", m.codigo, "mensal"), + anual: lerPreco("modulo", m.codigo, "anual"), aVenda: marcado(m.codigo) }; + }), + pacotes: (catalogo.pacotes || []).map(function (p) { + var modulos = []; + document.querySelectorAll('[data-cat-inclui="' + p.codigo + '"]').forEach(function (c) { + if (c.checked) modulos.push(c.value); + }); + return { codigo: p.codigo, mensal: lerPreco("pacote", p.codigo, "mensal"), + anual: lerPreco("pacote", p.codigo, "anual"), aVenda: marcado(p.codigo), modulos: modulos }; + }) + }; + } + + function pedirCatalogo(metodo, corpo) { + var h = { "x-atm-admin-token": tokenAtual }; + if (corpo) h["Content-Type"] = "application/json"; + return fetch(API_CATALOGO, { method: metodo, headers: h, body: corpo ? JSON.stringify(corpo) : undefined }) + .then(function (r) { + if (r.ok) return r.json(); + return r.json().catch(function () { return {}; }).then(function (d) { + throw new Error(d.erro || "HTTP " + r.status); + }); + }); + } + + function carregarCatalogo() { + if (!tokenAtual) return Promise.resolve(); + return pedirCatalogo("GET").then(function (c) { catalogo = c || {}; pintarCatalogo(); }) + .catch(function (e) { + $("catalogoPacotes").innerHTML = '

Não consegui carregar: ' + esc(e.message) + "

"; + }); + } + + $("catalogoSalvar").addEventListener("click", function () { + if (!catalogo) return; + var botao = $("catalogoSalvar"), saida = $("catalogoResultado"); + botao.disabled = true; + saida.classList.remove("erro"); + saida.textContent = "Salvando…"; + var pedido; + try { pedido = pedidoDoCatalogo(); } catch (e) { + saida.classList.add("erro"); saida.textContent = e.message; botao.disabled = false; return; + } + pedirCatalogo("PUT", pedido).then(function (c) { + catalogo = c; pintarCatalogo(); + saida.textContent = "Salvo. Na vitrine agora: " + ((c.naVitrine || []).join(", ") || "nenhum pacote") + "."; + }).catch(function (e) { + saida.classList.add("erro"); + saida.textContent = e.message; + }).then(function () { botao.disabled = false; }); + }); + /* ── termo de dados ─────────────────────────────────────────────────────── */ function pedirTermo(metodo, caminho, corpo) { @@ -3446,6 +3600,7 @@ data: p.classList.toggle("oculto", p.id !== "aba-" + b.getAttribute("data-aba")); }); if (b.getAttribute("data-aba") === "termo") carregarTermo(); + if (b.getAttribute("data-aba") === "catalogo") carregarCatalogo(); }); }); diff --git a/tenants/plataforma/96-publico-configmap.yaml b/tenants/plataforma/96-publico-configmap.yaml index c9c1be2..3d610c8 100644 --- a/tenants/plataforma/96-publico-configmap.yaml +++ b/tenants/plataforma/96-publico-configmap.yaml @@ -2415,6 +2415,20 @@ data: .termo-acoes { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-top: 10px; } .erro-termo { color: var(--perigo); font-size: 13px; } + /* ── produtos e precos ───────────────────────────────────────────────────── */ + .catalogo-tabela { width: 100%; border-collapse: collapse; font-size: 14px; } + .catalogo-tabela th, .catalogo-tabela td { padding: 8px 6px; border-bottom: 1px solid var(--line); text-align: left; } + .catalogo-tabela input[type="text"] { + width: 110px; padding: 6px 8px; border: 1px solid var(--line); border-radius: 8px; font: inherit; + } + .catalogo-pacote { border: 1px solid var(--line); border-radius: 12px; padding: 14px 16px; margin: 12px 0; } + .catalogo-pacote h3 { margin: 0 0 8px; font-size: 15px; display: flex; gap: 12px; align-items: center; flex-wrap: wrap; } + .catalogo-precos { display: flex; gap: 16px; flex-wrap: wrap; margin-bottom: 8px; font-size: 14px; } + .catalogo-precos input { width: 120px; padding: 6px 8px; border: 1px solid var(--line); border-radius: 8px; font: inherit; } + .catalogo-modulos { display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: 13px; } + .catalogo-acoes { display: flex; gap: 14px; align-items: center; margin: 4px 0 24px; } + .catalogo-acoes .erro { color: var(--perigo); } + painel.html: | @@ -2439,7 +2453,7 @@ data: `Cache-Control: immutable` por um ano. Suba o numero a cada publicacao. --> - + @@ -2499,6 +2513,7 @@ data: + @@ -2602,6 +2617,32 @@ data:
+ + +
@@ -2629,7 +2670,7 @@ data: - + @@ -2665,6 +2706,7 @@ data: var API = "/api/plataforma/painel/visao"; var API_ALERTAS = "/api/plataforma/painel/alertas-infra"; var API_TERMO = "/api/plataforma/painel/termo-de-dados"; + var API_CATALOGO = "/api/plataforma/painel/catalogo"; var CHAVE = "atm.painel.token"; var INTERVALO_SINO_MS = 60000; @@ -3273,6 +3315,118 @@ data: + item("Treinos (30 dias)", numeroOuTraco(d.treinos30Dias)); } + /* ── produtos e precos ──────────────────────────────────────────────────── */ + + var catalogo = null; + + function valorDoCampo(v) { return v === null || v === undefined ? "" : String(v); } + + function campoPreco(tipo, codigo, ciclo, valor, configurado) { + // Texto, e nao `number`: o campo numerico descarta "189,90" em silencio, e + // virgula e como se digita dinheiro aqui. + return ''; + } + + function pintarCatalogo() { + var modulos = catalogo.modulos || []; + $("catalogoPacotes").innerHTML = (catalogo.pacotes || []).map(function (p) { + var inclui = {}; + (p.modulos || []).forEach(function (m) { inclui[m] = true; }); + return '
' + + "

" + esc(p.nome) + + '" + + ((catalogo.naVitrine || []).indexOf(p.codigo) >= 0 ? 'na vitrine' : "") + + "

" + + '
" + + '
' + modulos.map(function (m) { + return '"; + }).join("") + "
"; + }).join(""); + $("catalogoModulos").innerHTML = '' + + "" + + modulos.map(function (m) { + return "" + + '" + + "" + + ""; + }).join("") + "
MóduloVende avulsoMensal (R$)Anual (R$)
" + esc(m.nome) + "" + campoPreco("modulo", m.codigo, "mensal", m.mensal, null) + "" + campoPreco("modulo", m.codigo, "anual", m.anual, null) + "
"; + } + + function lerPreco(tipo, codigo, ciclo) { + var el = document.querySelector('[data-cat-' + tipo + '="' + codigo + '"][data-ciclo="' + ciclo + '"]'); + var v = el ? el.value.trim().replace(/\s|R\$/g, "").replace(/\.(?=\d{3}(\D|$))/g, "").replace(",", ".") : ""; + if (v === "") return null; + var n = Number(v); + if (!isFinite(n) || n <= 0) throw new Error("Preço inválido: \"" + el.value + "\" (use, por exemplo, 189,90)."); + return Math.round(n * 100) / 100; + } + + function pedidoDoCatalogo() { + var marcado = function (codigo) { + var el = document.querySelector('[data-cat-venda="' + codigo + '"]'); + return !!(el && el.checked); + }; + return { + modulos: (catalogo.modulos || []).map(function (m) { + return { codigo: m.codigo, mensal: lerPreco("modulo", m.codigo, "mensal"), + anual: lerPreco("modulo", m.codigo, "anual"), aVenda: marcado(m.codigo) }; + }), + pacotes: (catalogo.pacotes || []).map(function (p) { + var modulos = []; + document.querySelectorAll('[data-cat-inclui="' + p.codigo + '"]').forEach(function (c) { + if (c.checked) modulos.push(c.value); + }); + return { codigo: p.codigo, mensal: lerPreco("pacote", p.codigo, "mensal"), + anual: lerPreco("pacote", p.codigo, "anual"), aVenda: marcado(p.codigo), modulos: modulos }; + }) + }; + } + + function pedirCatalogo(metodo, corpo) { + var h = { "x-atm-admin-token": tokenAtual }; + if (corpo) h["Content-Type"] = "application/json"; + return fetch(API_CATALOGO, { method: metodo, headers: h, body: corpo ? JSON.stringify(corpo) : undefined }) + .then(function (r) { + if (r.ok) return r.json(); + return r.json().catch(function () { return {}; }).then(function (d) { + throw new Error(d.erro || "HTTP " + r.status); + }); + }); + } + + function carregarCatalogo() { + if (!tokenAtual) return Promise.resolve(); + return pedirCatalogo("GET").then(function (c) { catalogo = c || {}; pintarCatalogo(); }) + .catch(function (e) { + $("catalogoPacotes").innerHTML = '

Não consegui carregar: ' + esc(e.message) + "

"; + }); + } + + $("catalogoSalvar").addEventListener("click", function () { + if (!catalogo) return; + var botao = $("catalogoSalvar"), saida = $("catalogoResultado"); + botao.disabled = true; + saida.classList.remove("erro"); + saida.textContent = "Salvando…"; + var pedido; + try { pedido = pedidoDoCatalogo(); } catch (e) { + saida.classList.add("erro"); saida.textContent = e.message; botao.disabled = false; return; + } + pedirCatalogo("PUT", pedido).then(function (c) { + catalogo = c; pintarCatalogo(); + saida.textContent = "Salvo. Na vitrine agora: " + ((c.naVitrine || []).join(", ") || "nenhum pacote") + "."; + }).catch(function (e) { + saida.classList.add("erro"); + saida.textContent = e.message; + }).then(function () { botao.disabled = false; }); + }); + /* ── termo de dados ─────────────────────────────────────────────────────── */ function pedirTermo(metodo, caminho, corpo) { @@ -3446,6 +3600,7 @@ data: p.classList.toggle("oculto", p.id !== "aba-" + b.getAttribute("data-aba")); }); if (b.getAttribute("data-aba") === "termo") carregarTermo(); + if (b.getAttribute("data-aba") === "catalogo") carregarCatalogo(); }); });