// AllenOps.jsx — Internal backoffice for the Allen ops team.
// Per PRODUCT.md: "Allen ops: curación de destacados, fee overrides, disputas,
// aprobaciones. Web primero." — the only canonical web surface in spec.
//
// Sections: Dashboard, Aprobaciones (KYC), Disputas, Comisiones, Curación, Sellers.
const { useState: useOpsState } = React;
const OPS_NAV = [
{ id: "dashboard", label: "Dashboard", icon: "tune" },
{ id: "aprobaciones", label: "Aprobaciones", icon: "verified", badge: 7 },
{ id: "disputas", label: "Disputas", icon: "support_agent", badge: 12 },
{ id: "comisiones", label: "Comisiones", icon: "credit_card" },
{ id: "curacion", label: "Curación", icon: "favorite" },
{ id: "sellers", label: "Sellers", icon: "storefront" },
];
const AllenOpsPage = ({ onNav }) => {
const [tab, setTab] = useOpsState("dashboard");
return (
{/* Internal banner */}
Allen Ops · Herramienta interna · No compartir con sellers ni clientes
Sesión: ana.ruiz@allenmx.com · Admin · Vallarta HQ
{/* SIDEBAR */}
{/* CONTENT */}
{tab === "dashboard" && }
{tab === "aprobaciones" && }
{tab === "disputas" && }
{tab === "comisiones" && }
{tab === "curacion" && }
{tab === "sellers" && }
);
};
// ===== DASHBOARD =====
const OpsDashboard = ({ onTab }) => (
Operaciones
Estado del marketplace · últimos 7 días
{/* Pending action queues */}
Tu cola
onTab("aprobaciones")} />
onTab("disputas")} />
onTab("comisiones")} />
{/* KPI strip */}
{/* Marketplace health */}
Salud del marketplace
{[
{ k: "Pedidos entregados a tiempo", v: 96.4, target: 95, unit: "%" },
{ k: "Cumplimiento de SLA disputas (24h)", v: 87, target: 90, unit: "%" },
{ k: "Tasa de cancelación por seller", v: 2.1, target: 3, unit: "%", lowerBetter: true },
{ k: "Sellers con stock 0", v: 4, target: 8, unit: "%", lowerBetter: true },
].map(m => {
const good = m.lowerBetter ? m.v <= m.target : m.v >= m.target;
return (
);
})}
Top sellers por GMV
{[
{ name: "Ferretería El Tornillo", gmv: 184500, n: 142 },
{ name: "Cremas L'Oréal MX", gmv: 156200, n: 98 },
{ name: "Hogar Vallarta", gmv: 128900, n: 76 },
{ name: "Sony Store PV", gmv: 112400, n: 54 },
{ name: "Adidas Outlet", gmv: 98800, n: 71 },
].map((s, i) => (
{i + 1}
${(s.gmv / 1000).toFixed(0)}K
))}
);
const QueueCard = ({ count, label, sub, tone, onClick }) => {
const tones = {
warning: { bg: "var(--warning-bg)", fg: "var(--warning)" },
error: { bg: "var(--error-bg)", fg: "var(--error)" },
primary: { bg: "var(--primary-soft)", fg: "var(--primary-press)" },
};
const c = tones[tone];
return (
);
};
const OpsKpi = ({ label, value, delta, up }) => (
{label}
{value}
↑ {delta}
);
// ===== APPROVALS (KYC) =====
const OpsApprovals = () => {
const [selected, setSelected] = useOpsState("k1");
const list = [
{ id: "k1", name: "Hogar Vallarta", who: "Diana Ruiz", since: "hace 14 h", risk: "low", rfc: "HVA920310G47" },
{ id: "k2", name: "TechZone MX", who: "Pablo Cárdenas", since: "hace 22 h", risk: "medium", rfc: "TZM010415AB1", flag: "RFC inactivo en SAT" },
{ id: "k3", name: "Boutique Daniela", who: "Daniela Pérez", since: "hace 26 h", risk: "low", rfc: "BUD850612QR8" },
{ id: "k4", name: "Pinturas El Pintor", who: "Mario González", since: "hace 36 h", risk: "high", rfc: "PIN700125XY3", flag: "Documentos ilegibles · CLABE no validada" },
];
const cur = list.find(k => k.id === selected) || list[0];
const toast = useToast();
return (
Aprobaciones KYC
{list.length} sellers esperan revisión · SLA 24 h
{/* Queue */}
{list.map((k, i) => (
))}
{/* Detail */}
{cur.name}
Representante: {cur.who}
toast(`${cur.name} aprobado`)}>Aprobar y activar
{cur.flag && (
)}
Documentos
{["CSF", "Comprobante", "Estado cta.", "Acta"].map(d => (
))}
);
};
const RiskBadge = ({ risk }) => {
const cfg = { low: { l: "Riesgo bajo", fg: "var(--success)", bg: "var(--success-bg)" }, medium: { l: "Riesgo medio", fg: "#8A6500", bg: "var(--warning-bg)" }, high: { l: "Riesgo alto", fg: "var(--error)", bg: "var(--error-bg)" } }[risk];
return {cfg.l};
};
const KvBlock = ({ title, rows }) => (
{title}
{rows.map(([k, v]) => (
{k}
{v}
))}
);
// ===== DISPUTES =====
const OpsDisputes = () => {
const [filter, setFilter] = useOpsState("all");
const list = [
{ id: "D-2840", order: "AL-712840", buyer: "Lucía Pérez", seller: "TechZone MX", amount: 1499, reason: "Producto no recibido", priority: "high", age: "hace 6 h", state: "Buyer abrió disputa" },
{ id: "D-2839", order: "AL-712830", buyer: "Carlos Rojas", seller: "Adidas Outlet", amount: 1899, reason: "Talla equivocada", priority: "medium", age: "hace 18 h", state: "Esperando seller" },
{ id: "D-2838", order: "AL-712820", buyer: "María García", seller: "Hogar Vallarta", amount: 879, reason: "Producto dañado", priority: "high", age: "hace 22 h", state: "Reembolso ofrecido" },
{ id: "D-2837", order: "AL-712802", buyer: "Sofía Luna", seller: "Cremas L'Oréal MX", amount: 459, reason: "Producto falsificado", priority: "high", age: "hace 1 d", state: "Investigación interna" },
{ id: "D-2836", order: "AL-712790", buyer: "Andrés Mata", seller: "Sony Store PV", amount: 4299, reason: "Cargo duplicado", priority: "medium", age: "hace 1 d", state: "Reembolso parcial" },
{ id: "D-2835", order: "AL-712779", buyer: "Bau Andalón", seller: "Ferretería Tornillo", amount: 549, reason: "No corresponde", priority: "low", age: "hace 2 d", state: "Esperando buyer" },
];
const filtered = filter === "all" ? list : list.filter(d => d.priority === filter);
return (
Disputas
{[{ id: "all", l: "Todas" }, { id: "high", l: "Críticas" }, { id: "medium", l: "Estándar" }, { id: "low", l: "Bajas" }].map(f => (
))}
{filtered.length} disputas · ordenadas por urgencia
| Disputa | Pedido | Buyer / Seller | Motivo | Monto | Estado | |
{filtered.map((d, i) => (
|
{d.priority === "high" && }
{d.priority === "medium" && }
{d.priority === "low" && }
{d.id}
{d.age}
|
{d.order} |
{d.buyer}
vs. {d.seller}
|
{d.reason} |
${d.amount.toLocaleString("es-MX")} |
{d.state}
|
|
))}
);
};
// ===== COMMISSIONS =====
const OpsCommissions = () => {
const toast = useToast();
return (
Comisiones
Tabla base + overrides por seller o categoría
{/* Base table */}
Tabla base por categoría
| Categoría | Comisión Allen | Procesamiento pago | Total seller paga | Tasa promedio realizada |
{[
["Electrónica", "8.5%", 4.2, 98 ],
["Hogar", "10.0%", 4.5, 165 ],
["Belleza", "12.5%", 5.1, 92 ],
["Moda", "11.0%", 4.8, 76 ],
["Deportes", "9.0%", 4.3, 54 ],
["Herramientas", "8.0%", 4.0, 23 ],
].map(([cat, pct, totalPct, sellers], i) => (
| {cat} |
{pct} |
2.9% + $4 |
{totalPct}% |
{sellers} sellers |
))}
{/* Overrides */}
Overrides activos (4)
Nuevo override
{[
{ seller: "Ferretería El Tornillo", reason: "Top seller · pricing match", base: "8.0%", override: "6.5%", until: "30 jun 2026" },
{ seller: "Cremas L'Oréal MX", reason: "Acuerdo marca", base: "12.5%", override: "9.0%", until: "31 dic 2026" },
{ seller: "Sony Store PV", reason: "Lanzamiento Q1", base: "8.5%", override: "7.0%", until: "15 abr 2026" },
{ seller: "Hogar Vallarta", reason: "Promoción Mes del Hogar", base: "10.0%", override: "8.5%", until: "31 mar 2026" },
].map((o, i) => (
{o.base}
→
{o.override}
Vence {o.until}
))}
);
};
// ===== CURATION =====
const OpsCuration = () => {
const toast = useToast();
return (
Curación
Edita "Lo más nuevo", "Ofertas" y "Marcas destacadas" del home
{/* Slot: Lo más nuevo */}
Lo más nuevo
4 slots · próxima publicación: lunes 10:00
toast("Cambios publicados al home")}>Publicar
{CATALOG.slice(0, 4).map((p, i) => (
{i + 1}
{p.name}
))}
{/* Slot: Ofertas */}
Ofertas
Auto: top 12 productos con descuento ≥20% · {CATALOG.filter(p => p.discount >= 20).length} elegibles
toast("Modo automático actualizado")} />
Modo automático activo. Para curar manualmente, apaga el toggle.
{/* Featured brands */}
Marcas destacadas
{BRANDS.map((b, i) => (
{i + 1}
{b.name}
))}
);
};
const Switch = ({ on, onChange }) => (
);
// ===== SELLERS =====
const OpsSellers = () => (
Sellers
284 sellers activos · 7 pendientes
| Seller | Categoría | GMV 30d | Pedidos | Tasa cancel. | Rating | Estado |
{[
{ n: "Ferretería El Tornillo", c: "Herramientas", g: 184500, o: 142, x: 1.2, r: 4.8, s: "active" },
{ n: "Cremas L'Oréal MX", c: "Belleza", g: 156200, o: 98, x: 0.8, r: 4.9, s: "active" },
{ n: "Hogar Vallarta", c: "Hogar", g: 128900, o: 76, x: 2.1, r: 4.7, s: "active" },
{ n: "Sony Store PV", c: "Electrónica", g: 112400, o: 54, x: 1.5, r: 4.8, s: "active" },
{ n: "Adidas Outlet", c: "Deportes", g: 98800, o: 71, x: 3.4, r: 4.5, s: "warning" },
{ n: "TechZone MX", c: "Electrónica", g: 76300, o: 42, x: 5.8, r: 4.2, s: "warning" },
{ n: "Boutique Daniela", c: "Moda", g: 54100, o: 38, x: 1.8, r: 4.6, s: "review" },
].map((s, i, a) => (
{s.n.split(/\s+/).map(w => w[0]).slice(0, 2).join("")}
{s.n}
|
{s.c} |
${(s.g / 1000).toFixed(0)}K |
{s.o} |
5 ? "var(--error)" : s.x > 3 ? "var(--warning)" : "var(--success)", fontWeight: 600 }}>{s.x}% |
★ {s.r} |
{s.s === "active" && Activo}
{s.s === "warning" && Vigilado}
{s.s === "review" && En revisión}
|
))}
);
const Th = ({ children, align = "left" }) => (
{children} |
);
const Td = ({ children, align = "left", style }) => (
{children} |
);
window.AllenOpsPage = AllenOpsPage;