453 lines
14 KiB
JavaScript
453 lines
14 KiB
JavaScript
const API_BASE_URL = "https://jvapi.haiyihy.com";
|
||
const icons = {
|
||
back: "./icons/back.svg",
|
||
arrow: "./icons/arrow.svg"
|
||
};
|
||
|
||
let commonHeaders = {
|
||
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"
|
||
};
|
||
|
||
const i18n = {
|
||
en: {
|
||
host_setting: "Host Setting",
|
||
bank_card: "Bank card",
|
||
more: "More",
|
||
add_payment_method: "Add payment method",
|
||
category: "Category",
|
||
card_number_label: "Card number",
|
||
payee: "Payee",
|
||
kyc: "KYC",
|
||
review_passed: "Review passed",
|
||
review_failed: "Review failed",
|
||
awaiting_review: "Awaiting review",
|
||
complete_information: "Complete information",
|
||
passport_id_card_title: "Passport / ID card",
|
||
contact_number: "Contact number",
|
||
other_description: "Other description",
|
||
something_went_wrong: "Something went wrong."
|
||
},
|
||
ar: {
|
||
host_setting: "إعدادات المضيف",
|
||
bank_card: "البطاقة البنكية",
|
||
more: "المزيد",
|
||
add_payment_method: "إضافة طريقة دفع",
|
||
category: "الفئة",
|
||
card_number_label: "رقم البطاقة",
|
||
payee: "المستفيد",
|
||
kyc: "KYC",
|
||
review_passed: "تمت الموافقة",
|
||
review_failed: "فشل التحقق",
|
||
awaiting_review: "بانتظار المراجعة",
|
||
complete_information: "إكمال المعلومات",
|
||
passport_id_card_title: "جواز السفر / الهوية",
|
||
contact_number: "رقم التواصل",
|
||
other_description: "وصف آخر",
|
||
something_went_wrong: "حدث خطأ ما."
|
||
},
|
||
tr: {
|
||
host_setting: "Host Ayarı",
|
||
bank_card: "Banka kartı",
|
||
more: "Daha fazla",
|
||
add_payment_method: "Ödeme yöntemi ekle",
|
||
category: "Kategori",
|
||
card_number_label: "Kart numarası",
|
||
payee: "Alacaklı",
|
||
kyc: "KYC",
|
||
review_passed: "İnceleme geçti",
|
||
review_failed: "İnceleme başarısız",
|
||
awaiting_review: "İnceleme bekliyor",
|
||
complete_information: "Bilgileri tamamla",
|
||
passport_id_card_title: "Pasaport / kimlik kartı",
|
||
contact_number: "İletişim numarası",
|
||
other_description: "Diğer açıklama",
|
||
something_went_wrong: "Bir şeyler ters gitti."
|
||
},
|
||
bn: {
|
||
host_setting: "হোস্ট সেটিং",
|
||
bank_card: "ব্যাংক কার্ড",
|
||
more: "আরও",
|
||
add_payment_method: "পেমেন্ট পদ্ধতি যোগ করুন",
|
||
category: "ক্যাটাগরি",
|
||
card_number_label: "কার্ড নম্বর",
|
||
payee: "প্রাপক",
|
||
kyc: "KYC",
|
||
review_passed: "রিভিউ পাস হয়েছে",
|
||
review_failed: "রিভিউ ব্যর্থ হয়েছে",
|
||
awaiting_review: "রিভিউ অপেক্ষমাণ",
|
||
complete_information: "তথ্য সম্পূর্ণ করুন",
|
||
passport_id_card_title: "পাসপোর্ট / আইডি কার্ড",
|
||
contact_number: "যোগাযোগ নম্বর",
|
||
other_description: "অন্যান্য বিবরণ",
|
||
something_went_wrong: "কিছু ভুল হয়েছে।"
|
||
}
|
||
};
|
||
|
||
const state = {
|
||
lang: resolveLanguage(),
|
||
bankCard: null,
|
||
withdrawInfo: null,
|
||
profile: {}
|
||
};
|
||
|
||
const $ = (selector) => document.querySelector(selector);
|
||
const $$ = (selector) => Array.from(document.querySelectorAll(selector));
|
||
const t = (key) => (i18n[state.lang] && i18n[state.lang][key]) || i18n.en[key] || key;
|
||
|
||
function resolveLanguage() {
|
||
const params = new URLSearchParams(window.location.search);
|
||
const hashQuery = window.location.hash.includes("?") ? window.location.hash.split("?")[1] : "";
|
||
const hashParams = new URLSearchParams(hashQuery);
|
||
const lang = params.get("lang") || hashParams.get("lang") || navigator.language || "en";
|
||
if (lang.startsWith("ar")) return "ar";
|
||
if (lang.startsWith("tr")) return "tr";
|
||
if (lang.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 parseAccessOrigin(raw) {
|
||
const data = JSON.parse(raw);
|
||
const appIntel = splitHeaderPairs(data["Req-App-Intel"]);
|
||
const sysOrigin = splitHeaderPairs(data["Req-Sys-Origin"]);
|
||
return {
|
||
reqLang: data["Req-Lang"],
|
||
authorization: data.Authorization,
|
||
buildVersion: appIntel.build,
|
||
appVersion: appIntel.version,
|
||
appChannel: appIntel.channel,
|
||
reqImei: appIntel["Req-Imei"],
|
||
sysOrigin: sysOrigin.origin,
|
||
sysOriginChild: sysOrigin.child
|
||
};
|
||
}
|
||
|
||
function setHeadersFromApp(headers) {
|
||
const next = {};
|
||
if (headers.authorization) next.authorization = headers.authorization;
|
||
if (headers.reqLang) next["req-lang"] = headers.reqLang;
|
||
if (headers.appVersion || headers.buildVersion || headers.appChannel) {
|
||
const intel = [];
|
||
if (headers.appVersion) intel.push(`version=${headers.appVersion}`);
|
||
if (headers.buildVersion) intel.push(`build=${headers.buildVersion}`);
|
||
if (headers.appChannel) intel.push(`channel=${headers.appChannel}`);
|
||
next["req-app-intel"] = intel.join(";");
|
||
}
|
||
if (headers.reqImei) next["req-imei"] = headers.reqImei;
|
||
if (headers.sysOrigin) {
|
||
const origin = [`origin=${headers.sysOrigin}`];
|
||
if (headers.sysOriginChild) origin.push(`child=${headers.sysOriginChild}`);
|
||
next["req-sys-origin"] = origin.join(";");
|
||
}
|
||
commonHeaders = { ...commonHeaders, ...next };
|
||
}
|
||
|
||
function connectToApp() {
|
||
return new Promise((resolve) => {
|
||
window.renderData = resolve;
|
||
window.getIosAccessOriginParam = resolve;
|
||
|
||
if (!(window.app || window.webkit || window.FlutterPageControl)) {
|
||
resolve({ success: true, environment: "browser" });
|
||
return;
|
||
}
|
||
|
||
let attempt = 0;
|
||
const poll = () => {
|
||
attempt += 1;
|
||
if (window.app && typeof window.app.getAccessOrigin === "function") {
|
||
const raw = window.app.getAccessOrigin();
|
||
if (raw) setHeadersFromApp(parseAccessOrigin(raw));
|
||
resolve({ success: true, environment: "app" });
|
||
return;
|
||
}
|
||
if (attempt < 50) {
|
||
window.setTimeout(poll, 100);
|
||
return;
|
||
}
|
||
if (window.FlutterApp && typeof window.FlutterApp.postMessage === "function") {
|
||
window.FlutterApp.postMessage("requestAccessOrigin");
|
||
}
|
||
resolve({ success: true, environment: "app" });
|
||
};
|
||
poll();
|
||
}).then((result) => {
|
||
if (typeof result === "string") {
|
||
setHeadersFromApp(parseAccessOrigin(result));
|
||
return { success: true, environment: "app" };
|
||
}
|
||
return result;
|
||
});
|
||
}
|
||
|
||
async function apiGet(path) {
|
||
const response = await fetch(`${API_BASE_URL}${path}`, {
|
||
method: "GET",
|
||
headers: commonHeaders
|
||
});
|
||
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;
|
||
}
|
||
|
||
async function fetchUserProfile() {
|
||
const cached = localStorage.getItem("userProfile");
|
||
if (cached) {
|
||
try {
|
||
state.profile = JSON.parse(cached) || {};
|
||
} catch (error) {
|
||
console.error("Failed to parse userProfile:", error);
|
||
}
|
||
}
|
||
try {
|
||
const result = await apiGet("/team/member/profile");
|
||
if (result.status && result.body) {
|
||
state.profile = result.body;
|
||
localStorage.setItem("userProfile", JSON.stringify(result.body));
|
||
}
|
||
} catch (error) {
|
||
console.error("Failed to fetch user profile:", error);
|
||
}
|
||
}
|
||
|
||
function getMemberId() {
|
||
return state.profile.id || state.profile.userId || state.profile.account || null;
|
||
}
|
||
|
||
function calculateRoles(identity) {
|
||
if (!identity) return ["guest"];
|
||
const roles = [];
|
||
if (identity.freightAgent) roles.push("freightAgent");
|
||
if (identity.agent) roles.push("agent");
|
||
if (identity.bdLeader) roles.push("bdLeader");
|
||
if (identity.bd) roles.push("bd");
|
||
if (identity.anchor) roles.push("anchor");
|
||
if (identity.admin) roles.push("admin");
|
||
return roles.length ? roles : ["guest"];
|
||
}
|
||
|
||
function getPrimaryRole(roles) {
|
||
const weight = {
|
||
guest: 0,
|
||
anchor: 1,
|
||
agent: 2,
|
||
bd: 3,
|
||
bdLeader: 4,
|
||
freightAgent: 5,
|
||
admin: 6
|
||
};
|
||
return roles.reduce((current, role) => (weight[role] > weight[current] ? role : current), "guest");
|
||
}
|
||
|
||
function getDefaultPage(role) {
|
||
return {
|
||
admin: "/admin-center",
|
||
freightAgent: "/coin-seller",
|
||
agent: "/agency-center",
|
||
bdLeader: "/bd-leader-center",
|
||
bd: "/bd-center",
|
||
anchor: "/host-center",
|
||
guest: "/apply"
|
||
}[role] || "/apply";
|
||
}
|
||
|
||
async function checkIdentityAndRedirect() {
|
||
const memberId = getMemberId();
|
||
if (!memberId) {
|
||
navigateTo("/apply");
|
||
return;
|
||
}
|
||
const result = await apiGet("/app/h5/identity");
|
||
if (!result.status || !result.body) return;
|
||
const roles = calculateRoles(result.body);
|
||
if (!roles.includes("anchor")) {
|
||
navigateTo(getDefaultPage(getPrimaryRole(roles)));
|
||
}
|
||
}
|
||
|
||
async function fetchBankCards() {
|
||
const result = await apiGet("/wallet/bank-card/list");
|
||
if (result.status && result.body) {
|
||
state.bankCard = result.body.find((item) => item.use) || null;
|
||
}
|
||
}
|
||
|
||
async function fetchWithdrawInfo() {
|
||
const result = await apiGet("/wallet/withdraw-info/list");
|
||
if (result.status && result.body && result.body.length > 0) {
|
||
const first = result.body[0];
|
||
let previewUrls = [];
|
||
try {
|
||
previewUrls = JSON.parse(first.passportFrontUrl || "[]").map((item) => item);
|
||
} catch (error) {
|
||
console.error("Failed to parse passportFrontUrl:", error);
|
||
}
|
||
state.withdrawInfo = { previewUrls, ...first };
|
||
}
|
||
}
|
||
|
||
function normalizeRoute(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);
|
||
return `${url.pathname}${url.search}${url.hash}`;
|
||
}
|
||
|
||
function navigateTo(target) {
|
||
window.location.href = normalizeRoute(target);
|
||
}
|
||
|
||
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");
|
||
}
|
||
}
|
||
|
||
function showToast(message) {
|
||
const toast = $("#toast");
|
||
toast.textContent = message;
|
||
toast.hidden = false;
|
||
window.clearTimeout(showToast.timer);
|
||
showToast.timer = window.setTimeout(() => {
|
||
toast.hidden = true;
|
||
}, 2500);
|
||
}
|
||
|
||
function renderI18n() {
|
||
document.documentElement.lang = state.lang;
|
||
document.documentElement.dir = state.lang === "ar" ? "rtl" : "ltr";
|
||
$("[data-action='language']").textContent = state.lang.toUpperCase();
|
||
$$("[data-i18n]").forEach((node) => {
|
||
node.textContent = t(node.dataset.i18n);
|
||
});
|
||
}
|
||
|
||
function renderIcons() {
|
||
$("#backIcon").src = icons.back;
|
||
["#bankAddArrow", "#kycHeaderArrow", "#kycAddArrow"].forEach((selector) => {
|
||
$(selector).src = icons.arrow;
|
||
});
|
||
}
|
||
|
||
function renderBankCard() {
|
||
const hasCard = Boolean(state.bankCard);
|
||
$("#bankMoreButton").hidden = !hasCard;
|
||
$("#addBankCardRow").hidden = hasCard;
|
||
$("#bankDetail").hidden = !hasCard;
|
||
if (!hasCard) return;
|
||
$("#cardType").textContent = state.bankCard.cardType || "-";
|
||
$("#cardNo").textContent = state.bankCard.cardNo || "-";
|
||
$("#payee").textContent = state.bankCard.payee || "-";
|
||
}
|
||
|
||
function renderKyc() {
|
||
const info = state.withdrawInfo;
|
||
const hasInfo = Boolean(info);
|
||
$("#kycColon").hidden = !hasInfo;
|
||
$("#kycStatus").hidden = !hasInfo;
|
||
$("#kycHeaderButton").hidden = !hasInfo;
|
||
$("#completeKycRow").hidden = hasInfo;
|
||
$("#kycDetail").hidden = !hasInfo;
|
||
if (!hasInfo) return;
|
||
|
||
const status = $("#kycStatus");
|
||
status.className = "status-text";
|
||
if (info.status === "PASS") {
|
||
status.textContent = t("review_passed");
|
||
status.classList.add("status-pass");
|
||
} else if (info.status === "NOT_PASS") {
|
||
status.textContent = t("review_failed");
|
||
status.classList.add("status-failed");
|
||
} else if (info.status === "PENDING") {
|
||
status.textContent = t("awaiting_review");
|
||
status.classList.add("status-pending");
|
||
} else {
|
||
status.textContent = info.status || "";
|
||
}
|
||
|
||
const previewList = $("#previewList");
|
||
previewList.innerHTML = "";
|
||
(info.previewUrls || []).forEach((url) => {
|
||
const image = document.createElement("img");
|
||
image.src = url;
|
||
image.alt = "";
|
||
previewList.appendChild(image);
|
||
});
|
||
$("#contactNumber").textContent = info.contactNumber || "-";
|
||
$("#otherDescription").textContent = info.otherDescription || "-";
|
||
}
|
||
|
||
function render() {
|
||
renderI18n();
|
||
renderIcons();
|
||
renderBankCard();
|
||
renderKyc();
|
||
}
|
||
|
||
function bindEvents() {
|
||
$("[data-action='back']").addEventListener("click", closePage);
|
||
$("[data-action='language']").addEventListener("click", () => navigateTo("/language"));
|
||
$$("[data-route]").forEach((node) => {
|
||
node.addEventListener("click", () => navigateTo(node.dataset.route));
|
||
});
|
||
}
|
||
|
||
async function runTask(task, label) {
|
||
try {
|
||
await task();
|
||
} catch (error) {
|
||
console.error(`${label} failed:`, error);
|
||
if (label === "withdraw info") showToast(error.response?.errorMsg || error.message || t("something_went_wrong"));
|
||
}
|
||
}
|
||
|
||
async function init() {
|
||
localStorage.setItem("identity", JSON.stringify({ identity: "HOST" }));
|
||
bindEvents();
|
||
render();
|
||
try {
|
||
await connectToApp();
|
||
await fetchUserProfile();
|
||
await runTask(checkIdentityAndRedirect, "identity check");
|
||
await Promise.all([
|
||
runTask(fetchBankCards, "bank cards"),
|
||
runTask(fetchWithdrawInfo, "withdraw info")
|
||
]);
|
||
} catch (error) {
|
||
console.error("Host setting initialization failed:", error);
|
||
showToast(error.response?.errorMsg || error.message || t("something_went_wrong"));
|
||
} finally {
|
||
render();
|
||
}
|
||
}
|
||
|
||
init();
|