chore(tenants): conteudo de publico/ atualizado

This commit is contained in:
deploy
2026-09-28 15:02:25 +00:00
parent bfe60922a1
commit e79cd0c88d
2 changed files with 214 additions and 6 deletions
+107 -3
View File
@@ -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: |
<!DOCTYPE html>
<html lang="pt-BR">
@@ -1475,7 +1484,7 @@ data:
numero a cada publicacao que mexa nesses arquivos.
-->
<link rel="stylesheet" href="/publico/fontes/fontes.css">
<link rel="stylesheet" href="/publico/minha-conta.css?v=2.84">
<link rel="stylesheet" href="/publico/minha-conta.css?v=2.85">
</head>
<body>
@@ -1545,7 +1554,7 @@ data:
<footer class="direitos">&copy; 2026 Athletic Map. Todos os direitos reservados.</footer>
<script src="/publico/minha-conta.js?v=2.84"></script>
<script src="/publico/minha-conta.js?v=2.85"></script>
</body>
</html>
@@ -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", '<div class="plano-troca" data-tenant-plano="' + escapar(tenant) + '">'
+ '<button type="button" class="btn secundario" data-plano-acao="abrir">Trocar de plano</button></div>');
}
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
? '<p class="ajuda">Troca agendada: <b>' + escapar(NOME_DO_PLANO[pend.para] || pend.para) + "</b> a partir de "
+ escapar(dataCurta(pend.efetivaEm)) + '. <button type="button" class="link" data-plano-acao="cancelar">'
+ "Cancelar a troca</button></p>"
: "";
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 '<li class="atual"><b>' + nome + "</b> " + valor + ' <span class="selo ok">seu plano</span></li>';
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 "<li><b>" + nome + "</b> " + valor + ' <span class="ajuda">(' + quando + ")</span> "
+ '<button type="button" class="btn secundario" data-plano-acao="pedir" data-plano="' + escapar(p.plano)
+ '" data-quando="' + escapar(quando) + '">Mudar para ' + nome + "</button></li>";
}).join("");
return aviso + '<ul class="lista-planos">' + opcoes + '</ul><p class="erro-form oculto"></p>';
}
function mostrarPlano(tenant, d) {
var caixa = produtos.querySelector('[data-tenant-plano="' + tenant + '"]');
if (!caixa) return;
caixa.innerHTML = '<span class="cobranca-titulo">Plano</span>' + 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