(function () { const API_BASE_URL = "https://jvapi.haiyihy.com"; const supportedLanguages = ["en", "ar", "tr", "id"]; const languageLabels = { en: "EN", ar: "AR", tr: "TR", id: "ID" }; const translations = { en: { document_title: "Agency Center", page_label: "Agency Center", back: "Back", title: "Agency Center", language_button_aria: "Change language", uid_prefix: "UID:", bd_prefix: "BD:", salary: "Salary", withdraw_exchange: "Withdraw/Exchange", open_withdraw_exchange: "Open withdraw and exchange page", host_list: "Host List", open_host_list: "Open host list", team_bill: "Salary Bills", open_team_bill: "Open salary bills", streaming_duration: "Work Time (min)", target: "Target", daily_details: "Daily data", gift_points: "Gift points", online_minutes: "Online minutes", no_daily_data: "No daily data", open_daily_data: "Open daily data", close: "Close", open_messages: "Open messages", users_message: "Messages", messages_loading: "Loading...", no_messages: "No messages", unknown_user: "Unknown user", agree: "Agree", refuse: "Refuse", operation_failed: "Operation failed", approved_application: "Approved {name}'s application.", rejected_application: "Rejected {name}'s application.", platform_policy: "Agency Policy", how_to_invite_member: "How to invite host", open_invite_help: "Open invite host guide", invite_download_app: "Invite users to download APP.", invited_users_login: "Invited users need to log in to the APP.", join_team_steps: "Me > Host Center > Apply to join the team.", enter_team_id: "Enter the team ID, click send to join.", completed: "Completed", in_progress: "In progress", out_of_account: "Out of account", pending: "Pending", not_agency_title: "Agency access unavailable", not_agency_text: "This account is not an agency account.", missing_token_text: "Open this page from the app or add a token in the URL.", apply_now: "Apply", missing_token: "Missing token", load_failed: "Failed to load data" }, ar: { document_title: "مركز الوكالة", page_label: "مركز الوكالة", back: "رجوع", title: "مركز الوكالة", language_button_aria: "تغيير اللغة", uid_prefix: "UID:", bd_prefix: "BD:", salary: "الراتب", withdraw_exchange: "سحب/استبدال", open_withdraw_exchange: "فتح صفحة السحب والاستبدال", host_list: "قائمة المضيفين", open_host_list: "فتح قائمة المضيفين", team_bill: "Salary Bills", open_team_bill: "Open salary bills", streaming_duration: "وقت العمل (دقيقة)", target: "الهدف", daily_details: "البيانات اليومية", gift_points: "نقاط الهدايا", online_minutes: "دقائق الاتصال", no_daily_data: "لا توجد بيانات يومية", open_daily_data: "فتح البيانات اليومية", close: "إغلاق", open_messages: "فتح الرسائل", users_message: "الرسائل", messages_loading: "جار التحميل...", no_messages: "لا توجد رسائل", unknown_user: "مستخدم غير معروف", agree: "موافقة", refuse: "رفض", operation_failed: "فشلت العملية", approved_application: "تمت الموافقة على طلب {name}.", rejected_application: "تم رفض طلب {name}.", platform_policy: "سياسة الوكالة", how_to_invite_member: "كيفية دعوة مضيف", open_invite_help: "فتح دليل دعوة مضيف", invite_download_app: "ادع المستخدمين لتنزيل التطبيق.", invited_users_login: "يجب على المستخدمين المدعوين تسجيل الدخول إلى التطبيق.", join_team_steps: "أنا > مركز المضيف > طلب الانضمام إلى الفريق.", enter_team_id: "أدخل معرف الفريق، ثم اضغط إرسال للانضمام.", completed: "مكتمل", in_progress: "قيد التنفيذ", out_of_account: "خارج الحساب", pending: "قيد الانتظار", not_agency_title: "الوصول للوكالة غير متاح", not_agency_text: "هذا الحساب ليس حساب وكالة.", missing_token_text: "افتح هذه الصفحة من التطبيق أو أضف token في الرابط.", apply_now: "تقديم", missing_token: "رمز الدخول مفقود", load_failed: "فشل تحميل البيانات" }, tr: { document_title: "Ajans Merkezi", page_label: "Ajans Merkezi", back: "Geri", title: "Ajans Merkezi", language_button_aria: "Dili degistir", uid_prefix: "UID:", bd_prefix: "BD:", salary: "Maas", withdraw_exchange: "Cek/Degistir", open_withdraw_exchange: "Cekme ve degisim sayfasini ac", host_list: "Host Listesi", open_host_list: "Host listesini ac", team_bill: "Salary Bills", open_team_bill: "Open salary bills", streaming_duration: "Calisma Suresi (dk)", target: "Hedef", daily_details: "Gunluk veri", gift_points: "Hediye puani", online_minutes: "Online dakika", no_daily_data: "Gunluk veri yok", open_daily_data: "Gunluk veriyi ac", close: "Kapat", open_messages: "Mesajlari ac", users_message: "Mesajlar", messages_loading: "Yukleniyor...", no_messages: "Mesaj yok", unknown_user: "Bilinmeyen kullanici", agree: "Onayla", refuse: "Reddet", operation_failed: "Islem basarisiz", approved_application: "{name} basvurusu onaylandi.", rejected_application: "{name} basvurusu reddedildi.", platform_policy: "Ajans Politikasi", how_to_invite_member: "Host nasil davet edilir", open_invite_help: "Host davet rehberini ac", invite_download_app: "Kullanicilari APP indirmeye davet et.", invited_users_login: "Davet edilen kullanicilarin APP'e giris yapmasi gerekiyor.", join_team_steps: "Ben > Host Merkezi > Takima katilmak icin basvur.", enter_team_id: "Takim ID'sini girin, katilmak icin gonder'e tiklayin.", completed: "Tamamlandi", in_progress: "Devam ediyor", out_of_account: "Hesap disi", pending: "Beklemede", not_agency_title: "Ajans erisimi yok", not_agency_text: "Bu hesap ajans hesabi degil.", missing_token_text: "Bu sayfayi uygulamadan acin veya URL'ye token ekleyin.", apply_now: "Basvur", missing_token: "Token eksik", load_failed: "Veri yuklenemedi" }, id: { document_title: "Pusat Agensi", page_label: "Pusat Agensi", back: "Kembali", title: "Pusat Agensi", language_button_aria: "Ubah bahasa", uid_prefix: "UID:", bd_prefix: "BD:", salary: "Gaji", withdraw_exchange: "Tarik/Tukar", open_withdraw_exchange: "Buka halaman tarik dan tukar", host_list: "Daftar Host", open_host_list: "Buka daftar host", team_bill: "Salary Bills", open_team_bill: "Open salary bills", streaming_duration: "Waktu Kerja (mnt)", target: "Target", daily_details: "Data harian", gift_points: "Poin hadiah", online_minutes: "Menit online", no_daily_data: "Tidak ada data harian", open_daily_data: "Buka data harian", close: "Tutup", open_messages: "Buka pesan", users_message: "Pesan", messages_loading: "Memuat...", no_messages: "Tidak ada pesan", unknown_user: "Pengguna tidak dikenal", agree: "Setuju", refuse: "Tolak", operation_failed: "Operasi gagal", approved_application: "Pengajuan {name} disetujui.", rejected_application: "Pengajuan {name} ditolak.", platform_policy: "Kebijakan agensi", how_to_invite_member: "Cara mengundang host", open_invite_help: "Buka panduan undang host", invite_download_app: "Undang pengguna untuk mengunduh APP.", invited_users_login: "Pengguna yang diundang harus login ke APP.", join_team_steps: "Saya > Host Center > Ajukan bergabung ke tim.", enter_team_id: "Masukkan ID tim, lalu ketuk kirim untuk bergabung.", completed: "Selesai", in_progress: "Berjalan", out_of_account: "Di luar akun", pending: "Tertunda", not_agency_title: "Akses agensi tidak tersedia", not_agency_text: "Akun ini bukan akun agensi.", missing_token_text: "Buka halaman ini dari aplikasi atau tambahkan token di URL.", apply_now: "Ajukan", missing_token: "Token tidak ditemukan", load_failed: "Gagal memuat data" } }; const params = readURLParams(); let currentLang = normalizeLanguage(params.get("lang")); let currentMessages = translations[currentLang] || translations.en; let currentProfile = null; let currentTeamInfo = null; let currentBdProfile = null; let currentIdentity = null; let currentHasAgencyAccess = true; let currentAccessReason = ""; let currentStreamingDuration = "0"; let currentGiftValue = "0"; let currentDailyTargets = []; let currentUnreadMessageCount = 0; let currentMessageItems = []; let currentMessagesLoading = false; let currentTeamMemberCount = null; 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"; } function t(key, fallback) { return currentMessages[key] || translations.en[key] || fallback || key; } function formatMessageTemplate(key, values = {}) { return t(key).replace(/\{(\w+)\}/g, (match, name) => values[name] ?? match); } function apiBaseURL() { const override = window.HYAPP_API_BASE_URL || params.get("apiBase"); if (override) return String(override).replace(/\/+$/, ""); return API_BASE_URL.replace(/\/+$/, ""); } function normalizeAuthorization(token) { const value = String(token || "").trim(); if (!value) return ""; return /^bearer\s+/i.test(value) ? value : `Bearer ${value}`; } function authHeadersFromToken(token) { 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=ATYOU;originChild=ATYOU" }; } async function requestJSON(path, options = {}) { const token = readRawParam("token"); if (!token) throw new Error(t("missing_token", "Missing token")); const headers = authHeadersFromToken(token); const method = options.method || "GET"; const hasBody = options.body !== undefined; if (hasBody) headers["Content-Type"] = "application/json"; const response = await fetch(new URL(path, `${apiBaseURL()}/`).toString(), { method, cache: "no-store", headers, body: hasBody ? JSON.stringify(options.body) : undefined }); 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.response = data; throw error; } return data.body ?? data.data ?? null; } function isTruthyIdentityValue(value) { if (typeof value === "boolean") return value; if (typeof value === "number") return value === 1; if (typeof value === "string") return ["true", "1", "yes"].includes(value.toLowerCase()); return false; } function hasAgencyAccess(identity) { if (!identity) return false; return isTruthyIdentityValue(identity.agent) || isTruthyIdentityValue(identity.freightAgent) || isTruthyIdentityValue(identity.yumi_manager) || isTruthyIdentityValue(identity.yumiManager) || isTruthyIdentityValue(identity.admin); } function setLoading(isLoading) { const root = document.querySelector(".agency-center"); const loadingMask = document.querySelector("#loadingMask"); if (root) root.dataset.loading = isLoading ? "true" : "false"; if (loadingMask) { loadingMask.hidden = !isLoading; loadingMask.setAttribute("aria-busy", String(isLoading)); } } function setAgencyView(hasAccess, reason) { currentHasAgencyAccess = hasAccess; currentAccessReason = reason || ""; const root = document.querySelector(".agency-center"); if (root) root.dataset.view = hasAccess ? "agency" : "no-access"; document.querySelectorAll(".agent-only").forEach((node) => { node.hidden = !hasAccess; }); const accessCard = document.querySelector("#accessCard"); if (accessCard) accessCard.hidden = hasAccess; const accessText = document.querySelector("#accessText"); if (accessText && reason === "missing-token") accessText.textContent = t("missing_token_text"); if (accessText && reason !== "missing-token") accessText.textContent = t("not_agency_text"); } function formatMoney(value) { const number = Number(value); return Number.isFinite(number) ? number.toFixed(2) : "0.00"; } function pickCurrentSalary(body) { if (typeof body === "number") return body; if (body && typeof body === "object") { return body.currentSalary ?? body.availableBalance ?? body.balance ?? 0; } return 0; } function pickProfileName(profile) { return profile?.userNickname || profile?.name || "Agency"; } function pickProfileAccount(profile) { return profile?.ownSpecialId?.account || profile?.account || profile?.id || "-"; } function pickTeamInfo(body) { return body?.teamProfile || body || null; } function pickTeamId(teamInfo) { return teamInfo?.id || teamInfo?.teamId || teamInfo?.teamProfile?.id || ""; } function pickBdLabel(profile) { if (!profile) return "-"; const name = profile.userNickname || profile.name || "BD"; const account = profile.ownSpecialId?.account || profile.account || profile.id || ""; if (!account || String(account) === String(name)) return name; return `${name} (${account})`; } function renderProfile(profile = currentProfile) { currentProfile = profile; const displayName = pickProfileName(profile); const displayAccount = pickProfileAccount(profile); const nameNode = document.querySelector("#profileName"); const uidNode = document.querySelector("#profileUid"); const avatarImage = document.querySelector("#profileAvatar"); const avatarFallback = document.querySelector("#profileAvatarFallback"); if (nameNode) nameNode.textContent = displayName; if (uidNode) uidNode.textContent = `${t("uid_prefix")} ${displayAccount}`.trim(); if (avatarFallback) { avatarFallback.textContent = displayName.slice(0, 1).toUpperCase() || "A"; avatarFallback.hidden = false; } if (!avatarImage) return; const avatar = profile?.userAvatar ? String(profile.userAvatar) : ""; avatarImage.alt = displayName; if (!avatar) { avatarImage.hidden = true; avatarImage.removeAttribute("src"); return; } avatarImage.hidden = false; if (avatarFallback) avatarFallback.hidden = true; avatarImage.onerror = () => { avatarImage.hidden = true; avatarImage.removeAttribute("src"); if (avatarFallback) avatarFallback.hidden = false; }; avatarImage.src = avatar; } function renderTeamInfo(teamInfo = currentTeamInfo) { currentTeamInfo = teamInfo; syncLinks(); } function renderTeamMemberCount(count = currentTeamMemberCount) { currentTeamMemberCount = count; const countNode = document.querySelector("#teamMemberCount"); if (!countNode) return; const number = Number(count); if (Number.isFinite(number)) { countNode.textContent = String(Math.max(0, Math.trunc(number))); return; } countNode.textContent = "-"; } function renderMessageUnread(count = currentUnreadMessageCount) { currentUnreadMessageCount = Number.isFinite(Number(count)) ? Math.max(0, Number(count)) : 0; const dot = document.querySelector("#messageUnreadDot"); const messageButton = document.querySelector(".profile-message-button"); if (dot) dot.hidden = currentUnreadMessageCount <= 0; if (messageButton) messageButton.dataset.unread = currentUnreadMessageCount > 0 ? "true" : "false"; } function pickMessageRecords(body) { if (Array.isArray(body)) return body; if (Array.isArray(body?.records)) return body.records; if (Array.isArray(body?.list)) return body.list; return []; } function normalizeMessageRecord(record) { const profile = record?.createUserProfile || record?.userProfile || record?.user || {}; const name = profile.userNickname || profile.name || record?.name || record?.userNickname || t("unknown_user"); return { id: record?.id, reason: record?.reason || "", teamId: record?.teamId || "", status: record?.status || "WAIT", createTime: record?.createTime || "", userId: profile.id || record?.userId || record?.createUserId || "", account: profile.ownSpecialId?.account || profile.account || record?.account || record?.userAccount || "", name, avatar: profile.userAvatar || record?.avatar || record?.userAvatar || "" }; } function createMessageAvatar(message) { const avatar = document.createElement("div"); avatar.className = "message-avatar"; const fallback = document.createElement("span"); fallback.textContent = (message.name || t("unknown_user")).slice(0, 1).toUpperCase(); avatar.appendChild(fallback); if (message.avatar) { const image = document.createElement("img"); image.src = message.avatar; image.alt = message.name; image.addEventListener("error", () => { image.remove(); }); avatar.appendChild(image); } return avatar; } function createMessageCard(message) { const card = document.createElement("div"); card.className = "message-card"; const user = document.createElement("div"); user.className = "message-user"; user.appendChild(createMessageAvatar(message)); const copy = document.createElement("div"); copy.className = "message-copy"; const name = document.createElement("div"); name.className = "message-name"; name.textContent = message.name || t("unknown_user"); const idLine = document.createElement("div"); idLine.className = "message-id"; idLine.textContent = `ID : ${message.account || message.userId || "-"}`; copy.appendChild(name); copy.appendChild(idLine); user.appendChild(copy); const actions = document.createElement("div"); actions.className = "message-actions"; const agree = document.createElement("button"); agree.type = "button"; agree.className = "message-action agree-btn"; agree.textContent = t("agree"); agree.addEventListener("click", () => processMessageApplication(message, "AGREE")); const refuse = document.createElement("button"); refuse.type = "button"; refuse.className = "message-action refuse-btn"; refuse.textContent = t("refuse"); refuse.addEventListener("click", () => processMessageApplication(message, "REJECT")); actions.appendChild(agree); actions.appendChild(refuse); card.appendChild(user); card.appendChild(actions); return card; } function renderMessageList(items = currentMessageItems) { currentMessageItems = Array.isArray(items) ? items : []; const list = document.querySelector("#messageList"); if (!list) return; if (currentMessagesLoading) { const loading = document.createElement("div"); loading.className = "message-empty"; loading.textContent = t("messages_loading"); replaceNodeChildren(list, [loading]); return; } if (!currentMessageItems.length) { const empty = document.createElement("div"); empty.className = "message-empty"; empty.textContent = t("no_messages"); replaceNodeChildren(list, [empty]); return; } replaceNodeChildren(list, currentMessageItems.map(createMessageCard)); } function renderBdProfile(profile = currentBdProfile) { currentBdProfile = profile; const bdName = document.querySelector("#bdName"); if (bdName) bdName.textContent = `${t("bd_prefix")} ${pickBdLabel(profile)}`.trim(); } function renderSalary(value) { const salaryNode = document.querySelector("#currentSalary"); if (salaryNode) salaryNode.textContent = formatMoney(value); } function formatStreamingDuration(value) { const numericValue = Number(value); if (!Number.isFinite(numericValue)) return "0"; const safeValue = Math.max(0, numericValue); return Number.isInteger(safeValue) ? String(safeValue) : String(Number(safeValue.toFixed(2))); } function pickFirstMemberWorkTarget(body) { const targets = Array.isArray(body?.targets) ? body.targets : []; return targets[0] || body?.target || null; } function pickStreamingDuration(body) { const workTarget = pickFirstMemberWorkTarget(body); return body?.onlineTime ?? body?.target?.onlineTime ?? workTarget?.target?.onlineTime ?? workTarget?.onlineTime ?? 0; } function renderStreamingDuration(value) { currentStreamingDuration = formatStreamingDuration(value); const durationNode = document.querySelector("#streamingDuration"); if (durationNode) durationNode.textContent = currentStreamingDuration; } function formatCountValue(value) { if (value === null || value === undefined || value === "") return "-"; const number = Number(value); if (Number.isFinite(number) && Number.isInteger(number)) return String(number); if (Number.isFinite(number)) return String(Number(number.toFixed(2))); return String(value); } function renderCurrentGiftValue(value) { currentGiftValue = formatCountValue(value === null || value === undefined || value === "" ? 0 : value); const giftNode = document.querySelector("#currentGiftValue"); const dailyGiftNode = document.querySelector("#dailyCurrentGift"); if (giftNode) giftNode.textContent = currentGiftValue; if (dailyGiftNode) dailyGiftNode.textContent = currentGiftValue; } function pickGiftValue(workTarget) { const target = workTarget?.target || workTarget || {}; return target.acceptGiftValue ?? target.giftValue ?? target.giftScore ?? target.currentGiftValue ?? null; } function pickDailyTargets(workTarget) { const target = workTarget?.target || workTarget || {}; return Array.isArray(target.dailyTargets) ? target.dailyTargets : []; } function formatDateNumber(value) { const text = String(value || ""); if (/^\d{8}$/.test(text)) { return `${text.slice(0, 4)}.${text.slice(4, 6)}.${text.slice(6, 8)}`; } return text || "-"; } function createDailyCell(label, value) { const cell = document.createElement("div"); cell.className = "daily-cell"; const labelNode = document.createElement("span"); labelNode.textContent = label; const valueNode = document.createElement("strong"); valueNode.textContent = value; cell.appendChild(labelNode); cell.appendChild(valueNode); return cell; } function createDailyRow(item) { const row = document.createElement("div"); row.className = "daily-row"; const date = document.createElement("div"); date.className = "daily-date"; date.textContent = formatDateNumber(item?.dateNumber); const values = document.createElement("div"); values.className = "daily-values"; values.appendChild(createDailyCell(t("gift_points"), formatCountValue(item?.acceptGiftValue ?? 0))); values.appendChild(createDailyCell(t("online_minutes"), formatCountValue(item?.onlineTime ?? 0))); row.appendChild(date); row.appendChild(values); return row; } function replaceNodeChildren(node, children) { while (node.firstChild) node.removeChild(node.firstChild); children.forEach((child) => node.appendChild(child)); } function renderDailyTargets(targets = currentDailyTargets) { currentDailyTargets = Array.isArray(targets) ? targets : []; const list = document.querySelector("#dailyList"); if (!list) return; if (!currentDailyTargets.length) { const empty = document.createElement("div"); empty.className = "daily-empty"; empty.textContent = t("no_daily_data"); replaceNodeChildren(list, [empty]); return; } replaceNodeChildren(list, currentDailyTargets.map(createDailyRow)); } function renderMemberWorkSummary(memberWork) { const workTarget = pickFirstMemberWorkTarget(memberWork); renderStreamingDuration(pickStreamingDuration(memberWork)); renderCurrentGiftValue(pickGiftValue(workTarget) ?? 0); renderDailyTargets(pickDailyTargets(workTarget)); } function setDailyModalOpen(open) { const modal = document.querySelector("#dailyModal"); if (!modal) return; modal.hidden = !open; if (open) { const inviteModal = document.querySelector("#inviteModal"); if (inviteModal) inviteModal.hidden = true; const messageModal = document.querySelector("#messageModal"); if (messageModal) messageModal.hidden = true; renderDailyTargets(); } syncModalBodyLock(); } function setInviteModalOpen(open) { const modal = document.querySelector("#inviteModal"); if (!modal) return; modal.hidden = !open; if (open) { const dailyModal = document.querySelector("#dailyModal"); if (dailyModal) dailyModal.hidden = true; const messageModal = document.querySelector("#messageModal"); if (messageModal) messageModal.hidden = true; } syncModalBodyLock(); } function setMessagesModalOpen(open) { const modal = document.querySelector("#messageModal"); if (!modal) return; modal.hidden = !open; if (open) { const dailyModal = document.querySelector("#dailyModal"); const inviteModal = document.querySelector("#inviteModal"); if (dailyModal) dailyModal.hidden = true; if (inviteModal) inviteModal.hidden = true; renderMessageList(); } syncModalBodyLock(); } function syncModalBodyLock() { const hasOpenModal = Array.from(document.querySelectorAll(".daily-modal, .message-modal")).some((modal) => !modal.hidden); document.body.classList.toggle("daily-modal-open", hasOpenModal); } function buildPageURL(target, options = {}) { const url = new URL(target, window.location.href); const nextParams = new URLSearchParams(url.search); params.forEach((value, key) => { if (!nextParams.has(key)) nextParams.set(key, value); }); const token = readRawParam("token"); if (token) nextParams.set("token", token); if (currentLang) nextParams.set("lang", currentLang); if (options.teamId) nextParams.set("teamId", String(options.teamId)); if (options.members !== undefined && options.members !== null && options.members !== "") { nextParams.set("members", String(options.members)); } url.search = nextParams.toString(); return url.toString(); } function syncLinks() { const teamId = pickTeamId(currentTeamInfo); document.querySelectorAll("[data-route]").forEach((link) => { const options = {}; if (link.dataset.policy === "team" && teamId) options.teamId = teamId; if (link.dataset.teamMember === "true") { if (teamId) options.teamId = teamId; if (currentTeamMemberCount !== null && currentTeamMemberCount !== undefined) { options.members = currentTeamMemberCount; } } if (link.dataset.teamBill === "true" && teamId) options.teamId = teamId; link.setAttribute("href", buildPageURL(link.dataset.route, options)); }); } function showToast(message) { const toast = document.querySelector("#toast"); if (!toast) return; toast.textContent = message; toast.hidden = false; window.clearTimeout(showToast.timer); showToast.timer = window.setTimeout(() => { toast.hidden = true; }, 2200); } 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 agency center page failed:", error); if (window.history.length > 1) window.history.back(); } } function setLanguageMenuOpen(open) { const languageButton = document.querySelector(".language-button"); const languageMenu = document.querySelector(".language-menu"); if (!languageButton || !languageMenu) return; languageMenu.hidden = !open; languageButton.setAttribute("aria-expanded", String(open)); } function renderLanguageControls() { const languageButton = document.querySelector(".language-button"); if (languageButton) { languageButton.textContent = languageLabels[currentLang]; languageButton.setAttribute("aria-label", t("language_button_aria")); } 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 renderMessages() { document.querySelectorAll("[data-i18n]").forEach((node) => { const value = currentMessages[node.dataset.i18n]; if (value) node.textContent = value; }); document.querySelectorAll("[data-i18n-aria]").forEach((node) => { const value = currentMessages[node.dataset.i18nAria]; if (value) node.setAttribute("aria-label", value); }); } function applyLanguage(lang) { currentLang = normalizeLanguage(lang); currentMessages = translations[currentLang] || translations.en; document.documentElement.lang = currentLang; document.documentElement.dir = currentLang === "ar" ? "rtl" : "ltr"; document.title = t("document_title"); renderMessages(); renderLanguageControls(); renderProfile(); renderTeamInfo(); renderBdProfile(); renderStreamingDuration(currentStreamingDuration); renderCurrentGiftValue(currentGiftValue); renderDailyTargets(); renderMessageUnread(); renderMessageList(); renderTeamMemberCount(); syncLinks(); if (!currentHasAgencyAccess) setAgencyView(false, currentAccessReason); } async function fetchIdentity() { currentIdentity = await requestJSON("/app/h5/identity"); return currentIdentity; } async function fetchUserProfile() { const profile = await requestJSON("/team/member/profile"); renderProfile(profile); return profile; } async function fetchTeamInfo() { const body = await requestJSON("/team/entry"); const teamInfo = pickTeamInfo(body); renderTeamInfo(teamInfo); return teamInfo; } async function fetchBdProfile() { const profile = await requestJSON("/team/bd-profile"); renderBdProfile(profile); return profile; } async function fetchBankBalance() { const body = await requestJSON("/wallet/bank/balance"); renderSalary(pickCurrentSalary(body)); } function pickTeamMemberCount(body) { if (typeof body === "number") return body; if (body && typeof body === "object") { return body.memberQuantity ?? body.count ?? body.total ?? body.memberCount ?? null; } return null; } async function fetchTeamMemberCount(teamId) { if (!teamId) { renderTeamMemberCount(null); return null; } try { const query = new URLSearchParams({ id: String(teamId) }); const body = await requestJSON(`/team/members/count?${query.toString()}`); const count = pickTeamMemberCount(body); renderTeamMemberCount(count); syncLinks(); return count; } catch (error) { console.error("Failed to load team member count:", error); renderTeamMemberCount(null); syncLinks(); return null; } } async function fetchMemberWork(memberId) { if (!memberId) { console.warn("Missing memberId for /team/member-work"); renderMemberWorkSummary(null); return null; } try { const url = new URL("/team/member-work", `${apiBaseURL()}/`); url.searchParams.set("userId", String(memberId)); const memberWork = await requestJSON(`${url.pathname}${url.search}`); renderMemberWorkSummary(memberWork); return memberWork; } catch (error) { console.error("Failed to load member work:", error); renderMemberWorkSummary(null); return null; } } async function fetchMessageList(teamId) { if (!teamId) { currentMessageItems = []; renderMessageUnread(0); renderMessageList(); return []; } currentMessagesLoading = true; renderMessageList(); try { const query = new URLSearchParams({ teamId: String(teamId), status: "WAIT" }); const body = await requestJSON(`/team/user/apply/record?${query.toString()}`); currentMessageItems = pickMessageRecords(body).map(normalizeMessageRecord); renderMessageUnread(currentMessageItems.length); return currentMessageItems; } catch (error) { console.error("Failed to load messages:", error); currentMessageItems = []; renderMessageUnread(0); return []; } finally { currentMessagesLoading = false; renderMessageList(); } } async function processMessageApplication(message, status) { if (!message?.id) return; try { await requestJSON("/team/process/user/apply", { method: "POST", body: { id: message.id, status } }); currentMessageItems = currentMessageItems.filter((item) => item.id !== message.id); renderMessageUnread(currentMessageItems.length); renderMessageList(); const messageKey = status === "AGREE" ? "approved_application" : "rejected_application"; showToast(formatMessageTemplate(messageKey, { name: message.name || t("unknown_user") })); } catch (error) { console.error("Failed to process message application:", error); showToast(error.message || t("operation_failed")); } } function bindEvents() { document.querySelector(".back-button")?.addEventListener("click", closePage); document.querySelector(".language-button")?.addEventListener("click", (event) => { event.stopPropagation(); const languageMenu = document.querySelector(".language-menu"); setLanguageMenuOpen(Boolean(languageMenu?.hidden)); }); document.querySelectorAll(".language-menu [data-lang]").forEach((button) => { button.addEventListener("click", (event) => { event.stopPropagation(); setLanguageMenuOpen(false); applyLanguage(button.dataset.lang); }); }); document.querySelector(".gift-value")?.addEventListener("click", () => { setDailyModalOpen(true); }); document.querySelector(".profile-message-button")?.addEventListener("click", () => { setMessagesModalOpen(true); fetchMessageList(pickTeamId(currentTeamInfo)); }); document.querySelector(".invite-help-button")?.addEventListener("click", () => { setInviteModalOpen(true); }); document.querySelectorAll("[data-close-daily]").forEach((node) => { node.addEventListener("click", () => { setDailyModalOpen(false); }); }); document.querySelectorAll("[data-close-invite]").forEach((node) => { node.addEventListener("click", () => { setInviteModalOpen(false); }); }); document.querySelectorAll("[data-close-messages]").forEach((node) => { node.addEventListener("click", () => { setMessagesModalOpen(false); }); }); document.addEventListener("click", () => { setLanguageMenuOpen(false); }); document.addEventListener("keydown", (event) => { if (event.key === "Escape") { setDailyModalOpen(false); setInviteModalOpen(false); setMessagesModalOpen(false); } }); } async function initializePage() { setLoading(true); applyLanguage(currentLang); bindEvents(); syncLinks(); const token = readRawParam("token"); if (!token) { setAgencyView(false, "missing-token"); setLoading(false); return; } try { const firstWave = [ fetchIdentity(), fetchUserProfile() ]; const firstResults = await Promise.allSettled(firstWave); firstResults.forEach((result) => { if (result.status === "rejected") console.warn("Agency center data request failed:", result.reason); }); const hasAccess = hasAgencyAccess(currentIdentity); setAgencyView(hasAccess); if (hasAccess) { const agencyResults = await Promise.allSettled([ fetchTeamInfo(), fetchBdProfile(), fetchBankBalance() ]); agencyResults.forEach((result) => { if (result.status === "rejected") console.warn("Agency center data request failed:", result.reason); }); const memberId = currentProfile?.id || currentProfile?.account; const teamId = pickTeamId(currentTeamInfo); const dependentResults = await Promise.allSettled([ fetchMemberWork(memberId), fetchMessageList(teamId), fetchTeamMemberCount(teamId) ]); dependentResults.forEach((result) => { if (result.status === "rejected") console.warn("Agency center dependent request failed:", result.reason); }); } } catch (error) { console.error("Failed to initialize agency center:", error); showToast(error.message || t("load_failed")); setAgencyView(hasAgencyAccess(currentIdentity)); } finally { setLoading(false); } } initializePage(); })();