807 lines
28 KiB
JavaScript
807 lines
28 KiB
JavaScript
(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 fallbackMessages = {
|
||
en: {
|
||
document_title: "BD Leader Center",
|
||
page_label: "BD Leader Center",
|
||
back: "Back",
|
||
title: "BD Leader Center",
|
||
language_button_aria: "Change language",
|
||
role: "BD Leader",
|
||
uid_prefix: "UID:",
|
||
my_available_salary: "My available salary",
|
||
details: "Details",
|
||
bd_number: "BD number",
|
||
team_salary: "Team salary",
|
||
bd_policy_link: "BD policy",
|
||
bd_leader_history: "BD Leader history",
|
||
agency_list_link: "Agency list",
|
||
bd_list_link: "BD List",
|
||
invite_become_agent: "Invite to become agent",
|
||
invite_become_bd: "Invite to become BD",
|
||
bd_list_preview: "BD List",
|
||
bd_list_preview_subtitle: "Current settlement period",
|
||
more: "More",
|
||
total_income: "Total income",
|
||
previous_period_income: "Previous period income",
|
||
salary: "Salary",
|
||
agencies: "Agencies",
|
||
loading_data: "Loading...",
|
||
no_data: "No data",
|
||
in_progress: "In Progress",
|
||
pending: "Pending",
|
||
completed: "Completed",
|
||
out_of_account: "Out of account",
|
||
close: "Close",
|
||
failed_to_load: "Failed to load data",
|
||
failed_to_load_history: "Failed to load history"
|
||
},
|
||
ar: {
|
||
document_title: "مركز قائد BD",
|
||
page_label: "مركز قائد BD",
|
||
back: "رجوع",
|
||
title: "مركز قائد BD",
|
||
language_button_aria: "تغيير اللغة",
|
||
role: "قائد BD",
|
||
uid_prefix: "UID:",
|
||
my_available_salary: "راتبي المتاح",
|
||
details: "التفاصيل",
|
||
bd_number: "عدد BD",
|
||
team_salary: "راتب الفريق",
|
||
bd_policy_link: "سياسة BD",
|
||
bd_leader_history: "سجل قائد BD",
|
||
agency_list_link: "قائمة الوكالات",
|
||
bd_list_link: "قائمة BD",
|
||
invite_become_agent: "دعوة ليصبح وكيلا",
|
||
invite_become_bd: "دعوة ليصبح BD",
|
||
bd_list_preview: "قائمة BD",
|
||
bd_list_preview_subtitle: "فترة التسوية الحالية",
|
||
more: "المزيد",
|
||
total_income: "إجمالي الدخل",
|
||
previous_period_income: "دخل الفترة السابقة",
|
||
salary: "الراتب",
|
||
agencies: "الوكالات",
|
||
loading_data: "جار التحميل...",
|
||
no_data: "لا توجد بيانات",
|
||
in_progress: "قيد التنفيذ",
|
||
pending: "قيد الانتظار",
|
||
completed: "مكتمل",
|
||
out_of_account: "خارج الحساب",
|
||
close: "إغلاق",
|
||
failed_to_load: "فشل تحميل البيانات",
|
||
failed_to_load_history: "فشل تحميل السجل"
|
||
},
|
||
tr: {
|
||
document_title: "BD Leader Merkezi",
|
||
page_label: "BD Leader Merkezi",
|
||
back: "Geri",
|
||
title: "BD Leader Merkezi",
|
||
language_button_aria: "Dili değiştir",
|
||
role: "BD Leader",
|
||
uid_prefix: "UID:",
|
||
my_available_salary: "Kullanılabilir maaşım",
|
||
details: "Detaylar",
|
||
bd_number: "BD sayısı",
|
||
team_salary: "Takım maaşı",
|
||
bd_policy_link: "BD politikası",
|
||
bd_leader_history: "BD Leader geçmişi",
|
||
agency_list_link: "Ajans listesi",
|
||
bd_list_link: "BD Listesi",
|
||
invite_become_agent: "Ajans olmaya davet et",
|
||
invite_become_bd: "BD olmaya davet et",
|
||
bd_list_preview: "BD Listesi",
|
||
bd_list_preview_subtitle: "Mevcut ödeme dönemi",
|
||
more: "Daha fazla",
|
||
total_income: "Toplam gelir",
|
||
previous_period_income: "Önceki dönem geliri",
|
||
salary: "Maaş",
|
||
agencies: "Ajanslar",
|
||
loading_data: "Yükleniyor...",
|
||
no_data: "Veri yok",
|
||
in_progress: "Devam ediyor",
|
||
pending: "Beklemede",
|
||
completed: "Tamamlandı",
|
||
out_of_account: "Hesap dışı",
|
||
close: "Kapat",
|
||
failed_to_load: "Veri yüklenemedi",
|
||
failed_to_load_history: "Geçmiş yüklenemedi"
|
||
},
|
||
id: {
|
||
document_title: "Pusat BD Leader",
|
||
page_label: "Pusat BD Leader",
|
||
back: "Kembali",
|
||
title: "Pusat BD Leader",
|
||
language_button_aria: "Ubah bahasa",
|
||
role: "BD Leader",
|
||
uid_prefix: "UID:",
|
||
my_available_salary: "Gaji tersedia",
|
||
details: "Detail",
|
||
bd_number: "Jumlah BD",
|
||
team_salary: "Gaji tim",
|
||
bd_policy_link: "Kebijakan BD",
|
||
bd_leader_history: "Riwayat BD Leader",
|
||
agency_list_link: "Daftar agensi",
|
||
bd_list_link: "Daftar BD",
|
||
invite_become_agent: "Undang menjadi agen",
|
||
invite_become_bd: "Undang menjadi BD",
|
||
bd_list_preview: "Daftar BD",
|
||
bd_list_preview_subtitle: "Periode settlement saat ini",
|
||
more: "Lainnya",
|
||
total_income: "Total pendapatan",
|
||
previous_period_income: "Pendapatan periode sebelumnya",
|
||
salary: "Gaji",
|
||
agencies: "Agensi",
|
||
loading_data: "Memuat...",
|
||
no_data: "Tidak ada data",
|
||
in_progress: "Sedang diproses",
|
||
pending: "Menunggu",
|
||
completed: "Selesai",
|
||
out_of_account: "Di luar akun",
|
||
close: "Tutup",
|
||
failed_to_load: "Gagal memuat data",
|
||
failed_to_load_history: "Gagal memuat riwayat"
|
||
}
|
||
};
|
||
|
||
const params = readURLParams();
|
||
let currentLang = normalizeLanguage(params.get("lang"));
|
||
let currentMessages = fallbackMessages[currentLang] || fallbackMessages.en;
|
||
const state = {
|
||
profile: null,
|
||
identity: null,
|
||
teamEntry: null,
|
||
balanceTotal: {},
|
||
bill: {},
|
||
history: null,
|
||
historyMore: 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();
|
||
if (value.startsWith("ar")) return "ar";
|
||
if (value.startsWith("tr")) return "tr";
|
||
if (value.startsWith("id")) return "id";
|
||
return supportedLanguages.includes(value) ? value : "en";
|
||
}
|
||
|
||
function message(key, fallback = "") {
|
||
return currentMessages[key] || fallbackMessages.en[key] || fallback || key;
|
||
}
|
||
|
||
function renderMessages(messages) {
|
||
document.querySelectorAll("[data-i18n]").forEach((node) => {
|
||
const value = messages[node.dataset.i18n] || fallbackMessages.en[node.dataset.i18n];
|
||
if (value) node.textContent = value;
|
||
});
|
||
|
||
document.querySelectorAll("[data-i18n-aria]").forEach((node) => {
|
||
const value = messages[node.dataset.i18nAria] || fallbackMessages.en[node.dataset.i18nAria];
|
||
if (value) node.setAttribute("aria-label", value);
|
||
});
|
||
}
|
||
|
||
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) {
|
||
const token = readRawParam("token");
|
||
if (!token) throw new Error("Missing token");
|
||
|
||
const response = await fetch(new URL(path, `${apiBaseURL()}/`).toString(), {
|
||
cache: "no-store",
|
||
headers: authHeadersFromToken(token)
|
||
});
|
||
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 setLoading(isLoading) {
|
||
const root = document.querySelector(".bd-leader-center");
|
||
const mask = document.querySelector("#loadingMask");
|
||
if (root) root.dataset.loading = isLoading ? "true" : "false";
|
||
if (mask) mask.hidden = !isLoading;
|
||
}
|
||
|
||
function updateModalLock() {
|
||
const hasOpen = Array.from(document.querySelectorAll(".history-modal, .details-modal")).some((modal) => !modal.hidden);
|
||
document.body.classList.toggle("modal-open", hasOpen);
|
||
}
|
||
|
||
function setModalOpen(selector, open) {
|
||
const modal = document.querySelector(selector);
|
||
if (!modal) return;
|
||
modal.hidden = !open;
|
||
updateModalLock();
|
||
}
|
||
|
||
function showToast(text) {
|
||
const toast = document.querySelector("#toast");
|
||
if (!toast) return;
|
||
toast.textContent = text || "";
|
||
toast.hidden = !text;
|
||
window.clearTimeout(showToast.timer);
|
||
showToast.timer = window.setTimeout(() => {
|
||
toast.hidden = true;
|
||
}, 2500);
|
||
}
|
||
|
||
function formatMoney(value) {
|
||
const number = Number(value);
|
||
if (!Number.isFinite(number)) return "0.00";
|
||
return number.toFixed(2);
|
||
}
|
||
|
||
function formatCount(value) {
|
||
if (value === null || value === undefined || value === "") return "0";
|
||
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 pickSpecialAccount(profile) {
|
||
return profile?.ownSpecialId?.account || profile?.specialId?.account || profile?.specialAccount || profile?.shortAccount || profile?.shortId || "";
|
||
}
|
||
|
||
function pickProfileName(profile) {
|
||
return profile?.userNickname || profile?.name || "-";
|
||
}
|
||
|
||
function pickProfileAccount(profile) {
|
||
return pickSpecialAccount(profile) || profile?.account || profile?.id || "-";
|
||
}
|
||
|
||
function renderAvatar(profile) {
|
||
const image = document.querySelector("#profileAvatar");
|
||
const fallback = document.querySelector("#profileAvatarFallback");
|
||
if (!image || !fallback) return;
|
||
|
||
const name = pickProfileName(profile);
|
||
const avatar = profile?.userAvatar || profile?.avatar || "";
|
||
fallback.textContent = String(name || "B").slice(0, 1).toUpperCase() || "B";
|
||
|
||
if (!avatar) {
|
||
image.hidden = true;
|
||
image.removeAttribute("src");
|
||
fallback.hidden = false;
|
||
return;
|
||
}
|
||
|
||
image.alt = name;
|
||
fallback.hidden = true;
|
||
image.hidden = false;
|
||
image.onerror = () => {
|
||
image.hidden = true;
|
||
image.removeAttribute("src");
|
||
fallback.hidden = false;
|
||
};
|
||
image.src = avatar;
|
||
}
|
||
|
||
function renderProfile(profile = state.profile) {
|
||
const name = pickProfileName(profile);
|
||
const account = pickProfileAccount(profile);
|
||
const nameNode = document.querySelector("#profileName");
|
||
const uidNode = document.querySelector("#profileUid");
|
||
if (nameNode) nameNode.textContent = name;
|
||
if (uidNode) uidNode.textContent = `${message("uid_prefix")} ${account}`.trim();
|
||
renderAvatar(profile);
|
||
}
|
||
|
||
function renderBalance() {
|
||
const balance = state.balanceTotal?.availableBalance ?? state.balanceTotal?.balance ?? 0;
|
||
const node = document.querySelector("#availableBalance");
|
||
if (node) node.textContent = formatMoney(balance);
|
||
}
|
||
|
||
function renderBill() {
|
||
const bill = state.bill || {};
|
||
const members = Array.isArray(bill.memberBillList) ? bill.memberBillList : [];
|
||
const billTitle = document.querySelector("#billTitle");
|
||
const bdNumber = document.querySelector("#bdNumber");
|
||
const teamSalary = document.querySelector("#teamSalary");
|
||
if (billTitle) billTitle.textContent = bill.billTitle || "-";
|
||
if (bdNumber) bdNumber.textContent = formatCount(bill.memberCount ?? bill.bdNumber ?? members.length);
|
||
if (teamSalary) teamSalary.textContent = formatMoney(bill.totalSalary ?? bill.teamSalary ?? 0);
|
||
renderMembers(members);
|
||
}
|
||
|
||
function createFallbackAvatar(name) {
|
||
const span = document.createElement("span");
|
||
span.className = "member-fallback";
|
||
span.textContent = String(name || "B").slice(0, 1).toUpperCase() || "B";
|
||
return span;
|
||
}
|
||
|
||
function createMemberRow(item) {
|
||
const name = item?.agentName || item?.bdUserName || "-";
|
||
const account = item?.agentAccount || item?.account || "-";
|
||
const row = document.createElement("article");
|
||
row.className = "member-row";
|
||
|
||
const avatar = document.createElement("div");
|
||
avatar.className = "member-avatar";
|
||
const avatarUrl = item?.agentAvatar || item?.bdUserAvatar || "";
|
||
if (avatarUrl) {
|
||
const image = document.createElement("img");
|
||
image.src = avatarUrl;
|
||
image.alt = "";
|
||
image.addEventListener("error", () => {
|
||
avatar.replaceChildren(createFallbackAvatar(name));
|
||
});
|
||
avatar.appendChild(image);
|
||
} else {
|
||
avatar.appendChild(createFallbackAvatar(name));
|
||
}
|
||
|
||
const main = document.createElement("div");
|
||
main.className = "member-main";
|
||
const nameNode = document.createElement("div");
|
||
nameNode.className = "member-name";
|
||
nameNode.textContent = name;
|
||
const metaNode = document.createElement("div");
|
||
metaNode.className = "member-meta";
|
||
metaNode.textContent = `${message("uid_prefix")} ${account}`.trim();
|
||
main.append(nameNode, metaNode);
|
||
|
||
const side = document.createElement("div");
|
||
side.className = "member-side";
|
||
const salary = document.createElement("div");
|
||
salary.textContent = `${message("team_salary")}: $${formatMoney(item?.teamSalaryAmount || 0)}`;
|
||
const agencies = document.createElement("div");
|
||
agencies.textContent = `${message("agencies")}: ${formatCount(item?.teamMemberCount || item?.agencyCount || 0)}`;
|
||
side.append(salary, agencies);
|
||
|
||
row.append(avatar, main, side);
|
||
return row;
|
||
}
|
||
|
||
function replaceChildren(node, children) {
|
||
while (node.firstChild) node.removeChild(node.firstChild);
|
||
children.forEach((child) => node.appendChild(child));
|
||
}
|
||
|
||
function renderMembers(members) {
|
||
const list = document.querySelector("#bdMemberList");
|
||
if (!list) return;
|
||
const preview = members.slice(0, 5);
|
||
if (!preview.length) {
|
||
const empty = document.createElement("div");
|
||
empty.className = "empty-state";
|
||
empty.textContent = message("no_data");
|
||
replaceChildren(list, [empty]);
|
||
return;
|
||
}
|
||
replaceChildren(list, preview.map(createMemberRow));
|
||
}
|
||
|
||
function normalizeStatus(status) {
|
||
if (status === "UNPAID" || status === "In Progress" || status === message("in_progress")) return message("in_progress");
|
||
if (status === "Pending" || status === message("pending")) return message("pending");
|
||
if (status === "SETTLED" || status === "PAY_OUT" || status === "Completed" || status === message("completed")) return message("completed");
|
||
if (status === "HANG_UP" || status === "Out of account" || status === "Out Of Account" || status === message("out_of_account")) return message("out_of_account");
|
||
return status || "";
|
||
}
|
||
|
||
function statusClass(status) {
|
||
const value = normalizeStatus(status);
|
||
if (value === message("completed")) return "is-completed";
|
||
if (value === message("pending")) return "is-pending";
|
||
if (value === message("out_of_account")) return "is-out";
|
||
return "is-progress";
|
||
}
|
||
|
||
function isCompletedStatus(status) {
|
||
return normalizeStatus(status) === message("completed");
|
||
}
|
||
|
||
function createHistoryCell(label, value) {
|
||
const cell = document.createElement("div");
|
||
cell.className = "history-cell";
|
||
const labelNode = document.createElement("span");
|
||
labelNode.textContent = label;
|
||
const valueNode = document.createElement("strong");
|
||
valueNode.textContent = value;
|
||
cell.append(labelNode, valueNode);
|
||
return cell;
|
||
}
|
||
|
||
function createHistoryRow(item) {
|
||
const row = document.createElement("article");
|
||
row.className = `history-row ${statusClass(item?.statusText)}`;
|
||
|
||
const status = document.createElement("div");
|
||
status.className = "status-tag";
|
||
status.textContent = normalizeStatus(item?.statusText);
|
||
|
||
const title = document.createElement("div");
|
||
title.className = "history-title";
|
||
title.textContent = item?.billTitle || "-";
|
||
|
||
const grid = document.createElement("div");
|
||
grid.className = "history-grid";
|
||
grid.append(
|
||
createHistoryCell(message("bd_number"), formatCount(item?.bdNumber || 0)),
|
||
createHistoryCell(message("team_salary"), `$${formatMoney(item?.teamSalaryAmount || 0)}`)
|
||
);
|
||
|
||
row.append(status, title, grid);
|
||
if (isCompletedStatus(item?.statusText)) {
|
||
const more = document.createElement("button");
|
||
more.className = "more-button";
|
||
more.type = "button";
|
||
more.textContent = message("more");
|
||
more.addEventListener("click", () => showHistoryMore(item?.billBelong));
|
||
row.appendChild(more);
|
||
}
|
||
return row;
|
||
}
|
||
|
||
function renderHistory() {
|
||
const history = state.history || {};
|
||
const total = document.querySelector("#historyTotalIncome");
|
||
const previous = document.querySelector("#historyPreviousIncome");
|
||
const list = document.querySelector("#historyList");
|
||
if (total) total.textContent = `$${formatMoney(history.totalIncome || 0)}`;
|
||
if (previous) previous.textContent = `$${formatMoney(history.previousPeriodIncome || 0)}`;
|
||
if (!list) return;
|
||
|
||
const items = Array.isArray(history.incomeDetails) ? history.incomeDetails : [];
|
||
if (!items.length) {
|
||
const empty = document.createElement("div");
|
||
empty.className = "empty-state";
|
||
empty.textContent = message("no_data");
|
||
replaceChildren(list, [empty]);
|
||
return;
|
||
}
|
||
replaceChildren(list, items.map(createHistoryRow));
|
||
}
|
||
|
||
function normalizeBillBelong(value) {
|
||
const text = String(value || "").trim();
|
||
if (!text) return "";
|
||
const iso = text.match(/^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2})(?::(\d{2}))?)?/);
|
||
if (iso) return `${iso[1]}-${iso[2]}-${iso[3]}T${iso[4] || "00"}:${iso[5] || "00"}:${iso[6] || "00"}`;
|
||
const compact = text.match(/^(\d{4})(\d{2})(\d{2})(?:(\d{2})(\d{2})(\d{2})?)?$/);
|
||
if (compact) return `${compact[1]}-${compact[2]}-${compact[3]}T${compact[4] || "00"}:${compact[5] || "00"}:${compact[6] || "00"}`;
|
||
return text;
|
||
}
|
||
|
||
function historyMorePath(billBelong) {
|
||
const normalized = normalizeBillBelong(billBelong);
|
||
return normalized ? `/team/bd/leader/history/more?billBelong=${encodeURIComponent(normalized)}` : "";
|
||
}
|
||
|
||
function createDetailsCell(label, value) {
|
||
const cell = document.createElement("div");
|
||
cell.className = "details-cell";
|
||
const labelNode = document.createElement("span");
|
||
labelNode.textContent = label;
|
||
const valueNode = document.createElement("strong");
|
||
valueNode.textContent = value;
|
||
cell.append(labelNode, valueNode);
|
||
return cell;
|
||
}
|
||
|
||
function renderDetails() {
|
||
const data = state.historyMore || {};
|
||
const title = document.querySelector("#detailsTitle");
|
||
const summary = document.querySelector("#detailsSummary");
|
||
const list = document.querySelector("#detailsList");
|
||
if (title) title.textContent = data.period || "-";
|
||
if (summary) {
|
||
replaceChildren(summary, [
|
||
createDetailsCell(message("team_salary"), `$${formatMoney(data.teamSalary || 0)}`),
|
||
createDetailsCell(message("bd_number"), formatCount(data.bdNumber || 0))
|
||
]);
|
||
}
|
||
if (!list) return;
|
||
|
||
const members = Array.isArray(data.memberDetails) ? data.memberDetails : [];
|
||
if (!members.length) {
|
||
const empty = document.createElement("div");
|
||
empty.className = "empty-state";
|
||
empty.textContent = message("no_data");
|
||
replaceChildren(list, [empty]);
|
||
return;
|
||
}
|
||
|
||
replaceChildren(list, members.map((item) => {
|
||
const row = createMemberRow({
|
||
agentName: item.bdUserName,
|
||
agentAvatar: item.bdUserAvatar,
|
||
agentAccount: item.account,
|
||
teamSalaryAmount: item.salary,
|
||
teamMemberCount: item.agencyCount
|
||
});
|
||
row.classList.add("details-row");
|
||
return row;
|
||
}));
|
||
}
|
||
|
||
async function fetchProfile() {
|
||
state.profile = await requestJSON("/team/member/profile");
|
||
renderProfile();
|
||
}
|
||
|
||
async function fetchIdentity() {
|
||
state.identity = await requestJSON("/app/h5/identity");
|
||
}
|
||
|
||
async function fetchTeamEntry() {
|
||
state.teamEntry = await requestJSON("/team/entry");
|
||
}
|
||
|
||
async function fetchBalanceTotal() {
|
||
state.balanceTotal = await requestJSON("/wallet/salary-account/balance/total") || {};
|
||
renderBalance();
|
||
}
|
||
|
||
async function fetchBDLeaderBill() {
|
||
state.bill = await requestJSON("/team/bd/member-bill/list?type=BDLEADER") || {};
|
||
renderBill();
|
||
}
|
||
|
||
async function fetchHistory() {
|
||
const history = await requestJSON("/team/bd/leader/history") || {};
|
||
const currentHistory = state.bill?.bdHistoryCO;
|
||
const details = Array.isArray(history.incomeDetails) ? [...history.incomeDetails] : [];
|
||
if (currentHistory) details.unshift(currentHistory);
|
||
state.history = { ...history, incomeDetails: details };
|
||
renderHistory();
|
||
}
|
||
|
||
async function showHistoryModal() {
|
||
try {
|
||
setModalOpen("#historyModal", true);
|
||
const list = document.querySelector("#historyList");
|
||
if (list) {
|
||
const loading = document.createElement("div");
|
||
loading.className = "empty-state";
|
||
loading.textContent = message("loading_data");
|
||
replaceChildren(list, [loading]);
|
||
}
|
||
await fetchHistory();
|
||
} catch (error) {
|
||
console.error("Failed to load BD leader history:", error);
|
||
showToast(error.response?.errorMsg || error.message || message("failed_to_load_history"));
|
||
renderHistory();
|
||
}
|
||
}
|
||
|
||
async function showHistoryMore(billBelong) {
|
||
const path = historyMorePath(billBelong);
|
||
if (!path) return;
|
||
try {
|
||
state.historyMore = await requestJSON(path) || {};
|
||
renderDetails();
|
||
setModalOpen("#detailsModal", true);
|
||
} catch (error) {
|
||
console.error("Failed to load BD leader history more:", error);
|
||
showToast(error.response?.errorMsg || error.message || message("failed_to_load_history"));
|
||
}
|
||
}
|
||
|
||
function buildRouteURL(route) {
|
||
const url = new URL(route, window.location.origin);
|
||
const token = readRawParam("token");
|
||
if (token) url.searchParams.set("token", token);
|
||
if (currentLang) url.searchParams.set("lang", currentLang);
|
||
return `${url.pathname}${url.search}${url.hash}`;
|
||
}
|
||
|
||
function navigateTo(route) {
|
||
window.location.href = buildRouteURL(route);
|
||
}
|
||
|
||
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 BD leader center page failed:", error);
|
||
if (window.history.length > 1) window.history.back();
|
||
}
|
||
}
|
||
|
||
function setLanguageMenuOpen(open) {
|
||
const button = document.querySelector(".language-button");
|
||
const menu = document.querySelector(".language-menu");
|
||
if (!button || !menu) return;
|
||
menu.hidden = !open;
|
||
button.setAttribute("aria-expanded", String(open));
|
||
}
|
||
|
||
function renderLanguageControls() {
|
||
const button = document.querySelector(".language-button");
|
||
if (button) {
|
||
button.textContent = languageLabels[currentLang];
|
||
button.setAttribute("aria-label", message("language_button_aria", "Change language"));
|
||
}
|
||
document.querySelectorAll(".language-menu [data-lang]").forEach((node) => {
|
||
const active = node.dataset.lang === currentLang;
|
||
node.classList.toggle("is-active", active);
|
||
node.setAttribute("aria-pressed", String(active));
|
||
});
|
||
}
|
||
|
||
async function applyLanguage(lang) {
|
||
currentLang = normalizeLanguage(lang);
|
||
currentMessages = fallbackMessages[currentLang] || fallbackMessages.en;
|
||
document.documentElement.lang = currentLang;
|
||
document.documentElement.dir = currentLang === "ar" ? "rtl" : "ltr";
|
||
document.title = message("document_title", "BD Leader Center");
|
||
renderMessages(currentMessages);
|
||
renderLanguageControls();
|
||
renderProfile();
|
||
renderBalance();
|
||
renderBill();
|
||
renderHistory();
|
||
renderDetails();
|
||
}
|
||
|
||
function clearPayee() {
|
||
try {
|
||
sessionStorage.removeItem("payee");
|
||
localStorage.removeItem("payee");
|
||
} catch (error) {
|
||
console.debug("payee cache clear skipped:", error);
|
||
}
|
||
}
|
||
|
||
function setIdentity() {
|
||
try {
|
||
localStorage.setItem("identity", JSON.stringify({ identity: "BD_LEADER" }));
|
||
} catch (error) {
|
||
console.debug("identity cache write skipped:", error);
|
||
}
|
||
}
|
||
|
||
function bindEvents() {
|
||
document.querySelector(".back-button")?.addEventListener("click", closePage);
|
||
document.querySelector(".language-button")?.addEventListener("click", (event) => {
|
||
event.stopPropagation();
|
||
const menu = document.querySelector(".language-menu");
|
||
setLanguageMenuOpen(Boolean(menu?.hidden));
|
||
});
|
||
document.querySelectorAll(".language-menu [data-lang]").forEach((button) => {
|
||
button.addEventListener("click", (event) => {
|
||
event.stopPropagation();
|
||
setLanguageMenuOpen(false);
|
||
applyLanguage(button.dataset.lang);
|
||
});
|
||
});
|
||
document.addEventListener("click", () => setLanguageMenuOpen(false));
|
||
document.querySelectorAll("[data-route]").forEach((node) => {
|
||
node.addEventListener("click", () => navigateTo(node.dataset.route));
|
||
});
|
||
document.querySelector("[data-action='history']")?.addEventListener("click", showHistoryModal);
|
||
document.querySelectorAll("[data-close-history]").forEach((node) => {
|
||
node.addEventListener("click", () => setModalOpen("#historyModal", false));
|
||
});
|
||
document.querySelectorAll("[data-close-details]").forEach((node) => {
|
||
node.addEventListener("click", () => setModalOpen("#detailsModal", false));
|
||
});
|
||
document.addEventListener("keydown", (event) => {
|
||
if (event.key === "Escape") {
|
||
setModalOpen("#historyModal", false);
|
||
setModalOpen("#detailsModal", false);
|
||
}
|
||
});
|
||
}
|
||
|
||
async function initializePage() {
|
||
setLoading(true);
|
||
clearPayee();
|
||
setIdentity();
|
||
bindEvents();
|
||
renderProfile();
|
||
renderBalance();
|
||
|
||
try {
|
||
await applyLanguage(currentLang);
|
||
const tasks = [
|
||
fetchProfile(),
|
||
fetchIdentity(),
|
||
fetchTeamEntry(),
|
||
fetchBalanceTotal(),
|
||
fetchBDLeaderBill()
|
||
];
|
||
const results = await Promise.allSettled(tasks);
|
||
const rejected = results.find((item) => item.status === "rejected");
|
||
if (rejected) {
|
||
console.warn("BD leader center partial load failed:", rejected.reason);
|
||
showToast(rejected.reason?.response?.errorMsg || rejected.reason?.message || message("failed_to_load"));
|
||
}
|
||
} catch (error) {
|
||
console.error("Failed to initialize BD leader center:", error);
|
||
showToast(error.response?.errorMsg || error.message || message("failed_to_load"));
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
}
|
||
|
||
initializePage();
|
||
})();
|