"use client"; import { useEffect, useMemo, useState } from "react"; import { browserFetch } from "../lib/api"; import { logoutByNavigation } from "../lib/logout"; export type AdminSection = | "overview" | "queue" | "clients" | "makers" | "internal-users" | "reviews" | "incidents" | "reports" | "fraud" | "appeals" | "subscriptions" | "payments" | "billing" | "promotions" | "founders" | "works" | "showcases" | "services" | "reported-media" | "catalog-services" | "categories" | "materials" | "technologies" | "specialties" | "locations" | "tickets" | "conversations" | "help-center" | "analytics-product" | "analytics-makers" | "analytics-clients" | "analytics-trust" | "analytics-business" | "roles" | "settings" | "integrations" | "templates" | "audit" | "system"; type AdminClientProps = { section?: AdminSection; }; type AdminQueueItem = { id: string; kind: string; user: string; state: string; owner: string; wait: string; priority: "critical" | "high" | "normal" | "low"; }; type AdminAction = { title: string; detail: string; tone?: "primary" | "success" | "warning" | "danger"; }; function toText(value: unknown, fallback = "") { return typeof value === "string" && value ? value : fallback; } function toNumber(value: unknown, fallback = 0) { return typeof value === "number" && Number.isFinite(value) ? value : fallback; } const adminCopy: Record = { overview: { eyebrow: "Backoffice", title: "Operacion, confianza y riesgo en una sola vista", description: "Entrada diaria para administradores generales, moderacion y soporte." }, queue: { eyebrow: "Trabajo pendiente", title: "Colas operativas priorizadas", description: "Todo caso sensible entra por una cola con responsable, prioridad y trazabilidad." }, clients: { eyebrow: "Usuarios", title: "Clientes y actividad de demanda", description: "Supervisa busquedas, consultas, favoritos e historial de confianza del cliente." }, makers: { eyebrow: "Usuarios", title: "Makers, publicacion y presencia", description: "Revisa perfiles, estado comercial, riesgo y acciones administrativas seguras." }, "internal-users": { eyebrow: "Usuarios internos", title: "Administradores, moderadores y soporte", description: "Control de permisos internos sin abrir el backoffice a clientes ni makers." }, reviews: { eyebrow: "Confianza", title: "Resenas, reputacion y revision manual", description: "Las opiniones reportadas se revisan con contexto y evidencia." }, incidents: { eyebrow: "Confianza", title: "Incidencias entre cliente y maker", description: "Mediacion operativa para problemas de calidad, entrega o comunicacion." }, reports: { eyebrow: "Confianza", title: "Reportes de contenido y comportamiento", description: "Entrada rapida para denuncias, contenido inapropiado o riesgo reputacional." }, fraud: { eyebrow: "Confianza", title: "Prevencion de fraude", description: "Senales, bloqueos y acciones preventivas para proteger la plataforma." }, appeals: { eyebrow: "Confianza", title: "Apelaciones y reconsideraciones", description: "Revision secundaria cuando un maker o cliente cuestiona una decision." }, subscriptions: { eyebrow: "Negocio", title: "Suscripciones del Plan Maker", description: "Estado de planes, renovaciones, suspensiones y reactivaciones." }, payments: { eyebrow: "Negocio", title: "Pagos en riesgo y recuperacion", description: "Seguimiento de cobros fallidos, gracia y acciones de retencion." }, billing: { eyebrow: "Negocio", title: "Facturacion y comprobantes", description: "Eventos de facturacion, facturas y datos fiscales de cada maker." }, promotions: { eyebrow: "Negocio", title: "Promociones y visibilidad", description: "Herramientas para impulsar perfiles sin alterar el ranking organico." }, founders: { eyebrow: "Negocio", title: "Makers fundadores", description: "Beneficios especiales para los primeros makers de la plataforma." }, works: { eyebrow: "Contenido", title: "Trabajos publicados y borradores", description: "Revision de portafolios, calidad visual y piezas reportadas." }, showcases: { eyebrow: "Contenido", title: "Escaparates y colecciones", description: "Control de colecciones publicas, orden y destacadas." }, services: { eyebrow: "Contenido", title: "Servicios y precios", description: "Auditoria de capacidades, precios orientativos y condiciones visibles." }, "reported-media": { eyebrow: "Contenido", title: "Multimedia reportada", description: "Fotos, videos o archivos revisados antes de afectar la reputacion." }, "catalog-services": { eyebrow: "Catalogos", title: "Catalogo de servicios", description: "Categorias base para que los makers configuren su oferta." }, categories: { eyebrow: "Catalogos", title: "Categorias publicas", description: "Taxonomia de descubrimiento, filtros y escaparates." }, materials: { eyebrow: "Catalogos", title: "Materiales", description: "Materiales admitidos, aliases y filtros de busqueda." }, technologies: { eyebrow: "Catalogos", title: "Tecnologias", description: "FDM, resina, CAD, escaneo y capacidades futuras." }, specialties: { eyebrow: "Catalogos", title: "Especialidades", description: "Areas de enfoque para ranking, recomendaciones y perfil publico." }, locations: { eyebrow: "Catalogos", title: "Ubicaciones y cobertura", description: "Privacidad, cobertura y geocodificacion usada en los mapas." }, tickets: { eyebrow: "Soporte", title: "Tickets sin asignar y SLA", description: "Soporte operativo separado de conversaciones cliente-maker." }, conversations: { eyebrow: "Soporte", title: "Conversaciones escaladas", description: "Acceso administrativo solo cuando hay incidencia, reporte o auditoria." }, "help-center": { eyebrow: "Soporte", title: "Centro de ayuda", description: "Articulos, plantillas y respuestas sugeridas para reducir tickets." }, "analytics-product": { eyebrow: "Analitica", title: "Producto y embudo", description: "Busqueda, descubrimiento, consulta guiada y conversion." }, "analytics-makers": { eyebrow: "Analitica", title: "Rendimiento de makers", description: "Oferta, respuesta, reputacion y crecimiento de perfiles." }, "analytics-clients": { eyebrow: "Analitica", title: "Comportamiento de clientes", description: "Demanda, filtros, favoritos, contactos y recurrencia." }, "analytics-trust": { eyebrow: "Analitica", title: "Confianza y seguridad", description: "Incidencias, resenas, reportes y tiempos de resolucion." }, "analytics-business": { eyebrow: "Analitica", title: "Negocio", description: "Planes, pagos, cohortes y senales de retencion." }, roles: { eyebrow: "Sistema", title: "Roles y permisos", description: "Acceso exclusivo de admin con modos internos de moderador y soporte." }, settings: { eyebrow: "Sistema", title: "Configuracion operativa", description: "Parametros seguros para operar el MVP sin tocar codigo cada vez." }, integrations: { eyebrow: "Sistema", title: "Integraciones", description: "Servicios externos: mapas, email, imagenes, pagos y notificaciones." }, templates: { eyebrow: "Sistema", title: "Plantillas", description: "Mensajes, decisiones, soporte y respuestas reutilizables." }, audit: { eyebrow: "Sistema", title: "Auditoria y evidencia", description: "Registro de acciones sensibles, decisiones y accesos recientes." }, system: { eyebrow: "Sistema", title: "Estado operativo", description: "Salud de servicios, degradaciones y problemas conocidos." } }; const adminNavGroups: Array<{ label: string; items: Array<{ href: string; label: string; section: AdminSection; badge?: string }>; }> = [ { label: "Principal", items: [ { href: "/app/backoffice", label: "Inicio", section: "overview" }, { href: "/app/backoffice/queue", label: "Trabajo pendiente", section: "queue", badge: "12" } ] }, { label: "Usuarios", items: [ { href: "/app/backoffice/clients", label: "Clientes", section: "clients" }, { href: "/app/backoffice/makers", label: "Makers", section: "makers" }, { href: "/app/backoffice/internal-users", label: "Usuarios internos", section: "internal-users" } ] }, { label: "Confianza", items: [ { href: "/app/backoffice/reviews", label: "Resenas", section: "reviews", badge: "8" }, { href: "/app/backoffice/incidents", label: "Incidencias", section: "incidents", badge: "3" }, { href: "/app/backoffice/reports", label: "Reportes", section: "reports" }, { href: "/app/backoffice/fraud", label: "Fraude", section: "fraud" }, { href: "/app/backoffice/appeals", label: "Apelaciones", section: "appeals" } ] }, { label: "Negocio", items: [ { href: "/app/backoffice/subscriptions", label: "Suscripciones", section: "subscriptions", badge: "5" }, { href: "/app/backoffice/payments", label: "Pagos", section: "payments" }, { href: "/app/backoffice/billing", label: "Facturacion", section: "billing" }, { href: "/app/backoffice/promotions", label: "Promociones", section: "promotions" }, { href: "/app/backoffice/founders", label: "Makers fundadores", section: "founders" } ] }, { label: "Contenido", items: [ { href: "/app/backoffice/works", label: "Trabajos", section: "works" }, { href: "/app/backoffice/showcases", label: "Escaparates", section: "showcases" }, { href: "/app/backoffice/services", label: "Servicios", section: "services" }, { href: "/app/backoffice/reported-media", label: "Multimedia reportada", section: "reported-media" } ] }, { label: "Catalogos", items: [ { href: "/app/backoffice/catalog-services", label: "Servicios", section: "catalog-services" }, { href: "/app/backoffice/categories", label: "Categorias", section: "categories" }, { href: "/app/backoffice/materials", label: "Materiales", section: "materials" }, { href: "/app/backoffice/technologies", label: "Tecnologias", section: "technologies" }, { href: "/app/backoffice/specialties", label: "Especialidades", section: "specialties" }, { href: "/app/backoffice/locations", label: "Ubicaciones", section: "locations" } ] }, { label: "Soporte", items: [ { href: "/app/backoffice/tickets", label: "Tickets", section: "tickets", badge: "8" }, { href: "/app/backoffice/conversations", label: "Conversaciones", section: "conversations" }, { href: "/app/backoffice/help-center", label: "Centro de ayuda", section: "help-center" } ] }, { label: "Analitica", items: [ { href: "/app/backoffice/analytics-product", label: "Producto", section: "analytics-product" }, { href: "/app/backoffice/analytics-makers", label: "Makers", section: "analytics-makers" }, { href: "/app/backoffice/analytics-clients", label: "Clientes", section: "analytics-clients" }, { href: "/app/backoffice/analytics-trust", label: "Confianza", section: "analytics-trust" }, { href: "/app/backoffice/analytics-business", label: "Negocio", section: "analytics-business" } ] }, { label: "Sistema", items: [ { href: "/app/backoffice/roles", label: "Roles y permisos", section: "roles" }, { href: "/app/backoffice/settings", label: "Configuracion", section: "settings" }, { href: "/app/backoffice/integrations", label: "Integraciones", section: "integrations" }, { href: "/app/backoffice/templates", label: "Plantillas", section: "templates" }, { href: "/app/backoffice/audit", label: "Auditoria", section: "audit" }, { href: "/app/backoffice/system", label: "Estado operativo", section: "system" } ] } ]; const queueSeed: AdminQueueItem[] = [ { id: "#R-832", kind: "Resena", user: "Juan P.", state: "En analisis", owner: "Maria Lopez", wait: "34 min", priority: "critical" }, { id: "#I-048", kind: "Incidencia", user: "MakerLab 3D", state: "Nuevo", owner: "Sin asignar", wait: "2 h", priority: "high" }, { id: "#R-831", kind: "Resena", user: "Ana G.", state: "Asignado", owner: "Maria Lopez", wait: "3 h", priority: "high" }, { id: "#T-184", kind: "Ticket", user: "Juan P.", state: "Esperando usuario", owner: "Pablo Dibene", wait: "1 dia", priority: "normal" }, { id: "#T-182", kind: "Ticket", user: "Carlos R.", state: "Nuevo", owner: "Sin asignar", wait: "1 dia", priority: "normal" } ]; const systemHealthRows = [ ["API", "Operativa", "success"], ["Base de datos", "Operativa", "success"], ["Imagenes", "Operativa", "success"], ["Emails", "Degradado", "warning"], ["Notificaciones", "Operativa", "success"], ["Pagos", "Operativa", "success"], ["Mapas / Geocodificacion", "Operativa", "success"], ["Tareas en cola", "Operativa", "success"] ]; const platformRows = [ ["42", "Nuevas consultas", "+18%", "success"], ["18", "Nuevos makers", "+12%", "success"], ["7", "Perfiles publicados", "+8%", "success"], ["3", "Cancelaciones de suscripcion", "-3%", "danger"], ["96,4%", "Servicios operativos", "+0,2%", "success"] ]; const workRows = [ ["Ticket #184", "Problema de acceso", "ALTA", "Hace 5 min"], ["Resena #832", "Posible chantaje", "CRITICA", "Hace 1 h"], ["Incidencia #48", "Calidad del trabajo", "ALTA", "Hace 2 h"], ["Reporte #67", "Contenido inapropiado", "NORMAL", "Hace 3 h"] ]; const paymentHistory = [ ["10 jul, 2026", "Renovacion", "$19.990", "Pagado"], ["8 jul, 2026", "Intento de cobro", "$19.990", "Fallido"], ["7 jul, 2026", "Intento de cobro", "$19.990", "Fallido"], ["10 jun, 2026", "Renovacion", "$19.990", "Pagado"], ["10 may, 2026", "Renovacion", "$19.990", "Pagado"] ]; const sectionActions: Record = { overview: [ { title: "Priorizar cola", detail: "Ordena pendientes por SLA, riesgo y antiguedad.", tone: "primary" }, { title: "Revisar sistema", detail: "Abre servicios degradados y problemas conocidos.", tone: "success" } ], queue: [ { title: "Asignar responsable", detail: "Mueve el caso a mi cola y registra auditoria.", tone: "primary" }, { title: "Escalar prioridad", detail: "Marca el caso como critico para revision inmediata.", tone: "danger" } ], clients: [ { title: "Ver actividad", detail: "Consultas, favoritos, reportes y resenas del cliente.", tone: "primary" }, { title: "Bloquear contacto", detail: "Evita nuevas interacciones si hay riesgo.", tone: "warning" } ], makers: [ { title: "Ver ficha completa", detail: "Perfil, trabajos, consultas, reputacion y plan.", tone: "primary" }, { title: "Suspender perfil", detail: "Accion real: cambia el estado del maker.", tone: "danger" } ], "internal-users": [ { title: "Crear moderador", detail: "Permisos limitados a confianza y soporte.", tone: "primary" }, { title: "Revisar sesiones", detail: "Audita accesos recientes del equipo.", tone: "warning" } ], reviews: [ { title: "Mantener resena", detail: "La opinion queda publica y se notifica al maker.", tone: "success" }, { title: "Solicitar edicion", detail: "Pide corregir datos personales o lenguaje.", tone: "warning" }, { title: "Invalidar resena", detail: "Oculta la resena por politica.", tone: "danger" } ], incidents: [ { title: "Solicitar informacion", detail: "Pide evidencia al cliente o maker.", tone: "primary" }, { title: "Resolver incidencia", detail: "Cierra el caso con resolucion registrada.", tone: "success" } ], reports: [ { title: "Validar reporte", detail: "Confirma que incumple una politica.", tone: "warning" }, { title: "Descartar reporte", detail: "Mantiene el contenido visible.", tone: "success" } ], fraud: [ { title: "Congelar cuenta", detail: "Bloqueo preventivo hasta revision manual.", tone: "danger" }, { title: "Marcar falso positivo", detail: "Libera la cuenta y aprende del caso.", tone: "success" } ], appeals: [ { title: "Aceptar apelacion", detail: "Revierte una decision con motivo.", tone: "success" }, { title: "Mantener decision", detail: "Conserva la sancion y deja evidencia.", tone: "warning" } ], subscriptions: [ { title: "Extender gracia", detail: "Evita suspender perfil por un pago puntual.", tone: "warning" }, { title: "Reactivar perfil", detail: "Publica de nuevo al resolver el pago.", tone: "success" } ], payments: [ { title: "Reintentar cobro", detail: "Dispara reintento controlado del plan.", tone: "primary" }, { title: "Aplicar credito", detail: "Compensa un problema operativo.", tone: "warning" } ], billing: [ { title: "Ver factura", detail: "Consulta comprobantes y estado fiscal.", tone: "primary" }, { title: "Actualizar datos", detail: "Deriva al flujo validado de facturacion.", tone: "warning" } ], promotions: [ { title: "Crear promocion", detail: "Boost temporal identificado como promocionado.", tone: "primary" }, { title: "Pausar campana", detail: "Detiene promocion sin afectar perfil.", tone: "warning" } ], founders: [ { title: "Otorgar fundador", detail: "Aplica beneficio especial por tiempo limitado.", tone: "success" }, { title: "Revisar vigencia", detail: "Controla fecha y condiciones del beneficio.", tone: "warning" } ], works: [ { title: "Revisar trabajo", detail: "Calidad visual, categoria, fotos y reportes.", tone: "primary" }, { title: "Ocultar trabajo", detail: "Retira contenido sin borrar evidencia.", tone: "danger" } ], showcases: [ { title: "Ver escaparate", detail: "Controla coleccion, portada y orden.", tone: "primary" }, { title: "Ocultar escaparate", detail: "No aparece publicamente hasta corregir.", tone: "warning" } ], services: [ { title: "Auditar servicio", detail: "Revisa capacidades, precio y condiciones.", tone: "primary" }, { title: "Pausar servicio", detail: "Evita consultas mal calificadas.", tone: "warning" } ], "reported-media": [ { title: "Aprobar imagen", detail: "Mantiene multimedia visible.", tone: "success" }, { title: "Retirar imagen", detail: "Oculta y registra motivo.", tone: "danger" } ], "catalog-services": [ { title: "Agregar servicio", detail: "Nueva opcion para configuracion maker.", tone: "primary" }, { title: "Fusionar duplicados", detail: "Reduce ruido en filtros.", tone: "warning" } ], categories: [ { title: "Crear categoria", detail: "Aparece en busqueda y escaparates.", tone: "primary" }, { title: "Reordenar", detail: "Prioriza categorias de mayor demanda.", tone: "warning" } ], materials: [ { title: "Agregar material", detail: "Disponible en servicios, trabajos y filtros.", tone: "primary" }, { title: "Ocultar material", detail: "Evita seleccion publica sin borrarlo.", tone: "warning" } ], technologies: [ { title: "Agregar tecnologia", detail: "Activa una capacidad nueva.", tone: "primary" }, { title: "Marcar experimental", detail: "Visible solo para pruebas internas.", tone: "warning" } ], specialties: [ { title: "Editar especialidad", detail: "Ajusta etiquetas recomendadas.", tone: "primary" }, { title: "Medir demanda", detail: "Muestra busquedas relacionadas.", tone: "success" } ], locations: [ { title: "Validar geocodificacion", detail: "Revisa coordenadas y privacidad.", tone: "primary" }, { title: "Crear alerta", detail: "Notifica cuando haya oferta compatible.", tone: "success" } ], tickets: [ { title: "Asignar ticket", detail: "Pasa a un agente de soporte.", tone: "primary" }, { title: "Responder con plantilla", detail: "Usa respuesta sugerida.", tone: "success" } ], conversations: [ { title: "Ver contexto", detail: "Muestra consulta, acuerdo y evidencias.", tone: "primary" }, { title: "Registrar decision", detail: "Audita intervencion administrativa.", tone: "warning" } ], "help-center": [ { title: "Crear articulo", detail: "Reduce tickets repetitivos.", tone: "primary" }, { title: "Publicar plantilla", detail: "Respuesta reusable para soporte.", tone: "success" } ], "analytics-product": [ { title: "Exportar embudo", detail: "Busqueda a consulta y consulta a acuerdo.", tone: "primary" }, { title: "Crear alerta", detail: "Notifica caidas relevantes.", tone: "warning" } ], "analytics-makers": [ { title: "Ver ranking", detail: "Oferta, respuesta y conversion.", tone: "primary" }, { title: "Detectar baja calidad", detail: "Senales preventivas por perfil.", tone: "warning" } ], "analytics-clients": [ { title: "Segmentar demanda", detail: "Necesidades frecuentes por zona.", tone: "primary" }, { title: "Revisar retencion", detail: "Clientes que vuelven a consultar.", tone: "success" } ], "analytics-trust": [ { title: "Abrir riesgo", detail: "Incidencias por severidad.", tone: "danger" }, { title: "Medir resolucion", detail: "Tiempo medio por tipo de caso.", tone: "success" } ], "analytics-business": [ { title: "Ver MRR demo", detail: "Planes activos y pagos en riesgo.", tone: "primary" }, { title: "Cohortes", detail: "Retencion de makers por mes.", tone: "success" } ], roles: [ { title: "Crear rol interno", detail: "Define permisos de soporte o moderacion.", tone: "primary" }, { title: "Revocar acceso", detail: "Cierra sesiones y registra auditoria.", tone: "danger" } ], settings: [ { title: "Editar parametros", detail: "Cambios seguros sin redeploy.", tone: "primary" }, { title: "Restaurar defaults", detail: "Vuelve a configuracion MVP.", tone: "warning" } ], integrations: [ { title: "Probar servicio", detail: "Verifica mapas, email, pagos o imagenes.", tone: "primary" }, { title: "Marcar degradado", detail: "Activa aviso interno.", tone: "warning" } ], templates: [ { title: "Editar plantilla", detail: "Mensajes de soporte y moderacion.", tone: "primary" }, { title: "Publicar version", detail: "Disponible para todo el equipo.", tone: "success" } ], audit: [ { title: "Filtrar eventos", detail: "Busca por actor, recurso o decision.", tone: "primary" }, { title: "Exportar evidencia", detail: "Paquete para revision interna.", tone: "warning" } ], system: [ { title: "Ver detalles tecnicos", detail: "Estado por servicio y cola.", tone: "primary" }, { title: "Crear incidente interno", detail: "Abre seguimiento de degradacion.", tone: "danger" } ] }; export default function AdminClient({ section = "overview" }: AdminClientProps) { const [overview, setOverview] = useState<{ stats: Record } | null>(null); const [makers, setMakers] = useState>>([]); const [cases, setCases] = useState>>([]); const [error, setError] = useState(""); const [adminSearch, setAdminSearch] = useState(""); const [queueTab, setQueueTab] = useState<"mine" | "unassigned" | "high" | "all">("mine"); const [selectedMakerId, setSelectedMakerId] = useState(""); const [selectedCaseId, setSelectedCaseId] = useState(""); const [actionLog, setActionLog] = useState([]); const [caseState, setCaseState] = useState("En mediacion"); const [caseOwner, setCaseOwner] = useState("Maria Lopez"); const [reviewDecision, setReviewDecision] = useState("Invalidar resena"); async function loadAll() { try { const [overviewData, makersData, casesData] = await Promise.all([ browserFetch<{ stats: Record }>("/admin/overview"), browserFetch<{ makers: Array> }>("/admin/makers"), browserFetch<{ cases: Array> }>("/admin/cases") ]); setOverview(overviewData); setMakers(makersData.makers); setCases(casesData.cases); setSelectedMakerId((current) => current || String(makersData.makers[0]?.id || "")); setSelectedCaseId((current) => current || String(casesData.cases[0]?.id || queueSeed[1].id)); } catch (loadError) { setError(loadError instanceof Error ? loadError.message : "No se pudo cargar admin"); } } useEffect(() => { void loadAll(); }, []); function recordAction(message: string) { setActionLog((current) => [`${new Date().toLocaleTimeString("es-AR", { hour: "2-digit", minute: "2-digit" })} - ${message}`, ...current].slice(0, 8)); } async function suspendMaker(id: string) { try { await browserFetch(`/admin/makers/${id}/suspend`, { method: "POST" }); recordAction("Maker suspendido y registrado en auditoria."); await loadAll(); } catch (actionError) { setError(actionError instanceof Error ? actionError.message : "No se pudo suspender"); } } function logout() { logoutByNavigation(); } const search = adminSearch.trim().toLowerCase(); const filteredMakers = useMemo(() => { if (!search) { return makers; } return makers.filter((maker) => { const haystack = [ maker.business_name, maker.email, maker.city, maker.province, maker.status, maker.availability ].map((value) => String(value || "").toLowerCase()).join(" "); return haystack.includes(search); }); }, [makers, search]); const queueRows = useMemo(() => { const apiRows = cases.map((moderationCase, index): AdminQueueItem => ({ id: `#C-${String(moderationCase.id || index).slice(0, 4)}`, kind: toText(moderationCase.target_type, "Caso"), user: toText(moderationCase.reason, "Revision manual").slice(0, 24), state: toText(moderationCase.status, "open") === "resolved" ? "Resuelto" : "Nuevo", owner: index % 2 === 0 ? "Sin asignar" : "Maria Lopez", wait: index % 2 === 0 ? "45 min" : "2 h", priority: index % 3 === 0 ? "critical" : index % 3 === 1 ? "high" : "normal" })); const rows = [...apiRows, ...queueSeed]; if (queueTab === "mine") { return rows.filter((row) => row.owner !== "Sin asignar").slice(0, 8); } if (queueTab === "unassigned") { return rows.filter((row) => row.owner === "Sin asignar").slice(0, 8); } if (queueTab === "high") { return rows.filter((row) => row.priority === "critical" || row.priority === "high").slice(0, 8); } return rows.slice(0, 10); }, [cases, queueTab]); const selectedMaker = useMemo( () => filteredMakers.find((maker) => String(maker.id) === selectedMakerId) || filteredMakers[0] || makers[0], [filteredMakers, makers, selectedMakerId] ); const copy = adminCopy[section]; const stats = overview?.stats || {}; const activeActionLog = actionLog.length ? actionLog : [ "14:32 - Credito aplicado a MakerLab 3D.", "13:10 - Resena invalidada #R-832.", "12:45 - Sesiones revocadas a Juan P.", "11:22 - Rol asignado a Carlos R.", "10:15 - Incidencia resuelta #I-037." ]; return (
setAdminSearch(event.target.value)} placeholder="Buscar usuario, Maker, consulta, encargo, ticket..." /> Ctrl K
Sistema operativo
PD
Pablo Dibene Superadmin
{copy.title} {copy.eyebrow}
{section === "overview" ? ( ) : ( )}
); } function OverviewDashboard({ stats, makers, selectedMaker, queueRows, activeActionLog, queueTab, setQueueTab, setSelectedMakerId, selectedCaseId, setSelectedCaseId, caseState, setCaseState, caseOwner, setCaseOwner, reviewDecision, setReviewDecision, recordAction, suspendMaker }: { stats: Record; makers: Array>; selectedMaker?: Record; queueRows: AdminQueueItem[]; activeActionLog: string[]; queueTab: "mine" | "unassigned" | "high" | "all"; setQueueTab: (tab: "mine" | "unassigned" | "high" | "all") => void; setSelectedMakerId: (id: string) => void; selectedCaseId: string; setSelectedCaseId: (id: string) => void; caseState: string; setCaseState: (state: string) => void; caseOwner: string; setCaseOwner: (owner: string) => void; reviewDecision: string; setReviewDecision: (decision: string) => void; recordAction: (message: string) => void; suspendMaker: (id: string) => void; }) { return ( <>

Buenos dias, Pablo

Martes, 28 de julio de 2026

General vision total Moderador confianza Soporte tickets
{workRows.map(([title, detail, badge, time]) => ( ))}
{platformRows.map(([value, label, change, tone]) => (
{value} {label} {change}
))}
); } function SectionWorkspace({ section, copy, makers, selectedMaker, queueRows, activeActionLog, recordAction, suspendMaker }: { section: AdminSection; copy: { eyebrow: string; title: string; description: string }; makers: Array>; selectedMaker?: Record; queueRows: AdminQueueItem[]; activeActionLog: string[]; recordAction: (message: string) => void; suspendMaker: (id: string) => void; }) { const actions = sectionActions[section] || []; const catalogRows = getCatalogRows(section); return ( <>
{copy.eyebrow}

{copy.title}

{copy.description}

{actions.slice(0, 2).map((action) => ( ))}
{section === "makers" ? (
{makers.map((maker) => (
{initials(toText(maker.business_name) || toText(maker.email, "MK"))}
{toText(maker.business_name) || toText(maker.email, "Maker")} {toText(maker.city, "Cordoba")} | {translateStatus(toText(maker.status, "draft"))}
))}
) : section === "queue" || section === "incidents" || section === "tickets" || section === "reviews" ? ( recordAction(`Caso ${id} abierto desde ${copy.eyebrow}.`)} /> ) : (
{catalogRows.map((row) => ( ))}
)}
{actions.map((action) => ( ))}
{section === "makers" ? ( undefined} suspendMaker={suspendMaker} recordAction={recordAction} /> ) : section === "reviews" ? ( undefined} recordAction={recordAction} /> ) : section === "payments" || section === "subscriptions" || section === "billing" ? ( ) : section === "system" || section === "integrations" ? ( ) : (
)}
{activeActionLog.map((entry) => (

{entry}

))}
); } function KpiCard({ number, title, detail, tone }: { number: string; title: string; detail: string; tone: string }) { return (
{number}
{title} {detail}
); } function PanelHead({ title, meta }: { title: string; meta?: string }) { return (

{title}

{meta ? : null}
); } function QueueTable({ rows, selectedCaseId, onSelect }: { rows: AdminQueueItem[]; selectedCaseId: string; onSelect: (id: string) => void }) { return (
Prioridad Caso Tipo Usuario Estado Responsable Espera
{rows.map((row) => ( ))}
); } function SystemCard() { return (
{systemHealthRows.map(([label, state, tone]) => (
{label} {state}
))}
); } function MakerCard({ maker, makers, setSelectedMakerId, suspendMaker, recordAction }: { maker?: Record; makers: Array>; setSelectedMakerId: (id: string) => void; suspendMaker: (id: string) => void; recordAction: (message: string) => void; }) { const makerId = String(maker?.id || makers[0]?.id || ""); const name = toText(maker?.business_name, "MakerLab 3D"); const status = translateStatus(toText(maker?.status, "published")); return (
{initials(name)}

{name}

Plan Maker activo

{status} {translateAvailability(toText(maker?.availability, "available"))}
Reputacion 4,8 *****
Incidencias abiertas 1 Revision activa
Riesgo Bajo Sin bloqueos
); } function ReviewModerationCard({ decision, setDecision, recordAction }: { decision: string; setDecision: (decision: string) => void; recordAction: (message: string) => void; }) { return (
JP
Juan Perez Cliente verificado
Critica

"El trabajo llego mal impreso, piezas rotas y el Maker no quiere hacerse cargo. Pesima experiencia."

Decision {["Mantener resena", "Solicitar edicion", "Ocultar datos personales", "Invalidar resena", "Escalar caso"].map((item) => ( ))}