"use strict"; const UsersView = (function(){ const UsersView = function(judge_pole){ const self = this; let container = null; let cards_wrapper = null; let filter_query = ""; this.go = () => { judge_pole.content_area.innerHTML = ""; judge_pole.html(judge_pole.content_area, build()); }; const build = () => { const is_admin = judge_pole.session.is_admin(); const topbar_actions = [ ["input", { "type" : "search", "class" : "jp-search-input", "data-i18n" : "search_users_placeholder", "data-i18n-without" : "true", "placeholder" : judge_pole.i18n.get("search_users_placeholder"), "value" : filter_query, "oninput" : (input) => { filter_query = input.value.trim().toLowerCase(); render_cards(); } }] ]; // Sólo añadimos el botón si es admin if(is_admin){ topbar_actions.push(["button", { "type" : "button", "class" : "jp-btn-primary", "data-i18n" : "btn_new_user", "onclick" : () => show_user_modal() }, judge_pole.i18n.get("btn_new_user")]); } container = judge_pole.html(["div", { "class" : "jp-view jp-users-view" }, [ ["div", { "class" : "jp-view-topbar" }, [ ["h2", { "data-i18n" : "users_title" }, judge_pole.i18n.get("users_title")], ["div", { "style" : "display:flex; gap:0.5em; align-items:center;" }, topbar_actions] ]], cards_wrapper = judge_pole.html(["div", { "class" : "jp-cards-grid", "id" : "jp-users-cards" }])[0] ]])[0]; render_cards(); return container; }; const render_cards = () => { if(!cards_wrapper) return; cards_wrapper.innerHTML = ""; const users = judge_pole.db.get_data().users; const is_admin = judge_pole.session.is_admin(); if(!users.length){ cards_wrapper.appendChild(judge_pole.html(["p", { "class" : "jp-empty", "data-i18n" : "no_users" }, judge_pole.i18n.get("no_users")])[0]); return; } const filtered_users = users.filter(user => { if(!filter_query) return true; const match_nick = user.nick.toLowerCase().includes(filter_query); const match_desc = user.description ? user.description.toLowerCase().includes(filter_query) : false; const match_links = user.links ? user.links.some(l => l.name.toLowerCase().includes(filter_query)) : false; return match_nick || match_desc || match_links; }); if(!filtered_users.length){ cards_wrapper.appendChild(judge_pole.html(["p", { "class" : "jp-empty", "data-i18n" : "no_users_found" }, judge_pole.i18n.get("no_users_found")])[0]); return; } filtered_users.forEach(user => { const links_html = user.links.map(link => ["a", { "href" : link.url, "target" : "_blank", "class" : "jp-tag-link" }, link.name]); const is_ai = user.type === "ai"; const type_badge = ["span", { "class" : "jp-badge " + (is_ai ? "jp-badge-type-ai" : "jp-badge-type-human") }, is_ai ? "🤖 IA" : "👤 Humano"]; const avatar_element = user.avatar ? ["img", { "src" : user.avatar, "class" : "jp-avatar", "alt" : user.nick }] : ["div", { "class" : "jp-avatar-placeholder" }, (user.nick ? user.nick[0].toUpperCase() : (is_ai ? "🤖" : "👤"))]; const card_elements = []; // Botones sólo para Administradores if(is_admin){ card_elements.push(["button", { "type" : "button", "class" : "jp-card-btn-delete", "data-i18n" : "btn_delete", "data-i18n-without" : "true", "title" : judge_pole.i18n.get("btn_delete"), "onclick" : () => { const confirm_msg = judge_pole.i18n.get("confirm_delete_user", { nick : user.nick }); if(confirm(confirm_msg)){ judge_pole.db.delete_user(user.id); render_cards(); } } }, "✕"]); card_elements.push(["button", { "type" : "button", "class" : "jp-card-btn-edit", "data-i18n" : "btn_edit", "data-i18n-without" : "true", "title" : judge_pole.i18n.get("btn_edit"), "onclick" : () => show_user_modal(user.id) }, "✏️"]); } card_elements.push( avatar_element, ["div", { "style" : "display:flex; justify-content:space-between; align-items:center; margin-bottom:0.3em;" }, [ ["h3", { "style" : "margin:0;" }, user.nick], type_badge ]], ["p", { "class" : "jp-desc" }, user.description], ["div", { "class" : "jp-tags-group" }, links_html], ["div", { "class" : "jp-meta" }, [ ["small", {}, judge_pole.i18n.get("created_at") + " " + user.created_at.substring(0, 10)], ["small", {}, judge_pole.i18n.get("updated_at") + " " + user.updated_at.substring(0, 10)] ]] ); const card = judge_pole.html(["div", { "class" : "jp-card" }, card_elements])[0]; cards_wrapper.appendChild(card); }); }; const show_user_modal = (user_id = null) => { const current_user = user_id ? judge_pole.db.get_data().users.find(u => u.id === user_id) : null; let links_container = null; const add_link_row = (name = "", url = "") => { const row = judge_pole.html(["div", { "class" : "jp-link-row" }, [ ["input", { "type" : "text", "placeholder" : "Nombre (ej: GitHub)", "class" : "link-name", "value" : name }], ["input", { "type" : "url", "placeholder" : "https://...", "class" : "link-url", "value" : url }], ["button", { "type" : "button", "class" : "jp-btn-danger", "onclick" : (btn) => btn.parentNode.remove() }, "✕"] ]])[0]; links_container.appendChild(row); }; const close_modal = () => { if(modal_overlay && modal_overlay.parentNode) modal_overlay.remove(); }; const modal_title = current_user ? judge_pole.i18n.get("modal_edit_user_title", { nick : current_user.nick }) : judge_pole.i18n.get("modal_new_user_title"); const modal_overlay = judge_pole.html(["div", { "class" : "jp-modal-overlay", "onclick" : (overlay, e) => { if(e.target === overlay) close_modal(); } }, [ ["div", { "class" : "jp-modal-window" }, [ ["div", { "class" : "jp-modal-header" }, [ ["h3", {}, modal_title], ["button", { "type" : "button", "class" : "jp-btn-danger", "onclick" : () => close_modal() }, "✕"] ]], ["div", { "class" : "jp-modal-body" }] ]] ]])[0]; const modal_body = modal_overlay.querySelector(".jp-modal-body"); const form = judge_pole.html(["form", { "onsubmit" : (form_element, event) => { event.preventDefault(); const links = []; links_container.querySelectorAll(".jp-link-row").forEach(row => { const name = row.querySelector(".link-name").value.trim(); const url = row.querySelector(".link-url").value.trim(); if(name && url) links.push({ name : name, url : url }); }); const select_type = form_element.querySelector("[name='type']"); const pass_input = form_element.querySelector("[name='password']"); // <--- Extraer password const user_payload = { type : select_type ? select_type.value : "human", nick : form_element.querySelector("[name='nick']").value.trim(), password : pass_input ? pass_input.value.trim() : "", // <--- Incluir en payload description : form_element.querySelector("[name='description']").value.trim(), avatar : form_element.querySelector("[name='avatar']").value.trim(), links : links }; if(current_user) { judge_pole.db.update_user(current_user.id, user_payload); } else { judge_pole.db.add_user(user_payload); } close_modal(); judge_pole.render_header(); // <--- Forzar refresco del header por si cambió el estado de seguridad render_cards(); } }, [ ["div", { "class" : "jp-field" }, [ ["label", {"data-i18n" : "user_type"}, judge_pole.i18n.get("user_type")], ["select", { "name" : "type" }, [ ["option", { "value" : "human", "data-i18n" : "user_type_human", ...(current_user && current_user.type === "human" ? { "selected" : "selected" } : {}) }, judge_pole.i18n.get("user_type_human")], ["option", { "value" : "ai", "data-i18n" : "user_type_ai", ...(current_user && current_user.type === "ai" ? { "selected" : "selected" } : {}) }, judge_pole.i18n.get("user_type_ai")] ]] ]], ["div", { "class" : "jp-field" }, [ ["label", {"data-i18n" : "user_nick"}, judge_pole.i18n.get("user_nick")], ["input", { "type" : "text", "name" : "nick", "required" : "required", "value" : current_user ? current_user.nick : "" }] ]], ["div", { "class" : "jp-field" }, [ ["label", { "data-i18n" : "user_pass_label" }, judge_pole.i18n.get("user_pass_label")], ["input", { "type" : "password", "name" : "password", "placeholder" : judge_pole.i18n.get("user_pass_placeholder"), "value" : current_user ? (current_user.password || "") : "" }] ]], ["div", { "class" : "jp-field" }, [ ["label", {"data-i18n" : "user_avatar"}, judge_pole.i18n.get("user_avatar")], ["input", { "type" : "text", "name" : "avatar", "placeholder" : "./data/avatars/yo.png", "value" : current_user ? current_user.avatar : "" }] ]], ["div", { "class" : "jp-field" }, [ ["label", {"data-i18n" : "user_desc"}, judge_pole.i18n.get("user_desc")], ["textarea", { "name" : "description", "rows" : "3" }, current_user ? current_user.description : ""] ]], ["div", { "class" : "jp-field" }, [ ["label", {"data-i18n" : "user_links"}, judge_pole.i18n.get("user_links")], links_container = judge_pole.html(["div", { "class" : "jp-links-list" }])[0], ["button", { "type" : "button", "class" : "jp-btn-secondary", "data-i18n" : "btn_add_link", "onclick" : () => add_link_row() }, judge_pole.i18n.get("btn_add_link")] ]], ["div", { "style" : "display:flex; justify-content:flex-end; gap:0.5em; margin-top:1em;" }, [ ["button", { "type" : "button", "class" : "jp-btn", "data-i18n" : "btn_cancel_edit", "onclick" : () => close_modal() }, judge_pole.i18n.get("btn_cancel_edit")], ["button", { "type" : "submit", "class" : "jp-btn-primary", "data-i18n" : current_user ? "btn_update_user" : "btn_save_user" }, current_user ? judge_pole.i18n.get("btn_update_user") : judge_pole.i18n.get("btn_save_user") ] ]] ]])[0]; modal_body.appendChild(form); if(current_user && current_user.links && current_user.links.length) { current_user.links.forEach(link => add_link_row(link.name, link.url)); } judge_pole.item_self.appendChild(modal_overlay); }; }; return UsersView; })();