chatapp-h5/h5/bd-static/shared.js
2026-04-24 21:13:53 +08:00

385 lines
13 KiB
JavaScript

export const API_BASE_URL = "https://jvapi.haiyihy.com";
const text = {
en: {
bd_leader_center: "BD Leader Center",
available_salaries: "Available salaries",
bd: "BD",
bd_leader: "BD Leader",
my_bd_salary: "My BD salary",
my_bd_leader_salary: "My BD leader salary",
exchange: "Exchange",
transfer: "Transfer",
cash_out: "Cash out",
details: "Details",
please_select_amount: "Please select amount",
please_select_coin_amount: "Please select coin amount",
please_select_payee: "Please select payee",
transfer_dollar_success: "Transfer succeeded",
transfer_dollar_failed: "Transfer failed",
transfer_error: "Transfer error",
exchange_success: "Exchange succeeded",
exchange_error_occurred: "Exchange failed",
amount: "Amount",
coins: "Coins",
dollar: "Dollar",
minimum_cash_out: "Minimum cash out is $50",
bd_policy_link: "BD policy",
bd_leader_policy: "BD leader policy",
bd_policy: "BD policy",
agency_list_link: "Agency list",
bd_list_link: "BD List",
invite_become_agent: "Invite to become agent",
invite_become_BD: "Invite to become BD",
bank_cards_link: "Bank cards",
bank_card: "Bank Card",
kyc: "KYC",
category: "Category",
card_number_label: "Card number",
card_number: "Card number",
payee: "Payee",
more: "More",
add_payment_method: "Add payment method",
complete_information: "Complete information",
passport_id_card_title: "Passport/ID card",
contact_number: "Contact number",
other_description: "Other description",
review_passed: "Review passed",
review_failed: "Review failed",
awaiting_review: "Awaiting review",
currently_in_use: "Currently in use",
all_bank_cards: "All bank cards",
no_bank_cards_in_use: "No bank cards in use",
no_bank_cards_added: "No bank cards added",
add_new_payment_method: "Add new payment method",
withdrawal_method: "Withdrawal method",
choose_withdrawal_method: "Choose withdrawal method",
card_name: "Card name",
enter_card_name: "Enter card name",
enter_card_number: "Enter card number",
enter_payee: "Enter payee",
delete: "Delete",
use: "Use",
using: "Using",
confirm: "Confirm",
submit: "Submit",
change_kyc: "Change KYC",
enter_contact_number: "Enter contact number",
enter_other_description: "Enter other description",
current_status: "Current status",
tips: "Tips",
confirm_modify_kyc: "Confirm modify KYC?",
cancel: "Cancel",
application_submitted: "Application submitted",
agency_number: "Agency number",
number_of_bd: "BD number",
bd_number: "BD number",
team_salary: "Team salary",
team_recharge: "Team recharge",
salary: "Salary",
recharge: "Recharge",
host: "Host",
agencies: "Agencies",
user_id_prefix: "ID: ",
revenue_details: "Revenue details",
bd_leader_history: "BD Leader history",
total_income: "Total income",
previous_period_income: "Previous period income",
income_details_label: "Income details",
team_top_up: "Team top up",
bd_income_salary: "BD income salary",
bd_income_top_up: "BD income top up",
total_team_salary: "Total team salary",
num_teams: "Num teams",
in_progress: "In Progress",
pending: "Pending",
completed: "Completed",
out_of_account: "Out of account",
information: "Information",
enter_user_id: "Enter User ID",
invite: "Invite",
no_users_found: "No users found",
success: "Success",
invitation_submitted: "Invitation submitted",
application_cancelled: "Application cancelled",
something_went_wrong: "Something went wrong",
cancellation_failed_try_again: "Cancellation failed, try again"
,
item_distribution: "Item distribution",
frames: "Frames",
vehicles: "Vehicles",
vip: "VIP",
send: "Send",
validity: "Validity",
day: " day",
enter_user_id_placeholder: "Enter user ID",
gift_delivery_successful: "Gift delivery successful",
available_salaries: "Available salaries",
details: "Details",
bd: "BD",
bd_leader: "BD Leader",
my_bd_salary: "My BD salary",
my_bd_leader_salary: "My BD leader salary",
exchange: "Exchange",
transfer: "Transfer",
cash_out: "Cash out",
please_select_amount: "Please select amount",
please_select_payee: "Please select payee",
transfer_dollar_success: "Transfer successful",
transfer_dollar_failed: "Transfer failed",
transfer_error: "Transfer error",
please_select_coin_amount: "Please select coin amount",
exchange_success: "Exchange successful",
exchange_error_occurred: "Exchange failed",
confirm_exchange: "Confirm exchange?",
fill_info_tips: "Please complete bank card and KYC information",
card_issue_tips: "Bank card information is required before cash out",
to_improve: "To improve",
cash_withdrawal_tips: "Cash withdrawal submitted",
enter_cash_out_amount: "Enter cash out amount",
cash_out_minimum: "Cash out minimum: $50",
change_withdrawal_method: "Change withdrawal method",
please_select_bank_card: "Please select bank card",
prompt: "Prompt",
failed_to_load_balance: "Failed to load balance"
},
ar: {},
tr: {},
bn: {}
};
["ar", "tr", "bn"].forEach((lang) => {
text[lang] = { ...text.en };
});
let headers = {
authorization: "Bearer undefined",
"req-app-intel": "version=1.0.0;build=1;model=SM-G9550;sysVersion=9;channel=Google",
"req-client": "Android",
"req-imei": "8fa54d728ab449e04f9292329ed44bda",
"req-lang": "id-ID",
"req-sys-origin": "origin=ATYOU;originChild=ATYOU",
"req-version": "V2",
"req-zone": "Asia/Shanghai",
"content-type": "application/json"
};
export const lang = resolveLanguage();
export function t(key) {
return text[lang]?.[key] || text.en[key] || key;
}
export function applyLang() {
document.documentElement.lang = lang;
document.documentElement.dir = lang === "ar" ? "rtl" : "ltr";
document.querySelectorAll("[data-i18n]").forEach((node) => {
node.textContent = t(node.dataset.i18n);
});
const language = document.querySelector("[data-action='language']");
if (language) language.textContent = lang.toUpperCase();
}
function resolveLanguage() {
const params = new URLSearchParams(window.location.search);
const hash = window.location.hash.includes("?") ? window.location.hash.split("?")[1] : "";
const hashParams = new URLSearchParams(hash);
const value = params.get("lang") || hashParams.get("lang") || navigator.language || "en";
if (value.startsWith("ar")) return "ar";
if (value.startsWith("tr")) return "tr";
if (value.startsWith("bn")) return "bn";
return "en";
}
function splitHeaderPairs(value) {
const result = {};
if (!value) return result;
value.split(";").forEach((item) => {
const index = item.indexOf("=");
if (index > -1) result[item.slice(0, index)] = item.slice(index + 1);
});
return result;
}
function parseAppHeaders(raw) {
const data = JSON.parse(raw);
const appIntel = splitHeaderPairs(data["Req-App-Intel"]);
const sysOrigin = splitHeaderPairs(data["Req-Sys-Origin"]);
return {
authorization: data.Authorization,
reqLang: data["Req-Lang"],
appVersion: appIntel.version,
buildVersion: appIntel.build,
channel: appIntel.channel,
reqImei: appIntel["Req-Imei"],
origin: sysOrigin.origin,
child: sysOrigin.child
};
}
export function setHeadersFromApp(rawOrObject) {
const data = typeof rawOrObject === "string" ? parseAppHeaders(rawOrObject) : rawOrObject || {};
const next = {};
if (data.authorization) next.authorization = data.authorization;
if (data.reqLang) next["req-lang"] = data.reqLang;
if (data.appVersion || data.buildVersion || data.channel) {
next["req-app-intel"] = [
data.appVersion ? `version=${data.appVersion}` : "",
data.buildVersion ? `build=${data.buildVersion}` : "",
data.channel ? `channel=${data.channel}` : ""
].filter(Boolean).join(";");
}
if (data.reqImei) next["req-imei"] = data.reqImei;
if (data.origin) next["req-sys-origin"] = [`origin=${data.origin}`, data.child ? `child=${data.child}` : ""].filter(Boolean).join(";");
headers = { ...headers, ...next };
}
export async function connectToApp() {
window.renderData = (raw) => raw && setHeadersFromApp(raw);
window.getIosAccessOriginParam = window.renderData;
if (window.app && typeof window.app.getAccessOrigin === "function") {
const raw = window.app.getAccessOrigin();
if (raw) setHeadersFromApp(raw);
return;
}
if (window.FlutterApp && typeof window.FlutterApp.postMessage === "function") {
window.FlutterApp.postMessage("requestAccessOrigin");
}
setHeadersFromApp({ reqLang: lang, authorization: "" });
}
export async function request(method, path, body) {
const options = { method, headers };
if (body !== undefined) options.body = JSON.stringify(body);
const response = await fetch(`${API_BASE_URL}${path}`, options);
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;
}
export const get = (path) => request("GET", path);
export const post = (path, body) => request("POST", path, body);
export function navigateTo(target) {
const url = new URL(target, window.location.origin);
const currentLang = new URLSearchParams(window.location.search).get("lang");
if (currentLang && !url.searchParams.has("lang")) url.searchParams.set("lang", currentLang);
window.location.href = `${url.pathname}${url.search}${url.hash}`;
}
export function closePage() {
if (window.history.length > 1) {
window.history.back();
return;
}
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");
}
}
export function bindHeader(titleKey) {
document.body.insertAdjacentHTML("afterbegin", `
<header class="header">
<button class="icon-btn" type="button" data-action="back" aria-label="Back"><img src="../bd-static/icons/back.svg" alt=""></button>
<h1>${t(titleKey)}</h1>
<button class="lang-btn" type="button" data-action="language">EN</button>
</header>
`);
document.querySelector("[data-action='back']").addEventListener("click", closePage);
document.querySelector("[data-action='language']").addEventListener("click", () => navigateTo("/language"));
applyLang();
}
export function money(value) {
if (value === null || value === undefined || value === "") return "0";
const number = Number(value);
if (Number.isNaN(number)) return String(value);
return Number.isInteger(number) ? String(number) : number.toFixed(2);
}
export function safeJsonArray(value) {
try {
const result = JSON.parse(value || "[]");
return Array.isArray(result) ? result : [];
} catch {
return [];
}
}
export function getUserId() {
const keys = ["userInfo", "user", "USER_INFO"];
for (const key of keys) {
try {
const raw = localStorage.getItem(key) || sessionStorage.getItem(key);
if (!raw) continue;
const data = JSON.parse(raw);
if (data.id || data.userId) return data.id || data.userId;
} catch {}
}
return "";
}
export function toast(message) {
let node = document.getElementById("toast");
if (!node) {
node = document.createElement("div");
node.id = "toast";
node.className = "toast";
document.body.appendChild(node);
}
node.textContent = message;
node.hidden = false;
window.clearTimeout(toast.timer);
toast.timer = window.setTimeout(() => {
node.hidden = true;
}, 2500);
}
export function createMask(content) {
const old = document.getElementById("modalMask");
if (old) old.remove();
const mask = document.createElement("div");
mask.id = "modalMask";
mask.className = "mask";
mask.addEventListener("click", () => mask.remove());
content.addEventListener("click", (event) => event.stopPropagation());
mask.appendChild(content);
document.body.appendChild(mask);
return mask;
}
export function statusClass(status) {
if (status === "Completed") return "completed";
if (status === "Pending") return "pending";
if (status === "Out of account" || status === "HANG_UP") return "out";
return "";
}
export function statusText(status) {
const map = {
SETTLED: t("completed"),
PAY_OUT: t("completed"),
UNPAID: t("in_progress"),
HANG_UP: t("out_of_account"),
"In Progress": t("in_progress"),
Pending: t("pending"),
Completed: t("completed"),
"Out of account": t("out_of_account")
};
return map[status] || status || "";
}
export function avatarError(img) {
img.addEventListener("error", () => {
img.removeAttribute("src");
});
}