2026-05-12 20:08:48 +08:00

1137 lines
39 KiB
JavaScript

(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();
})();