e.stopPropagation()}>
{initials}
{c.name}
{c.form.industria} · {c.location}
{st.label}
{stage?.label}
{tab === "detalle" &&
}
{tab === "notes" &&
{c.notes.length === 0 &&
Sin notas. Visibles solo para el equipo.
}
{c.notes.map((n, i) =>
{n.who} · {n.ts}
{editingNote === i
?
:
{n.body}
}
)}
}
{tab === "hist" &&
{c.history.map((h, i) =>
{h.e} {h.det && — {h.det}}
{h.ts}
)}
{c.history.length === 0 &&
Sin eventos registrados
}
}
>);
}
function DetailPane({ c, dateLong, onUpdateSale }) {
const SOURCES = window.REVOLVR_DATA.SOURCES;
const src = SOURCES[c.utm.source] || { label: c.utm.source };
return (
{/* Venta (solo cuando la llamada está cerrada ganada) */}
{c.stage === "ganada" &&
}
{/* Cita */}
Cita agendada
} label="Fecha y hora" value={dateLong}/>
} label="Tipo de evento" value={c.eventType}/>
} label="Zona horaria" value={c.timezone}/>
} label="Reunión" value={Abrir enlace ↗}/>
{/* Contacto */}
Contacto
} label="Correo" value={{c.email}}/>
} label="Teléfono" value={}/>
} label="Ubicación" value={c.location}/>
{/* Respuestas del formulario de Calendly */}
Respuestas del formulario
} label="Industria" value={c.form.industria}/>
} label="Equipo" value={c.form.equipo}/>
} label="Facturación" value={c.form.facturacion}/>
{/* Atribución / UTM */}
Atribución (UTM)
source{c.utm.source}
medium{c.utm.medium}
campaign{c.utm.campaign}
);
}
function SaleSection({ c, onUpdateSale }) {
const base = c.sale || { programa: "", total: c.value || 0, tipo: "total", pagado: 0 };
const [sale, setSale] = React.useState(base);
const [dirty, setDirty] = React.useState(false);
React.useEffect(() => { setSale(c.sale || base); setDirty(false); /* eslint-disable-next-line */ }, [c.id]);
const set = (patch) => { setSale((s) => ({ ...s, ...patch })); setDirty(true); };
const pagado = sale.tipo === "total" ? Number(sale.total || 0) : Number(sale.pagado || 0);
const saldo = Math.max(0, Number(sale.total || 0) - pagado);
const paid = saldo <= 0 && Number(sale.total) > 0;
const save = () => {
const clean = { programa: sale.programa.trim() || "Programa", total: Number(sale.total) || 0,
tipo: sale.tipo, pagado: sale.tipo === "total" ? Number(sale.total) || 0 : Number(sale.pagado) || 0 };
onUpdateSale(c.id, clean);
setDirty(false);
};
return (
Venta {paid ? "Pagado" : "Saldo pendiente"}
{!paid && sale.tipo === "abono" && }
);
}
function PhoneValue({ phone }) {
const [copied, setCopied] = React.useState(false);
const waUrl = "https://wa.me/" + phone.replace(/[^\d]/g, "");
const copy = () => {
navigator.clipboard && navigator.clipboard.writeText(phone);
setCopied(true);
setTimeout(() => setCopied(false), 1500);
};
return (
{phone}
{ e.preventDefault(); window.open(waUrl, "_blank", "noopener,noreferrer"); }}>WhatsApp ↗
);
}
function InfoRow({ icon, label, value }) {
return (
{icon}
{label}
{value}
);
}
function FormCell({ icon, label, value, wide }) {
return (
{icon && {icon}}{label}
{value}
);
}
const IconUserMini = () => (
);
const IconMoney = () => (
);
function Field({ label, children }) {
return (
);
}
Object.assign(window, { Drawer });