From e79cd0c88dca7f7df9dbc568270ea010ecfe0da7 Mon Sep 17 00:00:00 2001 From: deploy Date: Mon, 28 Sep 2026 15:02:25 +0000 Subject: [PATCH] chore(tenants): conteudo de publico/ atualizado --- moldes/consolidado/96-publico-configmap.yaml | 110 ++++++++++++++++++- tenants/plataforma/96-publico-configmap.yaml | 110 ++++++++++++++++++- 2 files changed, 214 insertions(+), 6 deletions(-) diff --git a/moldes/consolidado/96-publico-configmap.yaml b/moldes/consolidado/96-publico-configmap.yaml index e07eb22..ee2a444 100644 --- a/moldes/consolidado/96-publico-configmap.yaml +++ b/moldes/consolidado/96-publico-configmap.yaml @@ -1451,6 +1451,15 @@ data: .lista-faturas .selo { margin: 0; } .lista-faturas a { color: var(--orange-600, #c2410c); font-weight: 600; } + /* ── a troca de plano, dentro do cartao ───────────────────────────────────── */ + .plano-troca { align-self: stretch; margin-top: 16px; padding-top: 14px; border-top: 1px dashed var(--line); + display: flex; flex-direction: column; gap: 8px; align-items: flex-start; font-size: 14px; } + .lista-planos { list-style: none; margin: 4px 0 0; padding: 0; align-self: stretch; } + .lista-planos li { padding: 8px 0; border-top: 1px solid var(--line); display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: center; } + .lista-planos li.atual { background: transparent; } + .lista-planos .selo { margin: 0; } + .plano-troca .link { background: none; border: 0; color: var(--orange-600); font-weight: 600; cursor: pointer; padding: 0; font: inherit; } + minha-conta.html: | @@ -1475,7 +1484,7 @@ data: numero a cada publicacao que mexa nesses arquivos. --> - + @@ -1545,7 +1554,7 @@ data: - + @@ -1585,7 +1594,8 @@ data: API: "/api/cliente/meus-produtos", COBRANCA: "/api/cliente/cobranca", TERMO: "/api/cliente/termo-de-dados", - FATURAS: "/api/cliente/faturas" + FATURAS: "/api/cliente/faturas", + PLANO: "/api/cliente/plano" }; var CHAVE_VERIFIER = "atm.conta.verifier"; @@ -1757,6 +1767,7 @@ data: produtos.innerHTML = (lista || []).map(cartao).join(""); nenhum.classList.toggle("oculto", (lista || []).length > 0); mostrar(conteudo); + (lista || []).forEach(function (p) { if (p.tenant && p.situacao === "ATIVA") acrescentarBotaoDePlano(p.tenant); }); return Promise.all([carregarCobranca(), carregarTermo(), carregarFaturas()]); }); } @@ -1907,6 +1918,99 @@ data: }); } + /* ── A TROCA DE PLANO ─────────────────────────────────────────────────────── + * + * Regras do dono: upgrade vale na hora e o valor novo so na proxima cobranca; + * downgrade vale no proximo vencimento (o cliente fica com o plano que pagou + * ate la). A tela diz isso ANTES de confirmar, com a data. */ + + var NOME_DO_PLANO = { bronze: "Bronze", prata: "Prata", ouro: "Ouro", institucional: "Institucional" }; + + function acrescentarBotaoDePlano(tenant) { + var alvo = cartaoDo(tenant); + if (!alvo || alvo.querySelector(".plano-troca")) return; + alvo.insertAdjacentHTML("beforeend", '
' + + '
'); + } + + function cartaoDo(tenant) { + var alvo = null; + produtos.querySelectorAll("article[data-tenant]").forEach(function (el) { + if (el.getAttribute("data-tenant") === tenant) alvo = el; + }); + return alvo; + } + + function pedirPlano(metodo, tenant, corpo) { + var h = { Authorization: "Bearer " + token }; + if (corpo) h["Content-Type"] = "application/json"; + return fetch(CONFIG.PLANO + "/" + encodeURIComponent(tenant), { + 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 || "Não consegui agora. Tente de novo em instantes."); + }); + }); + } + + function blocoDePlano(d) { + var pend = d.pendente; + var aviso = pend + ? '

Troca agendada: ' + escapar(NOME_DO_PLANO[pend.para] || pend.para) + " a partir de " + + escapar(dataCurta(pend.efetivaEm)) + '.

" + : ""; + var opcoes = (d.planos || []).map(function (p) { + var nome = escapar(NOME_DO_PLANO[p.plano] || p.plano); + var valor = escapar(reais(p.valor)) + (d.ciclo === "ANUAL" ? "/ano" : "/mês"); + if (p.atual) return '
  • ' + nome + " " + valor + ' seu plano
  • '; + var quando = p.tipo === "UPGRADE" + ? "vale na hora; o valor novo entra na próxima cobrança" + : "vale a partir de " + escapar(dataCurta(d.proximoVencimento)) + ", no fim do período já pago"; + return "
  • " + nome + " " + valor + ' (' + quando + ") " + + '
  • "; + }).join(""); + return aviso + '

    '; + } + + function mostrarPlano(tenant, d) { + var caixa = produtos.querySelector('[data-tenant-plano="' + tenant + '"]'); + if (!caixa) return; + caixa.innerHTML = 'Plano' + blocoDePlano(d); + } + + function agirNoPlano(botao) { + var caixa = botao.closest("[data-tenant-plano]"); + var tenant = caixa.getAttribute("data-tenant-plano"); + var acao = botao.getAttribute("data-plano-acao"); + var erro = function (e) { + var p = caixa.querySelector(".erro-form"); + if (p) { p.textContent = e.message; p.classList.remove("oculto"); } + botao.disabled = false; + }; + botao.disabled = true; + if (acao === "abrir") { + return pedirPlano("GET", tenant).then(function (d) { mostrarPlano(tenant, d); }).catch(erro); + } + if (acao === "pedir") { + var plano = botao.getAttribute("data-plano"); + if (typeof window.confirm === "function" && !window.confirm("Mudar para " + (NOME_DO_PLANO[plano] || plano) + + "? " + botao.getAttribute("data-quando") + ".")) { botao.disabled = false; return Promise.resolve(); } + return pedirPlano("POST", tenant, { plano: plano }).then(function (d) { mostrarPlano(tenant, d); }).catch(erro); + } + if (acao === "cancelar") { + return pedirPlano("DELETE", tenant).then(function (d) { mostrarPlano(tenant, d); }).catch(erro); + } + return Promise.resolve(); + } + + if (produtos) produtos.addEventListener("click", function (ev) { + var b = ev.target && ev.target.closest ? ev.target.closest("[data-plano-acao]") : null; + if (b) agirNoPlano(b); + }); + /* ── AS FATURAS DA ASSINATURA ──────────────────────────────────────────────── * * As cobranças da Athletic Map para o cliente (não as dos alunos), com o link diff --git a/tenants/plataforma/96-publico-configmap.yaml b/tenants/plataforma/96-publico-configmap.yaml index 3d610c8..3694455 100644 --- a/tenants/plataforma/96-publico-configmap.yaml +++ b/tenants/plataforma/96-publico-configmap.yaml @@ -1451,6 +1451,15 @@ data: .lista-faturas .selo { margin: 0; } .lista-faturas a { color: var(--orange-600, #c2410c); font-weight: 600; } + /* ── a troca de plano, dentro do cartao ───────────────────────────────────── */ + .plano-troca { align-self: stretch; margin-top: 16px; padding-top: 14px; border-top: 1px dashed var(--line); + display: flex; flex-direction: column; gap: 8px; align-items: flex-start; font-size: 14px; } + .lista-planos { list-style: none; margin: 4px 0 0; padding: 0; align-self: stretch; } + .lista-planos li { padding: 8px 0; border-top: 1px solid var(--line); display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: center; } + .lista-planos li.atual { background: transparent; } + .lista-planos .selo { margin: 0; } + .plano-troca .link { background: none; border: 0; color: var(--orange-600); font-weight: 600; cursor: pointer; padding: 0; font: inherit; } + minha-conta.html: | @@ -1475,7 +1484,7 @@ data: numero a cada publicacao que mexa nesses arquivos. --> - + @@ -1545,7 +1554,7 @@ data: - + @@ -1585,7 +1594,8 @@ data: API: "/api/cliente/meus-produtos", COBRANCA: "/api/cliente/cobranca", TERMO: "/api/cliente/termo-de-dados", - FATURAS: "/api/cliente/faturas" + FATURAS: "/api/cliente/faturas", + PLANO: "/api/cliente/plano" }; var CHAVE_VERIFIER = "atm.conta.verifier"; @@ -1757,6 +1767,7 @@ data: produtos.innerHTML = (lista || []).map(cartao).join(""); nenhum.classList.toggle("oculto", (lista || []).length > 0); mostrar(conteudo); + (lista || []).forEach(function (p) { if (p.tenant && p.situacao === "ATIVA") acrescentarBotaoDePlano(p.tenant); }); return Promise.all([carregarCobranca(), carregarTermo(), carregarFaturas()]); }); } @@ -1907,6 +1918,99 @@ data: }); } + /* ── A TROCA DE PLANO ─────────────────────────────────────────────────────── + * + * Regras do dono: upgrade vale na hora e o valor novo so na proxima cobranca; + * downgrade vale no proximo vencimento (o cliente fica com o plano que pagou + * ate la). A tela diz isso ANTES de confirmar, com a data. */ + + var NOME_DO_PLANO = { bronze: "Bronze", prata: "Prata", ouro: "Ouro", institucional: "Institucional" }; + + function acrescentarBotaoDePlano(tenant) { + var alvo = cartaoDo(tenant); + if (!alvo || alvo.querySelector(".plano-troca")) return; + alvo.insertAdjacentHTML("beforeend", '
    ' + + '
    '); + } + + function cartaoDo(tenant) { + var alvo = null; + produtos.querySelectorAll("article[data-tenant]").forEach(function (el) { + if (el.getAttribute("data-tenant") === tenant) alvo = el; + }); + return alvo; + } + + function pedirPlano(metodo, tenant, corpo) { + var h = { Authorization: "Bearer " + token }; + if (corpo) h["Content-Type"] = "application/json"; + return fetch(CONFIG.PLANO + "/" + encodeURIComponent(tenant), { + 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 || "Não consegui agora. Tente de novo em instantes."); + }); + }); + } + + function blocoDePlano(d) { + var pend = d.pendente; + var aviso = pend + ? '

    Troca agendada: ' + escapar(NOME_DO_PLANO[pend.para] || pend.para) + " a partir de " + + escapar(dataCurta(pend.efetivaEm)) + '.

    " + : ""; + var opcoes = (d.planos || []).map(function (p) { + var nome = escapar(NOME_DO_PLANO[p.plano] || p.plano); + var valor = escapar(reais(p.valor)) + (d.ciclo === "ANUAL" ? "/ano" : "/mês"); + if (p.atual) return '
  • ' + nome + " " + valor + ' seu plano
  • '; + var quando = p.tipo === "UPGRADE" + ? "vale na hora; o valor novo entra na próxima cobrança" + : "vale a partir de " + escapar(dataCurta(d.proximoVencimento)) + ", no fim do período já pago"; + return "
  • " + nome + " " + valor + ' (' + quando + ") " + + '
  • "; + }).join(""); + return aviso + '

    '; + } + + function mostrarPlano(tenant, d) { + var caixa = produtos.querySelector('[data-tenant-plano="' + tenant + '"]'); + if (!caixa) return; + caixa.innerHTML = 'Plano' + blocoDePlano(d); + } + + function agirNoPlano(botao) { + var caixa = botao.closest("[data-tenant-plano]"); + var tenant = caixa.getAttribute("data-tenant-plano"); + var acao = botao.getAttribute("data-plano-acao"); + var erro = function (e) { + var p = caixa.querySelector(".erro-form"); + if (p) { p.textContent = e.message; p.classList.remove("oculto"); } + botao.disabled = false; + }; + botao.disabled = true; + if (acao === "abrir") { + return pedirPlano("GET", tenant).then(function (d) { mostrarPlano(tenant, d); }).catch(erro); + } + if (acao === "pedir") { + var plano = botao.getAttribute("data-plano"); + if (typeof window.confirm === "function" && !window.confirm("Mudar para " + (NOME_DO_PLANO[plano] || plano) + + "? " + botao.getAttribute("data-quando") + ".")) { botao.disabled = false; return Promise.resolve(); } + return pedirPlano("POST", tenant, { plano: plano }).then(function (d) { mostrarPlano(tenant, d); }).catch(erro); + } + if (acao === "cancelar") { + return pedirPlano("DELETE", tenant).then(function (d) { mostrarPlano(tenant, d); }).catch(erro); + } + return Promise.resolve(); + } + + if (produtos) produtos.addEventListener("click", function (ev) { + var b = ev.target && ev.target.closest ? ev.target.closest("[data-plano-acao]") : null; + if (b) agirNoPlano(b); + }); + /* ── AS FATURAS DA ASSINATURA ──────────────────────────────────────────────── * * As cobranças da Athletic Map para o cliente (não as dos alunos), com o link