|
|
|
@@ -16,12 +16,22 @@ function statusAction(e){const acao=e.status==='ativa'?'Bloquear':'Ativar';retur
|
|
|
|
|
function detalheRow(e){if(selecionado!==e.id||!modo)return'';if(modo==='ver')return `<tr><td colspan="5"><div class="inline-panel"><h2>${esc(e.nome)}</h2><p><strong>Slug:</strong> ${esc(e.slug)}</p><p><strong>CNPJ:</strong> ${esc(e.cnpj||'-')}</p><p><strong>Status:</strong> ${esc(e.status)}</p><p><strong>Plano:</strong> ${e.plano?`${esc(e.plano)} ${e.plano_valor_centavos?'- '+Util.money(e.plano_valor_centavos):''}`:'-'}</p><div class="field"><label>API Key de integração</label><input readonly value="${esc(e.api_key||'')}" onclick="this.select()"></div><div class="row compact"><button class="btn secondary" type="button" onclick="copiarApiKey(${e.id})">Copiar API Key</button><button class="btn secondary" type="button" onclick="solicitarAlteracaoApiKey(${e.id})">Solicitar alteração</button></div><p><strong>Conta principal:</strong> abra Editar para alterar dados da empresa; funcionarios ficam no acesso da empresa.</p><button class="btn secondary" onclick="fecharDetalhe()">Fechar</button></div></td></tr>`;return `<tr><td colspan="5"><form class="inline-panel grid cols" onsubmit="salvarEdicao(event,${e.id})"><div class="field"><label>Nome</label><input name="nome" value="${esc(e.nome||'')}" required></div><div class="field"><label>CNPJ</label><input name="cnpj" value="${esc(e.cnpj||'')}"></div><div class="field"><label>Plano</label><select name="plano_id">${planoOptions(e.plano_id)}</select></div><div class="row"><button class="btn">Salvar</button><button type="button" class="btn secondary" onclick="fecharDetalhe()">Cancelar</button></div></form></td></tr>`}
|
|
|
|
|
|
|
|
|
|
function proximoSlugSequencial(){
|
|
|
|
|
let max=0;
|
|
|
|
|
for(const e of empresas){
|
|
|
|
|
const n=parseInt(e.slug,10);
|
|
|
|
|
if(!isNaN(n)&&n>max)max=n;
|
|
|
|
|
const slugsExistentes = new Set(empresas.map(e => String(e.slug || '').trim().toLowerCase()));
|
|
|
|
|
let max = 0;
|
|
|
|
|
for (const e of empresas) {
|
|
|
|
|
const s = String(e.slug || '').trim();
|
|
|
|
|
const n = parseInt(s, 10);
|
|
|
|
|
if (!isNaN(n) && /^\d+$/.test(s)) {
|
|
|
|
|
if (n > max) max = n;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return String(max+1).padStart(4,'0');
|
|
|
|
|
let proximo = max + 1;
|
|
|
|
|
let candidato = String(proximo).padStart(4, '0');
|
|
|
|
|
while (slugsExistentes.has(candidato.toLowerCase())) {
|
|
|
|
|
proximo++;
|
|
|
|
|
candidato = String(proximo).padStart(4, '0');
|
|
|
|
|
}
|
|
|
|
|
return candidato;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function slugify(text){
|
|
|
|
@@ -34,6 +44,25 @@ function slugify(text){
|
|
|
|
|
.replace(/^_+|_+$/g,'');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function mostrarErroModal(msg){
|
|
|
|
|
const el = document.querySelector('#modal-error-msg');
|
|
|
|
|
if(el){
|
|
|
|
|
el.textContent = msg;
|
|
|
|
|
el.classList.remove('hidden');
|
|
|
|
|
el.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function limparErroModal(){
|
|
|
|
|
const el = document.querySelector('#modal-error-msg');
|
|
|
|
|
if(el){
|
|
|
|
|
el.textContent = '';
|
|
|
|
|
el.classList.add('hidden');
|
|
|
|
|
}
|
|
|
|
|
const slugInput = empresaForm.querySelector('input[name="slug"]');
|
|
|
|
|
if(slugInput) slugInput.style.borderColor = '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function render(){
|
|
|
|
|
const q=busca.value.trim();
|
|
|
|
|
const lista=empresas.filter(e=>match(e,q));
|
|
|
|
@@ -67,6 +96,7 @@ window.alternarTipoSlug=()=>{
|
|
|
|
|
const slugInput=empresaForm.querySelector('input[name="slug"]');
|
|
|
|
|
const nomeInput=empresaForm.querySelector('input[name="nome"]');
|
|
|
|
|
const btn=document.querySelector('#btn-slug-tipo');
|
|
|
|
|
limparErroModal();
|
|
|
|
|
if(modoSlugAuto==='sequencial'){
|
|
|
|
|
modoSlugAuto='nome';
|
|
|
|
|
if(btn)btn.textContent='Usar sequencial';
|
|
|
|
@@ -79,6 +109,7 @@ window.alternarTipoSlug=()=>{
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
window.abrirModalCadastro=()=>{
|
|
|
|
|
limparErroModal();
|
|
|
|
|
cadastroModal?.classList.remove('hidden');
|
|
|
|
|
const slugInput=empresaForm.querySelector('input[name="slug"]');
|
|
|
|
|
const btn=document.querySelector('#btn-slug-tipo');
|
|
|
|
@@ -86,11 +117,13 @@ window.abrirModalCadastro=()=>{
|
|
|
|
|
if(btn)btn.textContent='Gerar do nome';
|
|
|
|
|
if(slugInput){
|
|
|
|
|
slugInput.value=proximoSlugSequencial();
|
|
|
|
|
slugInput.style.borderColor='';
|
|
|
|
|
}
|
|
|
|
|
empresaForm.querySelector('input[name="nome"]')?.focus();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
window.fecharModalCadastro=()=>{
|
|
|
|
|
limparErroModal();
|
|
|
|
|
cadastroModal?.classList.add('hidden');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@@ -112,20 +145,49 @@ nomeInput?.addEventListener('input',()=>{
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
empresaForm.querySelector('input[name="slug"]')?.addEventListener('input',()=>{
|
|
|
|
|
limparErroModal();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
empresaForm.onsubmit=async e=>{
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
limparErroModal();
|
|
|
|
|
const slugInput=empresaForm.querySelector('input[name="slug"]');
|
|
|
|
|
if(slugInput&&!slugInput.value.trim()){
|
|
|
|
|
if(!slugInput) return;
|
|
|
|
|
|
|
|
|
|
if(!slugInput.value.trim()){
|
|
|
|
|
slugInput.value=proximoSlugSequencial();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const slugValor = slugInput.value.trim().toLowerCase();
|
|
|
|
|
const duplicado = empresas.find(emp => String(emp.slug || '').trim().toLowerCase() === slugValor);
|
|
|
|
|
if(duplicado){
|
|
|
|
|
const msg = `O Slug "${slugInput.value}" já está cadastrado no cliente "${duplicado.nome}". Por favor, utilize o próximo código sugerido (${proximoSlugSequencial()}).`;
|
|
|
|
|
mostrarErroModal(msg);
|
|
|
|
|
slugInput.style.borderColor = 'var(--danger)';
|
|
|
|
|
slugInput.focus();
|
|
|
|
|
Util.toast(msg, true);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try{
|
|
|
|
|
await Api.post('/api/master/empresas',Util.formData(empresaForm));
|
|
|
|
|
empresaForm.reset();
|
|
|
|
|
fecharModalCadastro();
|
|
|
|
|
Util.toast('Cliente cadastrado');
|
|
|
|
|
load();
|
|
|
|
|
Util.toast('Cliente cadastrado com sucesso!');
|
|
|
|
|
await load();
|
|
|
|
|
}catch(err){
|
|
|
|
|
Util.toast(err.message,true);
|
|
|
|
|
let msg = err.message || 'Erro ao cadastrar cliente';
|
|
|
|
|
if(msg.includes('slug_duplicado')){
|
|
|
|
|
msg = `O Slug "${slugInput.value}" já está em uso por outro cliente. Altere para outro código ou clique em "Usar sequencial".`;
|
|
|
|
|
slugInput.style.borderColor = 'var(--danger)';
|
|
|
|
|
slugInput.focus();
|
|
|
|
|
}else if(msg.includes('email_duplicado')){
|
|
|
|
|
msg = 'Este e-mail de login já está cadastrado no sistema.';
|
|
|
|
|
empresaForm.querySelector('input[name="email"]')?.focus();
|
|
|
|
|
}
|
|
|
|
|
mostrarErroModal(msg);
|
|
|
|
|
Util.toast(msg, true);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|