import { api } from "../lib/api.js"; import { emit, on } from "../lib/bus.js"; import { modal } from "../lib/modal.js"; class ConversationList extends HTMLElement { constructor() { super(); this.attachShadow({ mode: "open" }); this.conversations = []; this.selected = null; this.tab = "chats"; // chats | users this.users = []; this.selectedUser = null; this.shadowRoot.innerHTML = `
Chats
Usuarios
`; } connectedCallback() { this.shadowRoot.getElementById("tabChats").onclick = () => this.setTab("chats"); this.shadowRoot.getElementById("tabUsers").onclick = () => this.setTab("users"); this.shadowRoot.getElementById("q").oninput = () => { clearTimeout(this._t); this._t = setTimeout(() => this.refresh(), 250); }; this.shadowRoot.getElementById("status").onchange = () => this.refresh(); this.shadowRoot.getElementById("state").onchange = () => this.refresh(); // acciones del usuario seleccionado (solo en tab Users) this.shadowRoot.getElementById("uaSelect").onclick = () => { if (!this.selectedUser) return; emit("ui:selectedChat", { chat_id: this.selectedUser.chat_id }); this.setTab("chats"); }; this.shadowRoot.getElementById("uaDeleteConv").onclick = async () => { if (!this.selectedUser) return; const chat_id = this.selectedUser.chat_id; const confirmed = await modal.confirm(`¿Borrar conversación completa de ${chat_id}?`); if (!confirmed) return; await api.deleteConversation(chat_id); this.selectedUser = null; await this.refreshUsers(); }; this.shadowRoot.getElementById("uaDeleteUser").onclick = async () => { if (!this.selectedUser) return; const chat_id = this.selectedUser.chat_id; const confirmed = await modal.confirm(`¿Borrar usuario ${chat_id}, sus conversaciones y el customer en Woo?`); if (!confirmed) return; await api.deleteUser(chat_id, { deleteWoo: true }); this.selectedUser = null; await this.refreshUsers(); }; this._unsub1 = on("conversation:upsert", (conv) => { if (this.tab !== "chats") return; const idx = this.conversations.findIndex(x => x.chat_id === conv.chat_id); if (idx >= 0) this.conversations[idx] = conv; else this.conversations.unshift(conv); this.render(); }); this.refresh(); } disconnectedCallback() { this._unsub1?.(); } dot(status) { const cls = status === "ok" ? "ok" : (status === "warn" ? "warn" : "err"); return ``; } async refresh() { try { if (this.tab === "users") return await this.refreshUsers(); const q = this.shadowRoot.getElementById("q").value || ""; const status = this.shadowRoot.getElementById("status").value || ""; const state = this.shadowRoot.getElementById("state").value || ""; const data = await api.conversations({ q, status, state }); this.conversations = data.items || []; this.render(); } catch (e) { console.warn("[conversation-list] refresh failed", e); } } async refreshUsers() { try { const q = this.shadowRoot.getElementById("q").value || ""; const data = await api.users({ q, limit: 200 }); this.users = data.items || []; this.render(); } catch (e) { console.warn("[conversation-list] refreshUsers failed", e); } } setTab(tab) { this.tab = tab; this.shadowRoot.getElementById("tabChats").classList.toggle("active", tab === "chats"); this.shadowRoot.getElementById("tabUsers").classList.toggle("active", tab === "users"); // en users mantenemos el buscador; ocultamos filtros avanzados (status/state) this.shadowRoot.getElementById("filtersBox").style.display = "block"; const adv = this.shadowRoot.getElementById("status")?.closest(".row"); if (adv) adv.style.display = tab === "chats" ? "flex" : "none"; const qEl = this.shadowRoot.getElementById("q"); qEl.placeholder = tab === "users" ? "Buscar usuario (chat_id / pushName)…" : "Buscar chat_id / teléfono…"; // acciones visibles solo en users (si no hay selección, quedan disabled) this.renderSelectedUserActions(); this.refresh(); } renderSelectedUserActions() { const box = this.shadowRoot.getElementById("userActions"); const inUsers = this.tab === "users"; box.style.display = inUsers ? "block" : "none"; const hasSel = Boolean(this.selectedUser); const b1 = this.shadowRoot.getElementById("uaSelect"); const b2 = this.shadowRoot.getElementById("uaDeleteConv"); const b3 = this.shadowRoot.getElementById("uaDeleteUser"); if (b1) b1.disabled = !hasSel; if (b2) b2.disabled = !hasSel; if (b3) b3.disabled = !hasSel; } render() { const list = this.shadowRoot.getElementById("list"); list.innerHTML = ""; if (this.tab === "users") { // panel de acciones this.renderSelectedUserActions(); for (const u of this.users) { const el = document.createElement("div"); el.className = "item" + (this.selectedUser?.chat_id === u.chat_id ? " active" : ""); const name = u.push_name || u.chat_id.replace(/@.+$/, ""); el.innerHTML = `
${name}
${u.chat_id}
woo_customer_id: ${u.external_customer_id || "—"}
`; el.onclick = () => { this.selectedUser = u; this.render(); }; list.appendChild(el); } return; } for (const c of this.conversations) { const el = document.createElement("div"); el.className = "item" + (c.chat_id === this.selected ? " active" : ""); el.innerHTML = `
${this.dot(c.status)}
${c.from}
${c.chat_id}
state: ${c.state} intent: ${c.intent} last: ${new Date(c.last_activity).toLocaleTimeString()}
`; el.onclick = async (e) => { if (e?.target?.dataset?.del) { e.stopPropagation(); const confirmed = await modal.confirm(`¿Borrar conversación completa de ${c.chat_id}?`); if (!confirmed) return; await api.deleteConversation(c.chat_id); if (this.selected === c.chat_id) this.selected = null; await this.refresh(); return; } this.selected = c.chat_id; this.render(); emit("ui:selectedChat", { chat_id: c.chat_id }); }; list.appendChild(el); } } } customElements.define("conversation-list", ConversationList);