Spaces:
Sleeping
Sleeping
File size: 4,482 Bytes
197ac2a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | import { useEffect, useState } from "react";
import SecaoHeader from "../components/SecaoHeader.jsx";
import {
getBaseUrl,
setBaseUrl,
getApiKey,
setApiKey,
verificarSaude,
listarEmailsCc,
adicionarEmailCc,
removerEmailCc,
} from "../api.js";
export default function Config({ notificar, onConfigSalva }) {
const [base, setBase] = useState(getBaseUrl());
const [key, setKey] = useState(getApiKey());
const [emailsCc, setEmailsCc] = useState([]);
const [novoEmail, setNovoEmail] = useState("");
const [carregandoCc, setCarregandoCc] = useState(true);
async function carregarEmailsCc() {
setCarregandoCc(true);
try {
const d = await listarEmailsCc();
setEmailsCc(d.emails_cc || []);
} catch (e) {
notificar("Falha ao carregar e-mails em cópia: " + e.message, "bad");
} finally {
setCarregandoCc(false);
}
}
useEffect(() => {
carregarEmailsCc();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
function salvarConexao() {
setBaseUrl(base);
setApiKey(key);
notificar("Configuração salva", "ok");
onConfigSalva?.();
}
async function testarConexao() {
setBaseUrl(base);
setApiKey(key);
try {
await verificarSaude();
notificar("Online ✓", "ok");
} catch {
notificar("Sem conexão", "bad");
}
onConfigSalva?.();
}
async function handleAdicionarEmail(e) {
e.preventDefault();
const email = novoEmail.trim();
if (!email) return;
try {
const d = await adicionarEmailCc(email);
setEmailsCc(d.emails_cc || []);
setNovoEmail("");
notificar("E-mail cadastrado em cópia", "ok");
} catch (err) {
notificar(err.message, "bad");
}
}
async function handleRemoverEmail(email) {
try {
const d = await removerEmailCc(email);
setEmailsCc(d.emails_cc || []);
notificar("E-mail removido da cópia", "ok");
} catch (err) {
notificar(err.message, "bad");
}
}
return (
<>
<div className="card" style={{ maxWidth: 620 }}>
<SecaoHeader icone="⚙️" titulo="Conexão" cor="#64748b" />
<label className="lbl">URL da API (Space)</label>
<input type="text" value={base} onChange={(e) => setBase(e.target.value)} />
<div style={{ height: 12 }}></div>
<label className="lbl">X-API-Key (vazio se o Space não exige)</label>
<input type="password" value={key} onChange={(e) => setKey(e.target.value)} />
<div style={{ display: "flex", gap: 9, marginTop: 18, flexWrap: "wrap" }}>
<button className="btn btn-ghost btn-sm" onClick={testarConexao}>
Testar conexão
</button>
<button className="btn btn-primary btn-sm" onClick={salvarConexao}>
Salvar
</button>
</div>
<div className="empty" style={{ textAlign: "left", padding: "16px 0 0", color: "var(--muted)" }}>
As telas leem os dados salvos no Turso (GET /day). Use <b>▶ Rodar</b> para gerar um novo dia.
</div>
</div>
<div className="card" style={{ maxWidth: 620 }}>
<SecaoHeader icone="✉️" titulo="E-mails em cópia (Cc)" cor="#0d9488" />
<div className="empty" style={{ textAlign: "left", padding: 0, color: "var(--muted)", fontSize: 13 }}>
Além do destinatário principal (fixo, definido no Space), estes e-mails recebem cópia do relatório
diário. Cadastrados aqui — persistidos no Turso, sem precisar de redeploy.
</div>
{carregandoCc ? (
<div className="empty">Carregando…</div>
) : emailsCc.length === 0 ? (
<div className="empty">Nenhum e-mail em cópia cadastrado.</div>
) : (
<ul className="cclist">
{emailsCc.map((e) => (
<li className="ccrow" key={e}>
<span>{e}</span>
<button onClick={() => handleRemoverEmail(e)}>Remover</button>
</li>
))}
</ul>
)}
<form className="ccadd" onSubmit={handleAdicionarEmail}>
<input
type="email"
placeholder="novo-email@empresa.com"
value={novoEmail}
onChange={(e) => setNovoEmail(e.target.value)}
required
/>
<button className="btn btn-primary btn-sm" type="submit">
Adicionar
</button>
</form>
</div>
</>
);
}
|