289 lines
14 KiB
JavaScript
289 lines
14 KiB
JavaScript
"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;
|
|
})(); |