From 2e25005d63cf8e17e10f0c6699c3c8e071b675f7 Mon Sep 17 00:00:00 2001 From: Administrator Date: Sat, 19 Sep 2026 11:46:28 -0500 Subject: [PATCH] Actualizar frontend/src/pages/Vendedores.jsx --- frontend/src/pages/Vendedores.jsx | 92 ++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/Vendedores.jsx b/frontend/src/pages/Vendedores.jsx index 0151d0e..3282c8c 100644 --- a/frontend/src/pages/Vendedores.jsx +++ b/frontend/src/pages/Vendedores.jsx @@ -14,6 +14,11 @@ export default function Vendedores() { const [mes, setMes] = useState(String(_hoy.getMonth() + 1)); // mes actual const [dia, setDia] = useState("TODOS"); const [modoTR, setModoTR] = useState("asig"); // "asig" | "resp" para el grafico de tiempo + // Pop-up de detalle al hacer click en un gráfico + const [detDia, setDetDia] = useState(null); + const [detData, setDetData] = useState(null); + const [detLoading, setDetLoading] = useState(false); + const [detModo, setDetModo] = useState("asignacion"); const [filtros, setFiltros] = useState({ anos: [2026] }); const [data, setData] = useState(null); @@ -103,6 +108,16 @@ export default function Vendedores() { return data.tiempo_resp_r_total || []; }, [data, vend]); + const abrirDetalle = (diaNum, modoForzado) => { + if (!diaNum) return; + const modo = modoForzado || (modoTR === "resp" ? "respuesta" : "asignacion"); + setDetDia(diaNum); setDetModo(modo); setDetData(null); setDetLoading(true); + api.tiempoRespuestaDetalle(diaNum, modo, vend, ano, mes) + .then((r) => setDetData(r)) + .catch(() => setDetData({ asesores: [], total: { cantidad: 0, promedio_min: 0 } })) + .finally(() => setDetLoading(false)); + }; + return (

🧑‍💼 Vendedores

@@ -222,7 +237,9 @@ export default function Vendedores() {
- + abrirDetalle(p && p.activePayload && p.activePayload[0] && p.activePayload[0].payload.dia)} + style={{ cursor: "pointer" }}> @@ -247,7 +264,7 @@ export default function Vendedores() { + activeDot={{ r: 7, fill: colorSoft, stroke: "#fff", strokeWidth: 2, cursor: "pointer" }} />
@@ -278,7 +295,9 @@ export default function Vendedores() { } return ( - + abrirDetalle(p && p.activePayload && p.activePayload[0] && p.activePayload[0].payload.dia, "sin_responder")} + style={{ cursor: "pointer" }}> @@ -357,6 +376,73 @@ export default function Vendedores() { } + + {/* Pop-up: detalle del día (leads por asesor con T1, T2 y minutos) */} + {detDia != null && ( +
setDetDia(null)} + style={{ position: "fixed", inset: 0, background: "rgba(15,23,42,0.45)", + display: "flex", alignItems: "center", justifyContent: "center", zIndex: 1000, padding: 20 }}> +
e.stopPropagation()} + style={{ background: "#fff", borderRadius: 14, width: "100%", maxWidth: 820, + maxHeight: "85vh", overflow: "auto", boxShadow: "0 20px 60px rgba(0,0,0,0.3)" }}> +
+
+ {detModo === "sin_responder" ? "🚫" : "⏱️"} Detalle Día {detDia} · { + detModo === "sin_responder" ? "Sin Responder" + : detModo === "respuesta" ? "Según Respuesta" : "Según Asignación"} + {detData && + {" · "}{detModo === "sin_responder" + ? `${detData.total?.cantidad || 0} sin responder` + : `Promedio: ${detData.total?.promedio_min || 0} min (${detData.total?.cantidad || 0} leads)`}} +
+ +
+
+ {detLoading ? ( +
Cargando…
+ ) : !detData || (detData.asesores || []).length === 0 ? ( +
Sin leads para este día.
+ ) : ( + (detData.asesores || []).map((a) => ( +
+
+ 👤 {a.asesor} + + {detModo === "sin_responder" + ? `${a.cantidad} sin responder` + : `Promedio: ${a.promedio_min} min · ${a.cantidad} leads`} +
+ + + + + + + + + + + {a.leads.map((l, i) => ( + + + + + + + ))} + +
TELÉFONOASIGNACIÓN (T1)RESPUESTA (T2)MINUTOS
{l.telefono || "-"}{l.t1}{l.t2}{l.minutos}
+
+ )) + )} +
+
+
+ )} ); }