chatapp-h5/h5/search-payee/search-payee.js
2026-04-24 21:13:53 +08:00

388 lines
12 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const API_BASE_URL = "https://jvapi.haiyihy.com";
const DEFAULT_AVATAR = "/assets/defaultAvatar-CdxWBK1k-1776148661448.png";
const PAYEE_KEY = "transfer.payee";
const icons = {
back: "../host-center/icons/back.svg",
search: "./icons/search.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: {
search_payee: "Search Payee",
search_user: "Search user",
search: "Search",
cancel: "Cancel",
searching: "Searching",
tips: "Tips",
confirm_transfer_to_user: "Confirm transfer to this user?",
confirm: "Confirm",
add: "Add",
user_id_prefix: "ID:",
user_not_found_or_search_failed: "User not found or search failed"
},
ar: {
search_payee: "بحث عن المستلم",
search_user: "ابحث عن المستخدم",
search: "بحث",
cancel: "إلغاء",
searching: "جاري البحث",
tips: "نصائح",
confirm_transfer_to_user: "تأكيد التحويل إلى هذا المستخدم؟",
confirm: "تأكيد",
add: "إضافة",
user_id_prefix: "ID:",
user_not_found_or_search_failed: "لم يتم العثور على المستخدم أو فشل البحث"
},
tr: {
search_payee: "Alıcı Ara",
search_user: "Kullanıcı ara",
search: "Ara",
cancel: "İptal",
searching: "Aranıyor",
tips: "İpuçları",
confirm_transfer_to_user: "Bu kullanıcıya transferi onaylıyor musunuz?",
confirm: "Onayla",
add: "Ekle",
user_id_prefix: "ID:",
user_not_found_or_search_failed: "Kullanıcı bulunamadı veya arama başarısız"
},
bn: {
search_payee: "প্রাপক সার্চ",
search_user: "ব্যবহারকারী সার্চ",
search: "সার্চ",
cancel: "বাতিল",
searching: "সার্চ হচ্ছে",
tips: "টিপস",
confirm_transfer_to_user: "এই ব্যবহারকারীকে ট্রান্সফার নিশ্চিত করবেন?",
confirm: "নিশ্চিত",
add: "যোগ",
user_id_prefix: "ID:",
user_not_found_or_search_failed: "ব্যবহারকারী পাওয়া যায়নি বা সার্চ ব্যর্থ"
}
};
const state = {
lang: resolveLanguage(),
query: "",
results: [],
loading: false,
searched: false,
selected: null
};
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 lang = params.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)) {
setHeadersFromApp({
authorization: "",
reqLang: state.lang,
appVersion: "1.0.0",
buildVersion: "1",
appChannel: "Web",
reqImei: "H5-STATIC",
sysOrigin: "LIKEI",
sysOriginChild: "LIKEI"
});
resolve({ success: true });
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 });
return;
}
if (attempt < 50) {
window.setTimeout(poll, 100);
return;
}
if (window.FlutterApp && typeof window.FlutterApp.postMessage === "function") {
window.FlutterApp.postMessage("requestAccessOrigin");
}
resolve({ success: true });
};
poll();
}).then((result) => {
if (typeof result === "string") setHeadersFromApp(parseAccessOrigin(result));
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 || `HTTP ${response.status}`);
error.response = data;
throw error;
}
return data;
}
async function searchPayee() {
const query = $("#searchInput").value.trim();
state.query = query;
if (!query) {
state.results = [];
renderResults();
return;
}
state.loading = true;
state.searched = false;
renderResults();
try {
const result = await apiGet(`/wallet/bank/search/user-profile?account=${encodeURIComponent(query)}&type=AGENT&searchType=TRANSFER`);
if (result.status && result.body) {
state.results = [{
id: result.body.id,
account: result.body.account,
name: result.body.userNickname,
avatar: result.body.userAvatar,
sex: result.body.userSex,
age: result.body.age,
countryName: result.body.countryName,
countryCode: result.body.countryCode,
accountStatus: result.body.accountStatus,
goodID: result.body.ownSpecialId?.account
}];
} else {
state.results = [];
}
} catch (error) {
console.error("Search failed:", error);
state.results = [];
showToast(t("user_not_found_or_search_failed"));
} finally {
state.loading = false;
state.searched = true;
renderResults();
}
}
function resetSearch() {
state.searched = false;
state.query = "";
state.results = [];
$("#searchInput").value = "";
renderResults();
}
function showToast(message) {
const toast = $("#toast");
toast.textContent = message || "Request failed";
toast.hidden = false;
window.clearTimeout(showToast.timer);
showToast.timer = window.setTimeout(() => {
toast.hidden = true;
}, 2500);
}
function showConfirm(user) {
state.selected = user;
$("#confirmModal").hidden = false;
}
function hideConfirm() {
state.selected = null;
$("#confirmModal").hidden = true;
}
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 goBackToTransfer() {
const from = new URLSearchParams(window.location.search).get("from") || "/transfer";
window.location.href = normalizeRoute(from);
}
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 renderI18n() {
document.documentElement.lang = state.lang;
document.documentElement.dir = state.lang === "ar" ? "rtl" : "ltr";
$(".lang-button").textContent = state.lang.toUpperCase();
$$("[data-i18n]").forEach((node) => {
node.textContent = t(node.dataset.i18n);
});
$$("[data-i18n-placeholder]").forEach((node) => {
node.placeholder = t(node.dataset.i18nPlaceholder);
});
}
function renderIcons() {
$("#backIcon").src = icons.back;
$("#searchIcon").src = icons.search;
}
function renderSearchActions() {
const hasQuery = Boolean($("#searchInput").value.trim());
$("#searchButton").hidden = state.searched || !hasQuery;
$("#cancelButton").hidden = !state.searched && !hasQuery;
}
function renderResults() {
$("#loadingState").hidden = !state.loading;
renderSearchActions();
const root = $("#results");
root.innerHTML = "";
if (state.loading) return;
state.results.forEach((user) => {
const card = document.createElement("div");
card.className = "result-card";
card.innerHTML = `
<div class="result-row">
<div class="result-main">
<div class="avatar-wrap"><img src="${user.avatar || ""}" alt="" /></div>
<div class="result-info">
<div class="result-name"></div>
<div class="result-id"><span>${t("user_id_prefix")}</span> <span></span></div>
</div>
</div>
<button class="add-button" type="button">${t("add")}</button>
</div>`;
card.querySelector(".result-name").textContent = user.name;
card.querySelector(".result-id span:last-child").textContent = user.goodID || user.account || "-";
card.querySelector(".add-button").addEventListener("click", () => showConfirm(user));
card.querySelector("img").addEventListener("error", (event) => {
event.target.onerror = null;
event.target.src = DEFAULT_AVATAR;
});
root.appendChild(card);
});
}
function render() {
renderI18n();
renderIcons();
renderResults();
}
function bindEvents() {
$("[data-action='back']").addEventListener("click", closePage);
$(".lang-button").addEventListener("click", () => {
window.location.href = normalizeRoute("/language");
});
$("#searchInput").addEventListener("input", () => {
if (state.searched) state.searched = false;
renderSearchActions();
});
$("#searchInput").addEventListener("keyup", (event) => {
if (event.key === "Enter") searchPayee();
});
$("#searchButton").addEventListener("click", searchPayee);
$("#cancelButton").addEventListener("click", resetSearch);
$("#confirmModal").addEventListener("click", hideConfirm);
$(".modal-card").addEventListener("click", (event) => event.stopPropagation());
$("[data-action='cancel-select']").addEventListener("click", hideConfirm);
$("[data-action='confirm-select']").addEventListener("click", () => {
if (!state.selected) return;
sessionStorage.setItem(PAYEE_KEY, JSON.stringify(state.selected));
hideConfirm();
goBackToTransfer();
});
}
async function init() {
bindEvents();
render();
await connectToApp();
}
init();