Actualizar frontend/src/components/ConfigModal.jsx

This commit is contained in:
2026-10-09 13:47:55 -05:00
parent d3c74725d6
commit f2f78fe49d

View File

@@ -888,9 +888,16 @@ export default function ConfigModal({ onClose }) {
<button onClick={() => setSeccion("plantillas")} <button onClick={() => setSeccion("plantillas")}
style={{ width: "100%", textAlign: "left", padding: "10px 12px", borderRadius: 8, style={{ width: "100%", textAlign: "left", padding: "10px 12px", borderRadius: 8,
border: "none", cursor: "pointer", fontSize: 14, fontWeight: 600, whiteSpace: "nowrap", border: "none", cursor: "pointer", fontSize: 14, fontWeight: 600, whiteSpace: "nowrap",
marginBottom: 4,
background: seccion === "plantillas" ? "#e2e8f0" : "transparent", color: "#1e293b" }}> background: seccion === "plantillas" ? "#e2e8f0" : "transparent", color: "#1e293b" }}>
Plantillas Plantillas
</button> </button>
<button onClick={() => setSeccion("exportar_base")}
style={{ width: "100%", textAlign: "left", padding: "10px 12px", borderRadius: 8,
border: "none", cursor: "pointer", fontSize: 14, fontWeight: 600, whiteSpace: "nowrap",
background: seccion === "exportar_base" ? "#e2e8f0" : "transparent", color: "#1e293b" }}>
Exportar Base
</button>
</div> </div>
{/* Contenido */} {/* Contenido */}
<div style={{ flex: 1, display: "flex", flexDirection: "column" }}> <div style={{ flex: 1, display: "flex", flexDirection: "column" }}>
@@ -902,6 +909,7 @@ export default function ConfigModal({ onClose }) {
: seccion === "leyendas" ? "Leyenda" : seccion === "leyendas" ? "Leyenda"
: seccion === "plantillas" ? "Plantillas" : seccion === "plantillas" ? "Plantillas"
: seccion === "subir_base" ? "Subir Base" : seccion === "subir_base" ? "Subir Base"
: seccion === "exportar_base" ? "Exportar Base"
: "Sedes de Anuncios"} : "Sedes de Anuncios"}
</div> </div>
<button onClick={onClose} <button onClick={onClose}
@@ -912,6 +920,10 @@ export default function ConfigModal({ onClose }) {
<div style={{ flex: 1, overflow: "auto", padding: "16px 22px 24px" }}> <div style={{ flex: 1, overflow: "auto", padding: "16px 22px 24px" }}>
<SubirBase /> <SubirBase />
</div> </div>
) : seccion === "exportar_base" ? (
<div style={{ flex: 1, overflow: "auto", padding: "16px 22px 24px" }}>
<ExportarBase />
</div>
) : seccion === "plantillas" ? ( ) : seccion === "plantillas" ? (
<div style={{ flex: 1, overflow: "auto", padding: "16px 22px 24px" }}> <div style={{ flex: 1, overflow: "auto", padding: "16px 22px 24px" }}>
<Plantillas ocultarTitulo /> <Plantillas ocultarTitulo />
@@ -1238,3 +1250,97 @@ function SubirBase() {
</div> </div>
); );
} }
// ── EXPORTAR BASE ──────────────────────────────────────────────────────────
// Elige un asesor (en vivo de Chatwoot) y descarga su base de leads deduplicada
// (teléfono más antiguo), con SEDE_ACT por asesor y última etiqueta.
function ExportarBase() {
const [asesores, setAsesores] = useState([]);
const [asesorSel, setAsesorSel] = useState("");
const [etiquetas, setEtiquetas] = useState([]);
const [etiqSel, setEtiqSel] = useState([]);
const [cargando, setCargando] = useState(false);
const [msg, setMsg] = useState("");
useEffect(() => {
api.exportarBaseAsesores().then((r) => setAsesores(r.asesores || [])).catch(() => {});
api.subirBaseEtiquetas().then((r) => setEtiquetas(r.etiquetas || [])).catch(() => {});
}, []);
function toggleEtiqueta(t) {
setEtiqSel((p) => p.includes(t) ? p.filter((x) => x !== t) : [...p, t]);
}
async function exportar() {
if (!asesorSel || cargando) return;
setCargando(true); setMsg("");
try {
await api.exportarBaseDescargar(asesorSel, etiqSel);
setMsg("✓ Base descargada.");
} catch (e) {
setMsg("Error al exportar: " + e.message);
}
setCargando(false);
}
const puede = asesorSel && !cargando;
const card = { background: "#fff", border: "1px solid #e6eaf0", borderRadius: 14,
padding: 20, boxShadow: "0 1px 3px rgba(15,23,42,.04)" };
const cardHead = { display: "flex", alignItems: "center", gap: 10, marginBottom: 4 };
const step = { width: 26, height: 26, borderRadius: 8, background: "#1e3a5f", color: "#fff",
display: "flex", alignItems: "center", justifyContent: "center",
fontSize: 13, fontWeight: 800, flexShrink: 0 };
const cardTitle = { fontSize: 15, fontWeight: 700, color: "#0f172a" };
const cardSub = { fontSize: 12.5, color: "#94a3b8", margin: "2px 0 14px 36px" };
const fieldLabel = { fontSize: 12, fontWeight: 700, color: "#64748b", marginBottom: 7,
textTransform: "uppercase", letterSpacing: ".02em", display: "block" };
return (
<div style={{ display: "flex", flexDirection: "column", gap: 16, maxWidth: 680 }}>
<div style={card}>
<div style={cardHead}>
<span style={step}>1</span>
<span style={cardTitle}>Elige el asesor</span>
</div>
<div style={cardSub}>
Se descargará su base de leads (un número por teléfono, el más antiguo),
con sede, programa, fecha y última etiqueta.
</div>
<label style={fieldLabel}>👤 Asesor</label>
<Select value={asesorSel}
options={[{ value: "", label: "— Elige un asesor —" },
...asesores.map((a) => ({ value: a.nombre, label: a.nombre }))]}
onChange={(v) => { setAsesorSel(v); setMsg(""); }}
minWidth={0} />
</div>
<div style={card}>
<div style={cardHead}>
<span style={step}>2</span>
<span style={cardTitle}>Etiquetas (opcional)</span>
<span style={{ marginLeft: "auto", fontSize: 12, color: "#94a3b8", fontWeight: 600 }}>
{etiqSel.length} seleccionada{etiqSel.length === 1 ? "" : "s"}
</span>
</div>
<div style={cardSub}>
Filtra la base por la última etiqueta de cada número. Si no eliges ninguna,
se incluyen todas.
</div>
<label style={fieldLabel}>🏷️ Etiquetas de Chatwoot</label>
<MultiSelectEtiquetas opciones={etiquetas} seleccion={etiqSel} onToggle={toggleEtiqueta} />
</div>
<button onClick={exportar} disabled={!puede}
style={{ width: "100%", padding: "13px", borderRadius: 11, border: "none",
background: puede ? "#1e3a5f" : "#cbd5e1", color: "#fff", fontWeight: 700, fontSize: 14.5,
cursor: puede ? "pointer" : "default" }}>
{cargando ? "Generando Excel…" : "⬇ Exportar base a Excel"}
</button>
{msg && (
<div style={{ fontSize: 13, fontWeight: 600,
color: msg.startsWith("✓") ? "#15803d" : "#b91c1c" }}>{msg}</div>
)}
</div>
);
}