(function () { const supportedLanguages = ["en", "ar", "tr", "id"]; const languageLabels = { en: "EN", ar: "AR", tr: "TR", id: "ID" }; const API_BASE_URL = "https://jvapi.haiyihy.com"; const GO_API_PATH_PREFIX = "/go"; const LOCAL_GO_API_BASE_URL = "http://127.0.0.1:1100"; const defaultPropsType = "RIDE"; const fallbackMessages = { en: { document_title: "Manager Center", page_label: "Manager Center", back: "Back", title: "Manager Center", language_button_aria: "Change language", close: "Close", current_manager: "Current Manager", user: "User", user_search_placeholder: "Enter user ID or account", search: "Search", searching: "Searching...", target_user: "Target User", gift_props: "Gift Props", gift_type: "Gift Type", prop_type_ride: "Ride", prop_type_noble_vip: "Noble VIP", prop_type_avatar_frame: "Avatar Frame", prop_type_badge: "Badge", prop_type_chat_bubble: "Chat Bubble", prop_type_data_card: "Profile Card", no_giftable_props: "No giftable props", send: "Send", sending: "Sending...", send_success: "Sent successfully", ban_user: "Ban User", ban_reason: "Ban reason", ban: "Ban", submitting: "Submitting...", ban_success: "User banned", unban_user: "Unban User", unban_reason: "Unban reason", unban: "Unban", unban_success: "User unbanned", can_unban: "Can unban", cannot_unban: "Cannot unban", loading: "Loading...", uid_label: "UID", days: "{count} days", recharged: "Recharged", not_recharged: "Not recharged", recharge_unknown: "Recharge unknown", can_ban: "Can ban", cannot_ban: "Cannot ban", missing_token: "Missing token", not_manager: "Current account is not a manager", user_not_found: "User not found", user_recharged: "This user has recharge records and cannot be banned", user_already_banned: "This user is already banned", user_not_banned: "This user is not banned", prop_not_giftable: "This prop is not available for manager gifting", vip_not_giftable: "This noble prop cannot be gifted", request_failed: "Request failed", enter_user: "Enter user ID or account" }, ar: { document_title: "مركز المدير", page_label: "مركز المدير", back: "رجوع", title: "مركز المدير", language_button_aria: "تغيير اللغة", close: "إغلاق", current_manager: "المدير الحالي", user: "المستخدم", user_search_placeholder: "أدخل معرّف المستخدم أو الحساب", search: "بحث", searching: "جار البحث...", target_user: "المستخدم المستهدف", gift_props: "إرسال العناصر", gift_type: "نوع الهدية", prop_type_ride: "مركبة", prop_type_noble_vip: "VIP نبيل", prop_type_avatar_frame: "إطار الصورة", prop_type_badge: "شارة", prop_type_chat_bubble: "فقاعة الدردشة", prop_type_data_card: "بطاقة الملف", no_giftable_props: "لا توجد عناصر قابلة للإهداء", send: "إرسال", sending: "جار الإرسال...", send_success: "تم الإرسال بنجاح", ban_user: "حظر المستخدم", ban_reason: "سبب الحظر", ban: "حظر", submitting: "جار الإرسال...", ban_success: "تم حظر المستخدم", unban_user: "إلغاء حظر المستخدم", unban_reason: "سبب إلغاء الحظر", unban: "إلغاء الحظر", unban_success: "تم إلغاء حظر المستخدم", can_unban: "يمكن إلغاء الحظر", cannot_unban: "لا يمكن إلغاء الحظر", loading: "جار التحميل...", uid_label: "UID", days: "{count} يوم", recharged: "تم الشحن", not_recharged: "لم يتم الشحن", recharge_unknown: "حالة الشحن غير معروفة", can_ban: "يمكن الحظر", cannot_ban: "لا يمكن الحظر", missing_token: "رمز الدخول مفقود", not_manager: "الحساب الحالي ليس مديرًا", user_not_found: "المستخدم غير موجود", user_recharged: "لدى هذا المستخدم سجلات شحن ولا يمكن حظره", user_already_banned: "هذا المستخدم محظور بالفعل", user_not_banned: "هذا المستخدم غير محظور", prop_not_giftable: "هذا العنصر غير متاح كهديّة من المدير", vip_not_giftable: "لا يمكن إهداء عنصر VIP هذا", request_failed: "فشل الطلب", enter_user: "أدخل معرّف المستخدم أو الحساب" }, tr: { document_title: "Yönetici Merkezi", page_label: "Yönetici Merkezi", back: "Geri", title: "Yönetici Merkezi", language_button_aria: "Dili değiştir", close: "Kapat", current_manager: "Mevcut Yönetici", user: "Kullanıcı", user_search_placeholder: "Kullanıcı ID veya hesap gir", search: "Ara", searching: "Aranıyor...", target_user: "Hedef Kullanıcı", gift_props: "Eşya Gönder", gift_type: "Hediye Türü", prop_type_ride: "Araç", prop_type_noble_vip: "Noble VIP", prop_type_avatar_frame: "Avatar Çerçevesi", prop_type_badge: "Rozet", prop_type_chat_bubble: "Sohbet Balonu", prop_type_data_card: "Profil Kartı", no_giftable_props: "Gönderilebilir eşya yok", send: "Gönder", sending: "Gönderiliyor...", send_success: "Başarıyla gönderildi", ban_user: "Kullanıcıyı Yasakla", ban_reason: "Yasaklama nedeni", ban: "Yasakla", submitting: "Gönderiliyor...", ban_success: "Kullanıcı yasaklandı", unban_user: "Yasağı Kaldır", unban_reason: "Yasağı kaldırma nedeni", unban: "Yasağı kaldır", unban_success: "Kullanıcının yasağı kaldırıldı", can_unban: "Yasak kaldırılabilir", cannot_unban: "Yasak kaldırılamaz", loading: "Yükleniyor...", uid_label: "UID", days: "{count} gün", recharged: "Yükleme yaptı", not_recharged: "Yükleme yapmadı", recharge_unknown: "Yükleme durumu bilinmiyor", can_ban: "Yasaklanabilir", cannot_ban: "Yasaklanamaz", missing_token: "Token eksik", not_manager: "Mevcut hesap yönetici değil", user_not_found: "Kullanıcı bulunamadı", user_recharged: "Bu kullanıcının yükleme kaydı var, yasaklanamaz", user_already_banned: "Bu kullanıcı zaten yasaklı", user_not_banned: "Bu kullanıcı yasaklı değil", prop_not_giftable: "Bu eşya yönetici hediyesi için açık değil", vip_not_giftable: "Bu noble eşyası gönderilemez", request_failed: "İstek başarısız", enter_user: "Kullanıcı ID veya hesap gir" }, id: { document_title: "Pusat Manajer", page_label: "Pusat Manajer", back: "Kembali", title: "Pusat Manajer", language_button_aria: "Ubah bahasa", close: "Tutup", current_manager: "Manajer Saat Ini", user: "Pengguna", user_search_placeholder: "Masukkan ID pengguna atau akun", search: "Cari", searching: "Mencari...", target_user: "Pengguna Target", gift_props: "Kirim Properti", gift_type: "Jenis Hadiah", prop_type_ride: "Kendaraan", prop_type_noble_vip: "Noble VIP", prop_type_avatar_frame: "Bingkai Avatar", prop_type_badge: "Lencana", prop_type_chat_bubble: "Gelembung Chat", prop_type_data_card: "Kartu Profil", no_giftable_props: "Tidak ada properti yang dapat dikirim", send: "Kirim", sending: "Mengirim...", send_success: "Berhasil dikirim", ban_user: "Blokir Pengguna", ban_reason: "Alasan blokir", ban: "Blokir", submitting: "Mengirim...", ban_success: "Pengguna diblokir", unban_user: "Buka Blokir Pengguna", unban_reason: "Alasan buka blokir", unban: "Buka blokir", unban_success: "Blokir pengguna dibuka", can_unban: "Dapat dibuka", cannot_unban: "Tidak dapat dibuka", loading: "Memuat...", uid_label: "UID", days: "{count} hari", recharged: "Sudah isi ulang", not_recharged: "Belum isi ulang", recharge_unknown: "Status isi ulang tidak diketahui", can_ban: "Dapat diblokir", cannot_ban: "Tidak dapat diblokir", missing_token: "Token tidak ditemukan", not_manager: "Akun saat ini bukan manajer", user_not_found: "Pengguna tidak ditemukan", user_recharged: "Pengguna ini memiliki riwayat isi ulang dan tidak dapat diblokir", user_already_banned: "Pengguna ini sudah diblokir", user_not_banned: "Pengguna ini tidak diblokir", prop_not_giftable: "Properti ini tidak tersedia untuk hadiah manajer", vip_not_giftable: "Properti noble ini tidak dapat dikirim", request_failed: "Permintaan gagal", enter_user: "Masukkan ID pengguna atau akun" } }; const state = { manager: null, target: null, propsType: defaultPropsType, props: [], selectedPropsId: "" }; const params = readURLParams(); let currentLang = normalizeLanguage(params.get("lang")); let currentMessages = fallbackMessages[currentLang] || fallbackMessages.en; function readURLParams() { const result = new URLSearchParams(window.location.search); const hashQuery = window.location.hash.includes("?") ? window.location.hash.split("?")[1] : ""; const hashParams = new URLSearchParams(hashQuery); hashParams.forEach((value, key) => { if (!result.has(key)) result.set(key, value); }); return result; } function readRawParam(name) { const queries = [window.location.search.replace(/^\?/, "")]; if (window.location.hash.includes("?")) queries.push(window.location.hash.split("?")[1]); for (const query of queries) { for (const part of query.split("&")) { if (!part) continue; const equalIndex = part.indexOf("="); const rawKey = equalIndex >= 0 ? part.slice(0, equalIndex) : part; const rawValue = equalIndex >= 0 ? part.slice(equalIndex + 1) : ""; let decodedKey = ""; try { decodedKey = decodeURIComponent(rawKey); } catch (error) { continue; } if (decodedKey !== name) continue; try { return decodeURIComponent(rawValue.replace(/\+/g, "%2B")); } catch (error) { return rawValue; } } } return ""; } function normalizeLanguage(lang) { const value = String(lang || "en").toLowerCase(); return supportedLanguages.includes(value) ? value : "en"; } async function loadMessages(lang) { const normalizedLang = normalizeLanguage(lang); if (window.location.protocol === "file:") return fallbackMessages[normalizedLang]; try { const response = await fetch(`./locales/${normalizedLang}.json?v=20260511-0107`, { cache: "no-store" }); if (response.ok) return await response.json(); } catch (error) { return fallbackMessages[normalizedLang]; } return fallbackMessages[normalizedLang]; } function localizedValue(messages, key) { return messages?.[key] || fallbackMessages[currentLang]?.[key] || fallbackMessages.en[key] || ""; } function message(key, fallback = "") { return localizedValue(currentMessages, key) || fallback || key; } function renderMessages(messages) { document.querySelectorAll("[data-i18n]").forEach((node) => { const value = localizedValue(messages, node.dataset.i18n); if (value) node.textContent = value; }); document.querySelectorAll("[data-i18n-aria]").forEach((node) => { const value = localizedValue(messages, node.dataset.i18nAria); if (value) node.setAttribute("aria-label", value); }); document.querySelectorAll("[data-i18n-placeholder]").forEach((node) => { const value = localizedValue(messages, node.dataset.i18nPlaceholder); if (value) node.setAttribute("placeholder", value); }); } function setLanguageMenuOpen(open) { const languageButton = $(".language-button"); const languageMenu = $(".language-menu"); if (!languageButton || !languageMenu) return; languageMenu.hidden = !open; languageButton.setAttribute("aria-expanded", String(open)); } function renderLanguageControls(messages) { const languageButton = $(".language-button"); if (languageButton) { languageButton.textContent = languageLabels[currentLang]; languageButton.setAttribute("aria-label", localizedValue(messages, "language_button_aria") || "Change language"); } document.querySelectorAll(".language-menu [data-lang]").forEach((button) => { const isActive = button.dataset.lang === currentLang; button.classList.toggle("is-active", isActive); button.setAttribute("aria-pressed", String(isActive)); }); } function setPropsTypeMenuOpen(open) { const root = $("#propsTypeSelect"); const button = $("#propsTypeButton"); const menu = $("#propsTypeMenu"); if (!root || !button || !menu) return; root.classList.toggle("is-open", open); menu.hidden = !open; button.setAttribute("aria-expanded", String(open)); } function renderPropsTypeSelect() { const root = $("#propsTypeSelect"); const label = $("#propsTypeSelectedLabel"); if (root) root.dataset.value = state.propsType; if (label) label.textContent = propTypeLabel(state.propsType); document.querySelectorAll("#propsTypeMenu [data-value]").forEach((button) => { const isSelected = button.dataset.value === state.propsType; button.classList.toggle("is-selected", isSelected); button.setAttribute("aria-selected", String(isSelected)); }); } async function choosePropsType(value) { const nextValue = String(value || defaultPropsType); setPropsTypeMenuOpen(false); if (nextValue === state.propsType) { renderPropsTypeSelect(); return; } state.propsType = nextValue; renderPropsTypeSelect(); try { await loadProps(); } catch (error) { setStatus($("#propsStatus"), friendlyError(error), "error"); } } async function applyLanguage(lang) { currentLang = normalizeLanguage(lang); const messages = await loadMessages(currentLang); currentMessages = messages; document.documentElement.lang = currentLang; document.documentElement.dir = currentLang === "ar" ? "rtl" : "ltr"; document.title = message("document_title", "Manager Center"); renderMessages(messages); renderLanguageControls(messages); renderPropsTypeSelect(); renderManager(state.manager); renderTarget(); renderProps(); } function $(selector) { return document.querySelector(selector); } function apiBaseURL() { const override = window.HYAPP_API_BASE_URL || params.get("apiBase"); if (override) return String(override).replace(/\/+$/, ""); return API_BASE_URL.replace(/\/+$/, ""); } function isLocalDocumentsFile() { if (window.location.protocol !== "file:") return false; let pathname = window.location.pathname || ""; try { pathname = decodeURIComponent(pathname); } catch (error) { return false; } return pathname.startsWith("/Users/hy/Documents/"); } function goApiBaseURL() { const override = window.HYAPP_GO_API_BASE_URL || params.get("goApiBase") || params.get("goBase"); if (override) return String(override).replace(/\/+$/, ""); if (isLocalDocumentsFile()) return `${LOCAL_GO_API_BASE_URL}${GO_API_PATH_PREFIX}`; return `${apiBaseURL()}${GO_API_PATH_PREFIX}`; } function buildRequestURL(baseURL, path) { const base = `${String(baseURL || API_BASE_URL).replace(/\/+$/, "")}/`; const target = String(path || "").replace(/^\/+/, ""); return new URL(target, base).toString(); } function normalizeAuthorization(token) { const value = String(token || "").trim(); if (!value) return ""; return /^bearer\s+/i.test(value) ? value : `Bearer ${value}`; } function authHeadersFromToken(token) { const sysOrigin = params.get("sysOrigin") || params.get("origin") || "ATYOU"; return { Authorization: normalizeAuthorization(token), "req-lang": currentLang, "req-client": "H5", "req-version": "V2", "req-zone": Intl.DateTimeFormat().resolvedOptions().timeZone || "Asia/Shanghai", "req-app-intel": "version=1.0.0;build=1;model=H5;sysVersion=Web;channel=Web", "req-sys-origin": `origin=${sysOrigin};originChild=${sysOrigin}` }; } async function requestGoJSON(path, options = {}) { const token = readRawParam("token"); if (!token) { const error = new Error(message("missing_token")); error.code = "missing_token"; throw error; } const headers = authHeadersFromToken(token); const request = { method: options.method || "GET", cache: "no-store", headers }; if (options.body !== undefined) { headers["Content-Type"] = "application/json"; request.body = JSON.stringify(options.body); } const response = await fetch(buildRequestURL(goApiBaseURL(), path), request); const data = await response.json().catch(() => ({})); if (!response.ok || data.status === false) { const error = new Error(data.errorMsg || data.message || `Request failed: ${response.status}`); error.code = data.code || data.errorCodeName || ""; error.response = data; throw error; } return data.body ?? data.data ?? null; } function endpointProfile() { return "/app/h5/manager-center/profile"; } function endpointSearchUser(account) { return `/app/h5/manager-center/users/search?account=${encodeURIComponent(account)}`; } function endpointProps(type) { return `/app/h5/manager-center/props?type=${encodeURIComponent(type || "")}`; } function endpointSendProps() { return "/app/h5/manager-center/props/send"; } function endpointBanUser() { return "/app/h5/manager-center/users/ban"; } function endpointUnbanUser() { return "/app/h5/manager-center/users/unban"; } function setLoading(isLoading) { const root = $(".manager-center"); const mask = $("#loadingMask"); if (root) root.dataset.loading = isLoading ? "true" : "false"; if (mask) mask.hidden = !isLoading; } function setStatus(node, text, type = "") { if (!node) return; node.textContent = text || ""; node.hidden = !text; node.classList.toggle("is-error", type === "error"); } function showToast(text) { const toast = $("#toast"); if (!toast) return; toast.textContent = text || ""; toast.hidden = !text; window.clearTimeout(showToast.timer); showToast.timer = window.setTimeout(() => { toast.hidden = true; }, 2300); } function syncModalState() { document.body.classList.toggle("is-modal-open", Boolean(document.querySelector(".modal-mask:not([hidden])"))); } function setModalOpen(selector, open) { const modal = $(selector); if (!modal) return; modal.hidden = !open; if (open) { setLanguageMenuOpen(false); setPropsTypeMenuOpen(false); } syncModalState(); } function closeModals() { document.querySelectorAll(".modal-mask").forEach((modal) => { modal.hidden = true; }); setPropsTypeMenuOpen(false); syncModalState(); } function openGiftModal() { if (!state.target) { showToast(message("enter_user")); return; } setModalOpen("#giftModal", true); updateActionState(); } function openBanModal() { if (!state.target) { showToast(message("enter_user")); return; } setStatus($("#banStatus"), ""); setModalOpen("#banModal", true); updateActionState(); } function openUnbanModal() { if (!state.target) { showToast(message("enter_user")); return; } setStatus($("#unbanStatus"), ""); setModalOpen("#unbanModal", true); updateActionState(); } function closePage() { try { if (window.app && typeof window.app.closePage === "function") { window.app.closePage(); return; } if (window.FlutterPageControl && typeof window.FlutterPageControl.postMessage === "function") { window.FlutterPageControl.postMessage("close_page"); return; } if (window.history.length > 1) window.history.back(); } catch (error) { console.error("close manager center failed:", error); if (window.history.length > 1) window.history.back(); } } function firstLetter(name, fallback) { const value = String(name || fallback || "U").trim(); return value ? value.slice(0, 1).toUpperCase() : "U"; } function renderAvatar(imgSelector, fallbackSelector, url, name, fallback) { const img = $(imgSelector); const fallbackNode = $(fallbackSelector); if (!img || !fallbackNode) return; const src = String(url || "").trim(); fallbackNode.textContent = firstLetter(name, fallback); if (src) { img.src = src; img.hidden = false; fallbackNode.hidden = true; } else { img.removeAttribute("src"); img.hidden = true; fallbackNode.hidden = false; } } function displayName(user) { return user?.userNickname || user?.nickname || user?.name || "-"; } function displayUserID(user) { return String(user?.userId || user?.id || "-"); } function displayShortID(user) { return String(user?.actualAccount || user?.account || user?.shortId || user?.userId || user?.id || "-"); } function canBanTarget(target) { return Boolean(target) && target.canBan !== false && !target.hasRecharge && !canUnbanTarget(target); } function canUnbanTarget(target) { const status = String(target?.accountStatus || "").trim().toUpperCase(); return Boolean(target) && (status === "FREEZE" || status === "ARCHIVE" || status === "ARCHIVE_DEVICE"); } function userIDText(user) { return `${message("uid_label", "UID")}: ${displayShortID(user)}`; } function propTypeLabel(type) { const key = `prop_type_${String(type || "").toLowerCase()}`; return message(key, type || "-"); } function formatDays(days) { return message("days", "{count} days").replace("{count}", String(days || 0)); } function giftDays(item) { const days = Number(item?.days); if (Number.isFinite(days) && days > 0) return days; return String(item?.type || state.propsType).toUpperCase() === "NOBLE_VIP" ? 3 : 7; } function renderManager(manager) { $("#managerName").textContent = displayName(manager); $("#managerUid").textContent = userIDText(manager); renderAvatar("#managerAvatar", "#managerAvatarFallback", manager?.userAvatar, displayName(manager), "M"); } function renderTarget() { const card = $("#targetCard"); const actionCard = $("#actionCard"); if (!state.target) { if (card) card.hidden = true; if (actionCard) actionCard.hidden = true; closeModals(); updateActionState(); return; } const target = state.target; if (card) card.hidden = false; if (actionCard) actionCard.hidden = false; $("#targetName").textContent = displayName(target); $("#targetUid").textContent = userIDText(target); $("#targetAccountStatus").textContent = target.accountStatus || "-"; const canBan = canBanTarget(target); const banEligibility = $("#banEligibility"); if (banEligibility) { banEligibility.textContent = canBan ? message("can_ban") : message("cannot_ban"); banEligibility.classList.toggle("is-danger", !canBan); } const canUnban = canUnbanTarget(target); const unbanEligibility = $("#unbanEligibility"); if (unbanEligibility) { unbanEligibility.textContent = canUnban ? message("can_unban") : message("cannot_unban"); unbanEligibility.classList.toggle("is-danger", !canUnban); } renderAvatar("#targetAvatar", "#targetAvatarFallback", target.userAvatar, displayName(target), "U"); updateActionState(); } function renderProps() { const list = $("#propsList"); if (!list) return; list.replaceChildren(); if (!state.props.length) { setStatus($("#propsStatus"), message("no_giftable_props")); updateActionState(); return; } setStatus($("#propsStatus"), ""); state.props.forEach((item) => { const button = document.createElement("button"); button.type = "button"; button.className = "prop-option"; button.dataset.propsId = String(item.id); if (String(item.id) === String(state.selectedPropsId)) { button.classList.add("is-selected"); } const cover = document.createElement("span"); cover.className = "prop-cover"; if (item.cover || item.sourceUrl) { const img = document.createElement("img"); img.alt = ""; img.src = item.cover || item.sourceUrl; cover.appendChild(img); } else { const fallback = document.createElement("span"); fallback.textContent = firstLetter(item.name, "G"); cover.appendChild(fallback); } const copy = document.createElement("span"); copy.className = "prop-copy"; const name = document.createElement("span"); name.className = "prop-name"; name.textContent = item.name || `ID ${item.id}`; const meta = document.createElement("span"); meta.className = "prop-meta"; meta.textContent = item.vipLevel ? `${propTypeLabel(item.type)} · VIP ${item.vipLevel}` : propTypeLabel(item.type); copy.append(name, meta); const days = document.createElement("span"); days.className = "prop-days"; days.textContent = formatDays(giftDays(item)); button.append(cover, copy, days); button.addEventListener("click", () => { state.selectedPropsId = String(item.id); renderProps(); updateActionState(); }); list.appendChild(button); }); updateActionState(); } function updateActionState() { const giftEntryButton = $("#giftEntryButton"); const banEntryButton = $("#banEntryButton"); const unbanEntryButton = $("#unbanEntryButton"); const sendButton = $("#sendPropsButton"); const banButton = $("#banButton"); const unbanButton = $("#unbanButton"); if (giftEntryButton) giftEntryButton.disabled = !state.target; if (banEntryButton) banEntryButton.disabled = !state.target; if (unbanEntryButton) unbanEntryButton.disabled = !state.target; if (sendButton) sendButton.disabled = !state.target || !state.selectedPropsId; if (banButton) banButton.disabled = !canBanTarget(state.target); if (unbanButton) unbanButton.disabled = !canUnbanTarget(state.target); } async function loadProfile() { const body = await requestGoJSON(endpointProfile()); state.manager = body?.manager || body || {}; renderManager(state.manager); } async function loadProps() { state.props = []; state.selectedPropsId = ""; renderProps(); setStatus($("#propsStatus"), message("loading")); const body = await requestGoJSON(endpointProps(state.propsType)); state.props = Array.isArray(body?.records) ? body.records : []; state.selectedPropsId = state.props.length ? String(state.props[0].id) : ""; renderProps(); } async function searchUser(event) { event.preventDefault(); const input = $("#accountInput"); const account = String(input?.value || "").trim(); if (!account) { setStatus($("#searchStatus"), message("enter_user"), "error"); return; } $("#searchButton").disabled = true; setStatus($("#searchStatus"), message("searching")); try { const body = await requestGoJSON(endpointSearchUser(account)); state.target = body?.user || body || null; renderTarget(); setStatus($("#searchStatus"), ""); } catch (error) { state.target = null; renderTarget(); setStatus($("#searchStatus"), friendlyError(error), "error"); } finally { $("#searchButton").disabled = false; } } async function sendProps() { if (!state.target || !state.selectedPropsId) return; const button = $("#sendPropsButton"); button.disabled = true; try { await requestGoJSON(endpointSendProps(), { method: "POST", body: { acceptUserId: displayUserID(state.target), propsId: state.selectedPropsId } }); setModalOpen("#giftModal", false); showToast(message("send_success")); } catch (error) { showToast(friendlyError(error)); } finally { updateActionState(); } } async function banUser() { if (!canBanTarget(state.target)) return; const button = $("#banButton"); button.disabled = true; setStatus($("#banStatus"), message("submitting")); try { await requestGoJSON(endpointBanUser(), { method: "POST", body: { userId: displayUserID(state.target), reason: $("#banReason").value || "" } }); state.target.accountStatus = "ARCHIVE"; renderTarget(); setModalOpen("#banModal", false); setStatus($("#banStatus"), ""); showToast(message("ban_success")); } catch (error) { setStatus($("#banStatus"), friendlyError(error), "error"); } finally { updateActionState(); } } async function unbanUser() { if (!canUnbanTarget(state.target)) return; const button = $("#unbanButton"); button.disabled = true; setStatus($("#unbanStatus"), message("submitting")); try { await requestGoJSON(endpointUnbanUser(), { method: "POST", body: { userId: displayUserID(state.target), reason: $("#unbanReason").value || "" } }); state.target.accountStatus = "NORMAL"; renderTarget(); setModalOpen("#unbanModal", false); setStatus($("#unbanStatus"), ""); showToast(message("unban_success")); } catch (error) { setStatus($("#unbanStatus"), friendlyError(error), "error"); } finally { updateActionState(); } } function friendlyError(error) { const code = error?.code || error?.response?.code || error?.response?.errorCodeName || ""; if (code === "missing_token") return message("missing_token"); if (code === "not_manager") return message("not_manager"); if (code === "user_not_found") return message("user_not_found"); if (code === "user_recharged") return message("user_recharged"); if (code === "user_already_banned") return message("user_already_banned"); if (code === "user_not_banned") return message("user_not_banned"); if (code === "prop_not_giftable") return message("prop_not_giftable"); if (code === "vip_not_giftable") return message("vip_not_giftable"); return error?.message || message("request_failed"); } function bindEvents() { $(".back-button")?.addEventListener("click", closePage); $(".language-button")?.addEventListener("click", (event) => { event.stopPropagation(); setLanguageMenuOpen(Boolean($(".language-menu")?.hidden)); }); document.querySelectorAll(".language-menu [data-lang]").forEach((button) => { button.addEventListener("click", async (event) => { event.stopPropagation(); setLanguageMenuOpen(false); await applyLanguage(button.dataset.lang); }); }); document.addEventListener("click", () => { setLanguageMenuOpen(false); setPropsTypeMenuOpen(false); }); $("#giftEntryButton")?.addEventListener("click", openGiftModal); $("#banEntryButton")?.addEventListener("click", openBanModal); $("#unbanEntryButton")?.addEventListener("click", openUnbanModal); document.querySelectorAll("[data-modal-close]").forEach((button) => { button.addEventListener("click", closeModals); }); document.querySelectorAll(".modal-mask").forEach((modal) => { modal.addEventListener("click", (event) => { if (event.target === modal) closeModals(); }); }); $("#propsTypeButton")?.addEventListener("click", (event) => { event.stopPropagation(); setLanguageMenuOpen(false); setPropsTypeMenuOpen(Boolean($("#propsTypeMenu")?.hidden)); }); document.querySelectorAll("#propsTypeMenu [data-value]").forEach((button) => { button.addEventListener("click", async (event) => { event.stopPropagation(); await choosePropsType(button.dataset.value); }); }); document.addEventListener("keydown", (event) => { if (event.key !== "Escape") return; setLanguageMenuOpen(false); setPropsTypeMenuOpen(false); closeModals(); }); $("#searchForm")?.addEventListener("submit", searchUser); $("#sendPropsButton")?.addEventListener("click", sendProps); $("#banButton")?.addEventListener("click", banUser); $("#unbanButton")?.addEventListener("click", unbanUser); } async function init() { bindEvents(); renderPropsTypeSelect(); await applyLanguage(currentLang); if (!readRawParam("token")) { setLoading(false); setStatus($("#searchStatus"), message("missing_token"), "error"); return; } try { await Promise.all([loadProfile(), loadProps()]); } catch (error) { showToast(friendlyError(error)); } finally { setLoading(false); } } init(); })();