feat(master): transformar configuracao de email em card com modal e icones de acao
This commit is contained in:
@@ -1768,3 +1768,110 @@ th {
|
|||||||
border: 1px solid #e5e7eb;
|
border: 1px solid #e5e7eb;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Card de Configuração de E-mail */
|
||||||
|
.email-card {
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid var(--line, #e2e8f0);
|
||||||
|
border-radius: var(--radius-lg, 16px);
|
||||||
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -2px rgba(0, 0, 0, 0.05);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
|
||||||
|
overflow: hidden;
|
||||||
|
max-width: 720px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.email-card:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.08), 0 4px 6px -4px rgba(0, 0, 0, 0.05);
|
||||||
|
border-color: var(--brand-light, #cbd5e1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.email-card-header {
|
||||||
|
padding: 18px 20px;
|
||||||
|
border-bottom: 1px solid var(--line, #e2e8f0);
|
||||||
|
background: #fbfcfd;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.email-card-title-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.email-icon-bubble {
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: var(--brand-soft, #dff4f1);
|
||||||
|
color: var(--brand, #0f766e);
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.email-icon-bubble svg {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
stroke: currentColor;
|
||||||
|
stroke-width: 2;
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.email-card-user {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: var(--text, #1e293b);
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.email-card-remetente {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--muted-strong, #64748b);
|
||||||
|
margin-top: 3px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.email-card-badges {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.email-card-body {
|
||||||
|
padding: 18px 20px;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.email-card-footer {
|
||||||
|
padding: 14px 20px;
|
||||||
|
border-top: 1px solid var(--line, #e2e8f0);
|
||||||
|
background: #fbfcfd;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.email-card-footer .table-actions {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.email-empty-card {
|
||||||
|
padding: 36px 20px;
|
||||||
|
text-align: center;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px dashed var(--line, #e2e8f0);
|
||||||
|
border-radius: var(--radius-lg, 16px);
|
||||||
|
color: var(--muted-strong, #64748b);
|
||||||
|
max-width: 720px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,120 +16,16 @@
|
|||||||
<h1>Configurações</h1>
|
<h1>Configurações</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section class="email-config-panel">
|
<section class="panel">
|
||||||
<div class="email-config-header">
|
<div class="section-head">
|
||||||
<h2 class="email-config-title">Configurar Conta</h2>
|
<h2>Configuração de E-mail</h2>
|
||||||
<p class="email-config-subtitle">Preencha as configurações de IMAP e SMTP abaixo para conectar sua conta.</p>
|
<div class="section-actions">
|
||||||
|
<button class="header-add-btn" type="button" onclick="abrirModalEmail()" title="Configurar e-mail" aria-label="Configurar e-mail">
|
||||||
|
<svg viewBox="0 0 24 24" aria-hidden="true"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="email-card-container"></div>
|
||||||
<form id="email-form">
|
|
||||||
<div class="email-config-columns">
|
|
||||||
<!-- Coluna 1: Email Recebido (IMAP) -->
|
|
||||||
<div class="email-column">
|
|
||||||
<h3 class="email-section-heading">Email Recebido (IMAP):</h3>
|
|
||||||
|
|
||||||
<div class="email-field">
|
|
||||||
<label>Server:</label>
|
|
||||||
<input name="imap_host" placeholder="imap.seconectai.com.br">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="email-field">
|
|
||||||
<label>Porta:</label>
|
|
||||||
<select name="imap_port" id="imap-port-select">
|
|
||||||
<option value="993">993</option>
|
|
||||||
<option value="143">143</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="email-field">
|
|
||||||
<label>Segurança:</label>
|
|
||||||
<div class="email-security-wrap">
|
|
||||||
<select name="imap_security" id="imap-sec-select">
|
|
||||||
<option value="ssl_tls">SSL / TLS</option>
|
|
||||||
<option value="starttls">STARTTLS</option>
|
|
||||||
<option value="none">Nenhum</option>
|
|
||||||
</select>
|
|
||||||
<label class="email-checkbox-label">
|
|
||||||
<input type="checkbox" name="imap_allow_insecure_ssl" value="true">
|
|
||||||
Permitir SSL inseguro
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="email-field">
|
|
||||||
<label>Username:</label>
|
|
||||||
<input name="imap_user" placeholder="no_reply@seconectai.com.br">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="email-field">
|
|
||||||
<label>Senha:</label>
|
|
||||||
<input name="imap_password" type="password" placeholder="••••••••••••">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Coluna 2: Email de saída (SMTP) -->
|
|
||||||
<div class="email-column">
|
|
||||||
<h3 class="email-section-heading">Email de saída (SMTP):</h3>
|
|
||||||
|
|
||||||
<div class="email-field">
|
|
||||||
<label>Server:</label>
|
|
||||||
<input name="smtp_host" placeholder="smtp.seconectai.com.br">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="email-field">
|
|
||||||
<label>Porta:</label>
|
|
||||||
<select name="smtp_port" id="smtp-port-select">
|
|
||||||
<option value="465">465</option>
|
|
||||||
<option value="587">587</option>
|
|
||||||
<option value="25">25</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="email-field">
|
|
||||||
<label>Segurança:</label>
|
|
||||||
<div class="email-security-wrap">
|
|
||||||
<select name="smtp_security" id="smtp-sec-select">
|
|
||||||
<option value="ssl_tls">SSL / TLS</option>
|
|
||||||
<option value="starttls">STARTTLS</option>
|
|
||||||
<option value="none">Nenhum</option>
|
|
||||||
</select>
|
|
||||||
<label class="email-checkbox-label">
|
|
||||||
<input type="checkbox" name="smtp_allow_insecure_ssl" value="true">
|
|
||||||
Permitir SSL inseguro
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="email-field">
|
|
||||||
<label>Username:</label>
|
|
||||||
<input name="smtp_user" placeholder="no_reply@seconectai.com.br">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="email-field">
|
|
||||||
<label>Senha:</label>
|
|
||||||
<input name="smtp_password" type="password" placeholder="••••••••••••">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Remetente opcional -->
|
|
||||||
<div class="email-from-wrap">
|
|
||||||
<div class="email-field">
|
|
||||||
<label>Remetente de envio (From opcional):</label>
|
|
||||||
<input name="smtp_from" placeholder="Ex: no_reply@seconectai.com.br ou Notificações <no_reply@seconectai.com.br>">
|
|
||||||
<small style="color: var(--muted); font-size: 12px; margin-top: 4px;">Se deixado em branco, o Username SMTP será utilizado como remetente.</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="email-actions-footer">
|
|
||||||
<button class="btn" type="submit" id="btn-salvar-email">Salvar configurações</button>
|
|
||||||
<button class="btn secondary" type="button" onclick="testarEConectarEmail()" id="btn-testar-email">Testar e Conectar</button>
|
|
||||||
<button class="btn secondary" type="button" onclick="sincronizarEmailsAgora()" id="btn-sync-email">Sincronizar Respostas Agora</button>
|
|
||||||
<span id="email-header-status-badges" style="margin-left: auto; display: flex; gap: 8px;"></span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="email-status-feedback" class="email-status-feedback-box hidden"></div>
|
|
||||||
</form>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="panel">
|
<section class="panel">
|
||||||
@@ -167,6 +63,115 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Modal Configuração de E-mail -->
|
||||||
|
<div id="email-modal" class="modal hidden">
|
||||||
|
<div class="modal-backdrop" onclick="fecharModalEmail()"></div>
|
||||||
|
<section class="modal-panel" style="max-width: 860px;">
|
||||||
|
<div class="modal-head">
|
||||||
|
<h2>Configuração de E-mail</h2>
|
||||||
|
<button class="btn secondary" type="button" onclick="fecharModalEmail()">✕</button>
|
||||||
|
</div>
|
||||||
|
<form id="email-form" onsubmit="salvarConfiguracaoEmail(event)">
|
||||||
|
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: 24px; margin-top: 10px;">
|
||||||
|
<!-- Coluna IMAP -->
|
||||||
|
<div style="background: #f8fafc; border: 1px solid var(--line); border-radius: 12px; padding: 18px;">
|
||||||
|
<h3 style="margin-top: 0; margin-bottom: 14px; font-size: 16px; color: var(--brand); display: flex; align-items: center; gap: 8px;">
|
||||||
|
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"><polyline points="22 12 16 12 14 15 10 15 8 12 2 12"></polyline><path d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"></path></svg>
|
||||||
|
Email Recebido (IMAP)
|
||||||
|
</h3>
|
||||||
|
<div class="field" style="margin-bottom: 12px;">
|
||||||
|
<label>Servidor IMAP</label>
|
||||||
|
<input name="imap_host" placeholder="ex: imap.hostinger.com ou imap.gmail.com">
|
||||||
|
</div>
|
||||||
|
<div class="grid cols" style="margin-bottom: 12px;">
|
||||||
|
<div class="field">
|
||||||
|
<label>Porta</label>
|
||||||
|
<select name="imap_port" id="imap-port-select">
|
||||||
|
<option value="993">993 (SSL/TLS)</option>
|
||||||
|
<option value="143">143 (STARTTLS)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>Segurança</label>
|
||||||
|
<select name="imap_security" id="imap-sec-select">
|
||||||
|
<option value="ssl_tls">SSL/TLS</option>
|
||||||
|
<option value="starttls">STARTTLS</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field" style="margin-bottom: 12px;">
|
||||||
|
<label style="display: flex; align-items: center; gap: 8px; font-weight: normal; cursor: pointer;">
|
||||||
|
<input type="checkbox" name="imap_allow_insecure_ssl" value="true">
|
||||||
|
<span>Permitir certificados SSL inseguros</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="field" style="margin-bottom: 12px;">
|
||||||
|
<label>Usuário / E-mail</label>
|
||||||
|
<input name="imap_user" type="email" placeholder="ex: suporte@seudominio.com.br">
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>Senha IMAP</label>
|
||||||
|
<input name="imap_password" type="password" placeholder="•••••••• (deixe em branco para manter)">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Coluna SMTP -->
|
||||||
|
<div style="background: #f8fafc; border: 1px solid var(--line); border-radius: 12px; padding: 18px;">
|
||||||
|
<h3 style="margin-top: 0; margin-bottom: 14px; font-size: 16px; color: var(--brand); display: flex; align-items: center; gap: 8px;">
|
||||||
|
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"><line x1="22" y1="2" x2="11" y2="13"></line><polygon points="22 2 15 22 11 13 2 9 22 2"></polygon></svg>
|
||||||
|
Email de Saída (SMTP)
|
||||||
|
</h3>
|
||||||
|
<div class="field" style="margin-bottom: 12px;">
|
||||||
|
<label>Servidor SMTP</label>
|
||||||
|
<input name="smtp_host" placeholder="ex: smtp.hostinger.com ou smtp.gmail.com">
|
||||||
|
</div>
|
||||||
|
<div class="grid cols" style="margin-bottom: 12px;">
|
||||||
|
<div class="field">
|
||||||
|
<label>Porta</label>
|
||||||
|
<select name="smtp_port" id="smtp-port-select">
|
||||||
|
<option value="465">465 (SSL/TLS)</option>
|
||||||
|
<option value="587">587 (STARTTLS)</option>
|
||||||
|
<option value="25">25 (Nenhuma)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>Segurança</label>
|
||||||
|
<select name="smtp_security" id="smtp-sec-select">
|
||||||
|
<option value="ssl_tls">SSL/TLS</option>
|
||||||
|
<option value="starttls">STARTTLS</option>
|
||||||
|
<option value="none">Nenhuma</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field" style="margin-bottom: 12px;">
|
||||||
|
<label style="display: flex; align-items: center; gap: 8px; font-weight: normal; cursor: pointer;">
|
||||||
|
<input type="checkbox" name="smtp_allow_insecure_ssl" value="true">
|
||||||
|
<span>Permitir certificados SSL inseguros</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="field" style="margin-bottom: 12px;">
|
||||||
|
<label>Usuário / E-mail</label>
|
||||||
|
<input name="smtp_user" type="email" placeholder="ex: suporte@seudominio.com.br">
|
||||||
|
</div>
|
||||||
|
<div class="field" style="margin-bottom: 12px;">
|
||||||
|
<label>Senha SMTP</label>
|
||||||
|
<input name="smtp_password" type="password" placeholder="•••••••• (deixe em branco para manter)">
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>Remetente (Opcional)</label>
|
||||||
|
<input name="smtp_from" placeholder="ex: SeConectaí Notificações <suporte@seudominio.com.br>">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-actions" style="margin-top: 20px;">
|
||||||
|
<button class="btn secondary" type="button" onclick="fecharModalEmail()">Cancelar</button>
|
||||||
|
<button class="btn" type="submit" id="btn-modal-salvar-email">Salvar Configurações</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Modal Reativar para Cliente -->
|
<!-- Modal Reativar para Cliente -->
|
||||||
<div id="reativar-modal" class="modal hidden">
|
<div id="reativar-modal" class="modal hidden">
|
||||||
<div class="modal-backdrop" onclick="fecharModalReativar()"></div>
|
<div class="modal-backdrop" onclick="fecharModalReativar()"></div>
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
const emailForm = document.querySelector('#email-form'),
|
const emailForm = document.querySelector('#email-form'),
|
||||||
|
emailCardContainer = document.querySelector('#email-card-container'),
|
||||||
|
emailModal = document.querySelector('#email-modal'),
|
||||||
abacateForm = document.querySelector('#abacate-form'),
|
abacateForm = document.querySelector('#abacate-form'),
|
||||||
emailRows = document.querySelector('#email-rows'),
|
emailRows = document.querySelector('#email-rows'),
|
||||||
abacateRows = document.querySelector('#abacate-rows'),
|
abacateRows = document.querySelector('#abacate-rows'),
|
||||||
@@ -15,8 +17,15 @@ const emailForm = document.querySelector('#email-form'),
|
|||||||
qrModalTitle = document.querySelector('#qr-modal-title');
|
qrModalTitle = document.querySelector('#qr-modal-title');
|
||||||
|
|
||||||
let empresas = [];
|
let empresas = [];
|
||||||
|
let currentEmailConfig = {};
|
||||||
|
let lastEmailStatus = null;
|
||||||
|
let lastEmailFeedback = null;
|
||||||
|
|
||||||
const Icons = {
|
const Icons = {
|
||||||
|
mail: '<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"></rect><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"></path></svg>',
|
||||||
|
connect: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>',
|
||||||
|
sync: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M21.5 2v6h-6M2.5 22v-6h6M2 11.5a10 10 0 0 1 18.8-4.3M22 12.5a10 10 0 0 1-18.8 4.2"></path></svg>',
|
||||||
|
edit: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z"></path></svg>',
|
||||||
userCheck: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="8.5" cy="7" r="4"></circle><polyline points="17 11 19 13 23 9"></polyline></svg>',
|
userCheck: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="8.5" cy="7" r="4"></circle><polyline points="17 11 19 13 23 9"></polyline></svg>',
|
||||||
qrCode: '<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="3" width="7" height="7"></rect><rect x="14" y="3" width="7" height="7"></rect><rect x="3" y="14" width="7" height="7"></rect><rect x="14" y="14" width="3" height="3"></rect><rect x="18" y="18" width="3" height="3"></rect><rect x="18" y="14" width="3" height="3"></rect><rect x="14" y="18" width="3" height="3"></rect></svg>',
|
qrCode: '<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="3" width="7" height="7"></rect><rect x="14" y="3" width="7" height="7"></rect><rect x="3" y="14" width="7" height="7"></rect><rect x="14" y="14" width="3" height="3"></rect><rect x="18" y="18" width="3" height="3"></rect><rect x="18" y="14" width="3" height="3"></rect><rect x="14" y="18" width="3" height="3"></rect></svg>',
|
||||||
restart: '<svg viewBox="0 0 24 24" aria-hidden="true"><polyline points="23 4 23 10 17 10"></polyline><polyline points="1 20 1 14 7 14"></polyline><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path></svg>',
|
restart: '<svg viewBox="0 0 24 24" aria-hidden="true"><polyline points="23 4 23 10 17 10"></polyline><polyline points="1 20 1 14 7 14"></polyline><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path></svg>',
|
||||||
@@ -33,6 +42,121 @@ function getEmailFormData() {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderEmailCard(cfg) {
|
||||||
|
if (!emailCardContainer) return;
|
||||||
|
const isConfigured = !!(cfg && (cfg.smtp_host || cfg.imap_host || cfg.smtp_user || cfg.imap_user));
|
||||||
|
if (!isConfigured) {
|
||||||
|
emailCardContainer.innerHTML = `
|
||||||
|
<div class="email-empty-card">
|
||||||
|
<div style="display: inline-grid; place-items: center; width: 48px; height: 48px; border-radius: 12px; background: var(--bg-soft, #f4f6f8); color: var(--muted-strong, #64748b); margin: 0 auto 12px auto;">
|
||||||
|
${Icons.mail}
|
||||||
|
</div>
|
||||||
|
<h4 style="margin: 0 0 6px 0; font-size: 15px; font-weight: 700; color: var(--text, #1e293b);">Nenhuma conta de e-mail configurada</h4>
|
||||||
|
<p style="margin: 0 0 16px 0; font-size: 13px; color: var(--muted-strong, #64748b);">Clique no botão de adicionar (+) acima ou no botão abaixo para configurar o e-mail do sistema.</p>
|
||||||
|
<button class="btn secondary" type="button" onclick="abrirModalEmail()">Configurar E-mail</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const smtpBadge = lastEmailStatus
|
||||||
|
? `<span class="badge ${lastEmailStatus.smtpOk ? 'ok' : 'warn'}">SMTP: ${lastEmailStatus.smtpOk ? 'Conectado' : 'Erro'}</span>`
|
||||||
|
: `<span class="badge">SMTP: Não testado</span>`;
|
||||||
|
const imapBadge = lastEmailStatus
|
||||||
|
? `<span class="badge ${lastEmailStatus.imapOk ? 'ok' : 'warn'}">IMAP: ${lastEmailStatus.imapOk ? 'Conectado' : 'Erro'}</span>`
|
||||||
|
: `<span class="badge">IMAP: Não testado</span>`;
|
||||||
|
|
||||||
|
const userDisplay = cfg.smtp_user || cfg.imap_user || 'E-mail do Sistema';
|
||||||
|
const remetenteDisplay = cfg.smtp_from || 'Central de Notificações';
|
||||||
|
|
||||||
|
emailCardContainer.innerHTML = `
|
||||||
|
<article class="email-card">
|
||||||
|
<header class="email-card-header">
|
||||||
|
<div class="email-card-title-group">
|
||||||
|
<div class="email-icon-bubble">
|
||||||
|
${Icons.mail}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="email-card-user">${esc(userDisplay)}</h3>
|
||||||
|
<span class="email-card-remetente">${esc(remetenteDisplay)}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="email-card-badges">
|
||||||
|
${smtpBadge}
|
||||||
|
${imapBadge}
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div class="email-card-body">
|
||||||
|
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
|
||||||
|
<div style="background: #f8fafc; border: 1px solid var(--line); border-radius: 8px; padding: 12px 14px;">
|
||||||
|
<strong style="display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--brand); margin-bottom: 8px;">
|
||||||
|
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><line x1="22" y1="2" x2="11" y2="13"></line><polygon points="22 2 15 22 11 13 2 9 22 2"></polygon></svg>
|
||||||
|
Saída (SMTP)
|
||||||
|
</strong>
|
||||||
|
<div style="font-size: 13px; display: flex; flex-direction: column; gap: 4px;">
|
||||||
|
<div><strong>Servidor:</strong> <code>${esc(cfg.smtp_host || '-')}:${esc(cfg.smtp_port || '465')}</code></div>
|
||||||
|
<div><strong>Segurança:</strong> <span class="badge" style="font-size: 11px;">${esc(String(cfg.smtp_security || 'ssl_tls').toUpperCase())}</span></div>
|
||||||
|
<div><strong>Usuário:</strong> ${esc(cfg.smtp_user || '-')}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="background: #f8fafc; border: 1px solid var(--line); border-radius: 8px; padding: 12px 14px;">
|
||||||
|
<strong style="display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--brand); margin-bottom: 8px;">
|
||||||
|
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><polyline points="22 12 16 12 14 15 10 15 8 12 2 12"></polyline><path d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"></path></svg>
|
||||||
|
Recebimento (IMAP)
|
||||||
|
</strong>
|
||||||
|
<div style="font-size: 13px; display: flex; flex-direction: column; gap: 4px;">
|
||||||
|
<div><strong>Servidor:</strong> <code>${esc(cfg.imap_host || '-')}:${esc(cfg.imap_port || '993')}</code></div>
|
||||||
|
<div><strong>Segurança:</strong> <span class="badge" style="font-size: 11px;">${esc(String(cfg.imap_security || 'ssl_tls').toUpperCase())}</span></div>
|
||||||
|
<div><strong>Usuário:</strong> ${esc(cfg.imap_user || '-')}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="email-card-feedback" class="email-status-feedback-box ${lastEmailFeedback ? '' : 'hidden'}">
|
||||||
|
${lastEmailFeedback || ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="email-card-footer">
|
||||||
|
<span style="font-size: 12px; font-weight: 600; color: var(--muted-strong);">Ações:</span>
|
||||||
|
<div class="table-actions">
|
||||||
|
<button class="table-icon-btn" type="button" id="btn-icon-testar-email" onclick="testarEConectarEmail()" title="Testar e Conectar" aria-label="Testar e Conectar">
|
||||||
|
${Icons.connect}
|
||||||
|
</button>
|
||||||
|
<button class="table-icon-btn" type="button" id="btn-icon-sync-email" onclick="sincronizarEmailsAgora()" title="Sincronizar Respostas Agora" aria-label="Sincronizar Respostas Agora">
|
||||||
|
${Icons.sync}
|
||||||
|
</button>
|
||||||
|
<button class="table-icon-btn" type="button" onclick="abrirModalEmail()" title="Editar Configurações" aria-label="Editar Configurações">
|
||||||
|
${Icons.edit}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</article>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function abrirModalEmail() {
|
||||||
|
const modal = document.querySelector('#email-modal');
|
||||||
|
if (modal) {
|
||||||
|
if (emailForm && currentEmailConfig) {
|
||||||
|
for (const [k, v] of Object.entries(currentEmailConfig)) {
|
||||||
|
if (emailForm.elements[k]) {
|
||||||
|
if (emailForm.elements[k].type === 'checkbox') {
|
||||||
|
emailForm.elements[k].checked = (v === 'true' || v === true);
|
||||||
|
} else if (emailForm.elements[k].type !== 'password') {
|
||||||
|
emailForm.elements[k].value = v || '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
modal.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.abrirModalEmail = abrirModalEmail;
|
||||||
|
|
||||||
|
function fecharModalEmail() {
|
||||||
|
document.querySelector('#email-modal')?.classList.add('hidden');
|
||||||
|
}
|
||||||
|
window.fecharModalEmail = fecharModalEmail;
|
||||||
|
|
||||||
const emailKeys = ['imap_host', 'imap_port', 'imap_security', 'imap_user', 'smtp_host', 'smtp_port', 'smtp_security', 'smtp_user', 'smtp_from'];
|
const emailKeys = ['imap_host', 'imap_port', 'imap_security', 'imap_user', 'smtp_host', 'smtp_port', 'smtp_security', 'smtp_user', 'smtp_from'];
|
||||||
const abacateKeys = ['abacatepay_api_key', 'abacatepay_webhook_secret'];
|
const abacateKeys = ['abacatepay_api_key', 'abacatepay_webhook_secret'];
|
||||||
|
|
||||||
@@ -100,6 +224,9 @@ async function load() {
|
|||||||
try {
|
try {
|
||||||
const d = await Api.get('/api/master/configuracoes');
|
const d = await Api.get('/api/master/configuracoes');
|
||||||
const cfg = d.configuracoes || {};
|
const cfg = d.configuracoes || {};
|
||||||
|
currentEmailConfig = cfg;
|
||||||
|
renderEmailCard(cfg);
|
||||||
|
|
||||||
for (const [k, v] of Object.entries(cfg)) {
|
for (const [k, v] of Object.entries(cfg)) {
|
||||||
if (emailForm?.elements[k]) {
|
if (emailForm?.elements[k]) {
|
||||||
if (emailForm.elements[k].type === 'checkbox') {
|
if (emailForm.elements[k].type === 'checkbox') {
|
||||||
@@ -307,9 +434,9 @@ async function rejeitar(emp, id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emailForm.onsubmit = async e => {
|
async function salvarConfiguracaoEmail(e) {
|
||||||
e.preventDefault();
|
if (e) e.preventDefault();
|
||||||
const btn = document.querySelector('#btn-salvar-email');
|
const btn = document.querySelector('#btn-modal-salvar-email');
|
||||||
if (btn) {
|
if (btn) {
|
||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
btn.textContent = 'Salvando...';
|
btn.textContent = 'Salvando...';
|
||||||
@@ -318,6 +445,7 @@ emailForm.onsubmit = async e => {
|
|||||||
const payload = getEmailFormData();
|
const payload = getEmailFormData();
|
||||||
await Api.put('/api/master/configuracoes', payload);
|
await Api.put('/api/master/configuracoes', payload);
|
||||||
Util.toast('Configurações de e-mail salvas com sucesso!');
|
Util.toast('Configurações de e-mail salvas com sucesso!');
|
||||||
|
fecharModalEmail();
|
||||||
await load();
|
await load();
|
||||||
testarEConectarEmail();
|
testarEConectarEmail();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -325,50 +453,42 @@ emailForm.onsubmit = async e => {
|
|||||||
} finally {
|
} finally {
|
||||||
if (btn) {
|
if (btn) {
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
btn.textContent = 'Salvar configurações';
|
btn.textContent = 'Salvar Configurações';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
window.salvarConfiguracaoEmail = salvarConfiguracaoEmail;
|
||||||
|
if (emailForm) emailForm.onsubmit = salvarConfiguracaoEmail;
|
||||||
|
|
||||||
window.testarEConectarEmail = async () => {
|
window.testarEConectarEmail = async () => {
|
||||||
const btn = document.querySelector('#btn-testar-email');
|
const btn = document.querySelector('#btn-icon-testar-email');
|
||||||
const feedback = document.querySelector('#email-status-feedback');
|
if (btn) btn.disabled = true;
|
||||||
const headerBadges = document.querySelector('#email-header-status-badges');
|
|
||||||
if (btn) {
|
lastEmailFeedback = '<span class="muted">Testando conexões SMTP e IMAP...</span>';
|
||||||
btn.disabled = true;
|
renderEmailCard(currentEmailConfig);
|
||||||
btn.textContent = 'Testando conexão...';
|
|
||||||
}
|
|
||||||
if (feedback) {
|
|
||||||
feedback.classList.remove('hidden');
|
|
||||||
feedback.innerHTML = '<span class="muted">Testando conexões SMTP e IMAP...</span>';
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
const payload = getEmailFormData();
|
const payload = getEmailFormData();
|
||||||
const res = await Api.post('/api/master/configuracoes/testar-email', payload);
|
const dataToSend = Object.assign({}, currentEmailConfig, payload);
|
||||||
|
const res = await Api.post('/api/master/configuracoes/testar-email', dataToSend);
|
||||||
const smtpOk = !!res?.smtp?.ok;
|
const smtpOk = !!res?.smtp?.ok;
|
||||||
const imapOk = !!res?.imap?.ok;
|
const imapOk = !!res?.imap?.ok;
|
||||||
|
|
||||||
if (headerBadges) {
|
lastEmailStatus = { smtpOk, imapOk };
|
||||||
headerBadges.innerHTML = `
|
|
||||||
<span class="badge ${smtpOk ? 'ok' : 'warn'}">SMTP: ${smtpOk ? 'Conectado' : 'Erro'}</span>
|
|
||||||
<span class="badge ${imapOk ? 'ok' : 'warn'}">IMAP: ${imapOk ? 'Conectado' : 'Erro'}</span>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (feedback) {
|
lastEmailFeedback = `
|
||||||
feedback.classList.remove('hidden');
|
<div style="display: flex; gap: 12px; align-items: center; margin-bottom: 8px;">
|
||||||
feedback.innerHTML = `
|
<strong>Resultado do Teste:</strong>
|
||||||
<div style="display: flex; gap: 12px; align-items: center; margin-bottom: 8px;">
|
<span class="badge ${smtpOk ? 'ok' : 'warn'}">SMTP ${smtpOk ? 'Conectado' : 'Falhou'}</span>
|
||||||
<strong>Status da Conexão:</strong>
|
<span class="badge ${imapOk ? 'ok' : 'warn'}">IMAP ${imapOk ? 'Conectado' : 'Falhou'}</span>
|
||||||
<span class="badge ${smtpOk ? 'ok' : 'warn'}">SMTP ${smtpOk ? 'Conectado' : 'Falhou'}</span>
|
</div>
|
||||||
<span class="badge ${imapOk ? 'ok' : 'warn'}">IMAP ${imapOk ? 'Conectado' : 'Falhou'}</span>
|
<div style="font-size: 13px; line-height: 1.5;">
|
||||||
</div>
|
<p style="margin: 3px 0;"><strong>Saída (SMTP):</strong> ${esc(res?.smtp?.mensagem || '')}</p>
|
||||||
<div style="font-size: 13.5px; line-height: 1.6;">
|
<p style="margin: 3px 0;"><strong>Recebimento (IMAP):</strong> ${esc(res?.imap?.mensagem || '')}</p>
|
||||||
<p style="margin: 4px 0;"><strong>Email de saída (SMTP):</strong> ${esc(res?.smtp?.mensagem || '')}</p>
|
</div>
|
||||||
<p style="margin: 4px 0;"><strong>Email recebido (IMAP):</strong> ${esc(res?.imap?.mensagem || '')}</p>
|
`;
|
||||||
</div>
|
|
||||||
`;
|
renderEmailCard(currentEmailConfig);
|
||||||
}
|
|
||||||
|
|
||||||
if (res?.ok) {
|
if (res?.ok) {
|
||||||
Util.toast('Conexão de e-mail (SMTP e IMAP) estabelecida com sucesso!');
|
Util.toast('Conexão de e-mail (SMTP e IMAP) estabelecida com sucesso!');
|
||||||
@@ -376,40 +496,34 @@ window.testarEConectarEmail = async () => {
|
|||||||
Util.toast('Falha ao conectar em um ou mais servidores de e-mail.', true);
|
Util.toast('Falha ao conectar em um ou mais servidores de e-mail.', true);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (feedback) {
|
lastEmailFeedback = `<span style="color:var(--danger)">Erro ao testar conexão: ${esc(err.message)}</span>`;
|
||||||
feedback.classList.remove('hidden');
|
renderEmailCard(currentEmailConfig);
|
||||||
feedback.innerHTML = `<span style="color:var(--danger)">Erro ao testar conexão: ${esc(err.message)}</span>`;
|
|
||||||
}
|
|
||||||
Util.toast(err.message, true);
|
Util.toast(err.message, true);
|
||||||
} finally {
|
} finally {
|
||||||
if (btn) {
|
const b = document.querySelector('#btn-icon-testar-email');
|
||||||
btn.disabled = false;
|
if (b) b.disabled = false;
|
||||||
btn.textContent = 'Testar e Conectar';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.sincronizarEmailsAgora = async () => {
|
window.sincronizarEmailsAgora = async () => {
|
||||||
const btn = document.querySelector('#btn-sync-email');
|
const btn = document.querySelector('#btn-icon-sync-email');
|
||||||
const feedback = document.querySelector('#email-status-feedback');
|
if (btn) btn.disabled = true;
|
||||||
if (btn) {
|
|
||||||
btn.disabled = true;
|
lastEmailFeedback = '<span class="muted">Sincronizando respostas de e-mail...</span>';
|
||||||
btn.textContent = 'Sincronizando...';
|
renderEmailCard(currentEmailConfig);
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
const res = await Api.post('/api/master/configuracoes/sincronizar-email', {});
|
const res = await Api.post('/api/master/configuracoes/sincronizar-email', {});
|
||||||
Util.toast(res?.mensagem || 'E-mails sincronizados com sucesso.');
|
Util.toast(res?.mensagem || 'E-mails sincronizados com sucesso.');
|
||||||
if (feedback) {
|
lastEmailFeedback = `<p style="margin: 0; color: var(--brand-strong);"><strong>Sincronização de Respostas:</strong> ${esc(res?.mensagem || '')}</p>`;
|
||||||
feedback.classList.remove('hidden');
|
renderEmailCard(currentEmailConfig);
|
||||||
feedback.innerHTML = `<p style="margin: 0; color: var(--brand-strong);"><strong>Sincronização de Respostas:</strong> ${esc(res?.mensagem || '')}</p>`;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
lastEmailFeedback = `<span style="color:var(--danger)">Erro na sincronização: ${esc(err.message)}</span>`;
|
||||||
|
renderEmailCard(currentEmailConfig);
|
||||||
Util.toast(err.message, true);
|
Util.toast(err.message, true);
|
||||||
} finally {
|
} finally {
|
||||||
if (btn) {
|
const b = document.querySelector('#btn-icon-sync-email');
|
||||||
btn.disabled = false;
|
if (b) b.disabled = false;
|
||||||
btn.textContent = 'Sincronizar Respostas Agora';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user