(function () { const API_BASE_URL = "https://jvapi.haiyihy.com"; const RECHARGE_APPLICATION_ID = "1963531459019739137"; const supportedLanguages = ["en", "ar", "tr", "id"]; const languageLabels = { en: "EN", ar: "AR", tr: "TR", id: "ID" }; const messages = { en: { document_title: "Recharge Center", page_label: "Recharge Center", back: "Back", title: "Recharge Center", language_button_aria: "Change language", help: "Help", close: "Close", search_title: "Recharge user", search_subtitle: "Search by user ID", search_placeholder: "Enter user ID", search: "Search", searching: "Searching...", target_user: "Target user", uid_prefix: "UID:", change: "Change", select_country: "Select a country", payment_methods: "Payment methods", select_package: "Select a package", loading_data: "Loading...", no_country: "No supported country", no_packages: "No recharge packages", user_not_found: "User info not found", missing_token: "Missing token", failed_to_load: "Failed to load data", payment_not_available: "Payment not available", creating_order: "Creating order...", redirecting_payment: "Redirecting to payment...", order_created: "Order created", faq_title: "FAQ", faq_question_1: "How to recharge?", faq_answer_1: "Enter the user's ID, choose a package, then select a payment method.", faq_question_2: "How to check recharge result?", faq_answer_2: "After payment, return to the app and check the user's wallet balance." }, ar: { document_title: "Recharge Center", page_label: "Recharge Center", back: "Back", title: "Recharge Center", language_button_aria: "Change language", help: "Help", close: "Close", search_title: "Recharge user", search_subtitle: "Search by user ID", search_placeholder: "Enter user ID", search: "Search", searching: "Searching...", target_user: "Target user", uid_prefix: "UID:", change: "Change", select_country: "Select a country", payment_methods: "Payment methods", select_package: "Select a package", loading_data: "Loading...", no_country: "No supported country", no_packages: "No recharge packages", user_not_found: "User info not found", missing_token: "Missing token", failed_to_load: "Failed to load data", payment_not_available: "Payment not available", creating_order: "Creating order...", redirecting_payment: "Redirecting to payment...", order_created: "Order created", faq_title: "FAQ", faq_question_1: "How to recharge?", faq_answer_1: "Enter the user's ID, choose a package, then select a payment method.", faq_question_2: "How to check recharge result?", faq_answer_2: "After payment, return to the app and check the user's wallet balance." }, tr: { document_title: "Recharge Center", page_label: "Recharge Center", back: "Geri", title: "Recharge Center", language_button_aria: "Dili degistir", help: "Help", close: "Kapat", search_title: "Recharge user", search_subtitle: "Kullanici ID ile ara", search_placeholder: "Kullanici ID gir", search: "Ara", searching: "Araniyor...", target_user: "Target user", uid_prefix: "UID:", change: "Degistir", select_country: "Ulke sec", payment_methods: "Payment methods", select_package: "Paket sec", loading_data: "Yukleniyor...", no_country: "Desteklenen ulke yok", no_packages: "Recharge package yok", user_not_found: "Kullanici bulunamadi", missing_token: "Token eksik", failed_to_load: "Veri yuklenemedi", payment_not_available: "Payment not available", creating_order: "Order olusturuluyor...", redirecting_payment: "Payment sayfasina yonlendiriliyor...", order_created: "Order created", faq_title: "FAQ", faq_question_1: "How to recharge?", faq_answer_1: "Enter the user's ID, choose a package, then select a payment method.", faq_question_2: "How to check recharge result?", faq_answer_2: "After payment, return to the app and check the user's wallet balance." }, id: { document_title: "Recharge Center", page_label: "Recharge Center", back: "Kembali", title: "Recharge Center", language_button_aria: "Ubah bahasa", help: "Help", close: "Tutup", search_title: "Recharge user", search_subtitle: "Cari dengan user ID", search_placeholder: "Masukkan user ID", search: "Cari", searching: "Mencari...", target_user: "Target user", uid_prefix: "UID:", change: "Ganti", select_country: "Pilih negara", payment_methods: "Payment methods", select_package: "Pilih paket", loading_data: "Memuat...", no_country: "Negara tidak tersedia", no_packages: "Paket recharge tidak tersedia", user_not_found: "User tidak ditemukan", missing_token: "Token tidak ditemukan", failed_to_load: "Gagal memuat data", payment_not_available: "Payment not available", creating_order: "Membuat order...", redirecting_payment: "Membuka payment...", order_created: "Order created", faq_title: "FAQ", faq_question_1: "How to recharge?", faq_answer_1: "Enter the user's ID, choose a package, then select a payment method.", faq_question_2: "How to check recharge result?", faq_answer_2: "After payment, return to the app and check the user's wallet balance." } }; const params = readURLParams(); let currentLang = normalizeLanguage(params.get("lang")); let currentMessages = messages[currentLang] || messages.en; const state = { query: params.get("account") || params.get("targetAccount") || params.get("target") || "", searchLocked: false, loadingConfig: false, ordering: false, activeOrderKey: "", searchStatusText: "", searchStatusType: "", paymentStatusText: "", paymentStatusType: "", profile: null, application: null, appCode: "", rechargeType: "GOLD", payProfile: null, countryList: [], selectedCountryId: "", regionId: "", commodity: [], channels: [] }; 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] || messages.en[key] || fallback || key; } function renderMessages(dictionary) { document.querySelectorAll("[data-i18n]").forEach((node) => { const value = dictionary[node.dataset.i18n] || messages.en[node.dataset.i18n]; if (value) node.textContent = value; }); document.querySelectorAll("[data-i18n-aria]").forEach((node) => { const value = dictionary[node.dataset.i18nAria] || messages.en[node.dataset.i18nAria]; if (value) node.setAttribute("aria-label", value); }); document.querySelectorAll("[data-i18n-placeholder]").forEach((node) => { const value = dictionary[node.dataset.i18nPlaceholder] || messages.en[node.dataset.i18nPlaceholder]; if (value) node.setAttribute("placeholder", 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, options = {}) { const token = readRawParam("token"); if (!token) throw new Error(message("missing_token")); const headers = authHeadersFromToken(token); const request = { method: options.method || "GET", cache: "no-store", headers }; if (options.body !== undefined) { headers["Content-Type"] = "application/json"; request.body = JSON.stringify(options.body); } const response = await fetch(new URL(path, `${apiBaseURL()}/`).toString(), request); 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 endpointOpenSearch(account) { return `/user/user-profile/open-search?account=${encodeURIComponent(account)}`; } function endpointApplication() { return `/order/web/pay/application/${encodeURIComponent(RECHARGE_APPLICATION_ID)}`; } function endpointPayProfile(appCode, account, type) { const query = new URLSearchParams({ sysOrigin: appCode, account, type }); return `/order/web/pay/user-profile?${query.toString()}`; } function endpointCommodity(countryId, regionId, type) { const query = new URLSearchParams({ applicationId: RECHARGE_APPLICATION_ID, payCountryId: countryId, regionId: regionId || "", type }); return `/order/web/pay/commodity?${query.toString()}`; } function setLoading(isLoading) { const root = document.querySelector(".recharge-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(".help-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 replaceChildren(node, children) { while (node.firstChild) node.removeChild(node.firstChild); children.forEach((child) => node.appendChild(child)); } function formatMoney(value) { const number = Number(value); if (!Number.isFinite(number)) return "0.00"; return number.toFixed(2); } 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 pickDisplayAccount(profile) { return pickSpecialAccount(profile) || profile?.account || profile?.id || "-"; } function pickApiAccount(profile) { return profile?.account || state.query || pickSpecialAccount(profile) || ""; } function pickProfileId(profile) { return profile?.id || profile?.userId || ""; } function commodityType(profile = state.profile) { if (profile?.isSuperFreightAgent) return "FREIGHT_GOLD_SUPER"; if (profile?.isFreightAgent) return "FREIGHT_GOLD"; return "GOLD"; } function setSearchStatus(text = "", type = "") { state.searchStatusText = text; state.searchStatusType = type; const status = document.querySelector("#searchStatus"); if (!status) return; status.textContent = text; status.hidden = !text; status.classList.toggle("is-error", type === "error"); } function setPaymentStatus(text = "", type = "") { state.paymentStatusText = text; state.paymentStatusType = type; const status = document.querySelector("#paymentStatus"); if (!status) return; status.textContent = text; status.hidden = !text; status.classList.toggle("is-error", type === "error"); } function renderSearch() { const input = document.querySelector("#accountInput"); const button = document.querySelector("#searchButton"); if (input && document.activeElement !== input) input.value = state.query; if (button) { const hasQuery = Boolean(String(state.query || "").trim()); button.disabled = state.searchLocked || !hasQuery; button.textContent = state.searchLocked ? message("searching") : message("search"); } setSearchStatus(state.searchStatusText, state.searchStatusType); } function renderAvatar(profile) { const image = document.querySelector("#targetAvatar"); const fallback = document.querySelector("#targetAvatarFallback"); if (!image || !fallback) return; const name = pickProfileName(profile); const avatar = profile?.userAvatar || profile?.avatar || ""; fallback.textContent = String(name || "U").slice(0, 1).toUpperCase() || "U"; 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 renderTarget() { const card = document.querySelector("#targetCard"); if (card) card.hidden = !state.profile; if (!state.profile) return; const nameNode = document.querySelector("#targetName"); const uidNode = document.querySelector("#targetUid"); if (nameNode) nameNode.textContent = pickProfileName(state.profile); if (uidNode) uidNode.textContent = `${message("uid_prefix")} ${pickDisplayAccount(state.profile)}`.trim(); renderAvatar(state.profile); } function countryName(item) { return item?.countryName || item?.country?.aliasName || item?.country?.countryName || item?.name || "-"; } function countryFlag(item) { return item?.nationalFlag || item?.country?.nationalFlag || item?.flag || ""; } function selectedCountry() { return state.countryList.find((item) => String(item?.id) === String(state.selectedCountryId)) || state.countryList[0] || null; } function createCountryChip(item) { const button = document.createElement("button"); button.className = "country-chip"; button.type = "button"; const active = String(item?.id) === String(state.selectedCountryId); button.classList.toggle("is-active", active); button.disabled = state.loadingConfig || state.ordering; button.addEventListener("click", () => selectCountry(item?.id)); const flag = document.createElement("span"); flag.className = "country-flag"; const flagUrl = countryFlag(item); if (flagUrl) { const image = document.createElement("img"); image.src = flagUrl; image.alt = ""; image.addEventListener("error", () => { flag.textContent = String(countryName(item)).slice(0, 2).toUpperCase(); }); flag.appendChild(image); } else { flag.textContent = String(countryName(item)).slice(0, 2).toUpperCase(); } const name = document.createElement("span"); name.className = "country-name"; name.textContent = countryName(item); button.append(flag, name); return button; } function renderCountries() { const card = document.querySelector("#countryCard"); const list = document.querySelector("#countryList"); const subtitle = document.querySelector("#countrySubtitle"); if (card) card.hidden = !state.profile; if (!list || !state.profile) return; const country = selectedCountry(); if (subtitle) subtitle.textContent = country ? countryName(country) : message("no_country"); if (state.loadingConfig && !state.countryList.length) { const loading = document.createElement("div"); loading.className = "empty-state"; loading.textContent = message("loading_data"); replaceChildren(list, [loading]); return; } if (!state.countryList.length) { const empty = document.createElement("div"); empty.className = "empty-state"; empty.textContent = message("no_country"); replaceChildren(list, [empty]); return; } replaceChildren(list, state.countryList.map(createCountryChip)); } function channelCode(item) { return item?.channel?.channelCode || item?.details?.channelCode || item?.channelCode || ""; } function channelName(item) { return item?.channel?.channelName || item?.channelName || channelCode(item) || "-"; } function channelIcon(item) { return item?.channel?.channelIcon || item?.channelIcon || ""; } function createChannelIcon(item) { const icon = document.createElement("div"); icon.className = "channel-icon"; const url = channelIcon(item); if (!url) { icon.textContent = String(channelName(item)).slice(0, 1).toUpperCase(); return icon; } const image = document.createElement("img"); image.src = url; image.alt = ""; image.addEventListener("error", () => { icon.textContent = String(channelName(item)).slice(0, 1).toUpperCase(); }); icon.appendChild(image); return icon; } function packageKey(channel, goods) { return `${channelCode(channel)}:${goods?.id || ""}`; } function createPackageButton(channel, goods) { const button = document.createElement("button"); button.className = "package-button"; button.type = "button"; const key = packageKey(channel, goods); button.disabled = state.ordering || state.loadingConfig; button.addEventListener("click", () => placeOrder(channel, goods)); const coin = document.createElement("span"); coin.className = "coin-mark"; coin.textContent = "$"; const content = document.createElement("span"); content.className = "package-content"; content.textContent = goods?.content || goods?.awardContent || "-"; const price = document.createElement("span"); price.className = "package-price"; price.textContent = state.ordering && state.activeOrderKey === key ? message("creating_order") : `$${formatMoney(goods?.amountUsd)}`; button.append(coin, content, price); return button; } function createChannelCard(item) { const card = document.createElement("article"); card.className = "channel-card"; const head = document.createElement("div"); head.className = "channel-head"; const name = document.createElement("div"); name.className = "channel-name"; name.textContent = channelName(item); head.append(createChannelIcon(item), name); const grid = document.createElement("div"); grid.className = "package-grid"; state.commodity.forEach((goods) => grid.appendChild(createPackageButton(item, goods))); card.append(head, grid); return card; } function renderPayment() { const card = document.querySelector("#paymentCard"); const list = document.querySelector("#channelList"); if (card) card.hidden = !state.profile; if (!list || !state.profile) return; setPaymentStatus(state.paymentStatusText, state.paymentStatusType); if (state.loadingConfig) { const loading = document.createElement("div"); loading.className = "empty-state"; loading.textContent = message("loading_data"); replaceChildren(list, [loading]); return; } if (!state.channels.length || !state.commodity.length) { const empty = document.createElement("div"); empty.className = "empty-state"; empty.textContent = message("no_packages"); replaceChildren(list, [empty]); return; } replaceChildren(list, state.channels.map(createChannelCard)); } function renderAll() { renderSearch(); renderTarget(); renderCountries(); renderPayment(); } async function fetchApplication() { state.application = await requestJSON(endpointApplication()) || {}; state.appCode = state.application.appCode || ""; return state.application; } async function fetchRechargeProfile() { if (!state.application || !state.appCode) await fetchApplication(); const account = pickApiAccount(state.profile); state.rechargeType = commodityType(state.profile); const data = await requestJSON(endpointPayProfile(state.appCode, account, state.rechargeType)); state.payProfile = data?.userProfile || null; state.countryList = Array.isArray(data?.countryList) ? data.countryList : []; state.regionId = data?.regionId || ""; if (state.payProfile) { state.profile = { ...state.profile, ...state.payProfile, isFreightAgent: state.profile?.isFreightAgent, isSuperFreightAgent: state.profile?.isSuperFreightAgent }; } if (!state.countryList.some((item) => String(item?.id) === String(state.selectedCountryId))) { state.selectedCountryId = state.countryList[0]?.id ? String(state.countryList[0].id) : ""; } } async function fetchCommodities() { const country = selectedCountry(); if (!country?.id) { state.commodity = []; state.channels = []; return; } const data = await requestJSON(endpointCommodity(String(country.id), state.regionId, state.rechargeType)); state.commodity = Array.isArray(data?.commodity) ? data.commodity : []; state.channels = Array.isArray(data?.channels) ? data.channels : []; if (data?.application) state.application = data.application; } async function loadRechargeOptions() { state.loadingConfig = true; state.paymentStatusText = message("loading_data"); state.paymentStatusType = ""; state.countryList = []; state.selectedCountryId = ""; state.commodity = []; state.channels = []; renderAll(); try { await fetchRechargeProfile(); await fetchCommodities(); setPaymentStatus(""); } catch (error) { console.error("Failed to load recharge options:", error); state.paymentStatusText = error.response?.errorMsg || error.message || message("failed_to_load"); state.paymentStatusType = "error"; showToast(state.paymentStatusText); } finally { state.loadingConfig = false; renderAll(); } } async function searchTarget(event) { if (event) event.preventDefault(); if (state.searchLocked) return; const input = document.querySelector("#accountInput"); const query = String(input?.value || state.query || "").trim(); state.query = query; if (!query) { setSearchStatus(""); renderAll(); return; } state.searchLocked = true; state.profile = null; state.payProfile = null; state.countryList = []; state.selectedCountryId = ""; state.commodity = []; state.channels = []; setSearchStatus(message("searching")); setPaymentStatus(""); renderAll(); try { const result = await requestJSON(endpointOpenSearch(query)); const profile = Array.isArray(result) ? result[0] : result; if (!profile || !pickProfileId(profile)) throw new Error(message("user_not_found")); state.profile = profile; setSearchStatus(""); renderAll(); await loadRechargeOptions(); } catch (error) { console.error("Recharge target search failed:", error); const text = error.response?.errorMsg || error.message || message("user_not_found"); setSearchStatus(text, "error"); showToast(text); } finally { state.searchLocked = false; renderAll(); } } async function selectCountry(id) { if (!id || String(id) === String(state.selectedCountryId) || state.loadingConfig || state.ordering) return; state.selectedCountryId = String(id); state.loadingConfig = true; state.commodity = []; state.channels = []; state.paymentStatusText = message("loading_data"); state.paymentStatusType = ""; renderAll(); try { await fetchCommodities(); setPaymentStatus(""); } catch (error) { console.error("Failed to switch recharge country:", error); state.paymentStatusText = error.response?.errorMsg || error.message || message("failed_to_load"); state.paymentStatusType = "error"; showToast(state.paymentStatusText); } finally { state.loadingConfig = false; renderAll(); } } function payEnvironment() { const value = String(window.AIRWALLEX_ENV || params.get("payEnv") || window.ENV || "").toLowerCase(); if (value === "production" || value === "prod") return "prod"; if (value === "staging") return "staging"; if (value === "dev") return "dev"; if (value === "local") return "local"; return "demo"; } function airwallexHost(env) { const hosts = { prod: "checkout.airwallex.com", demo: "checkout-demo.airwallex.com", staging: "checkout-staging.airwallex.com", dev: "checkout-dev.airwallex.com", local: "localhost:3000" }; return `https://${hosts[env] || hosts.prod}`; } function loadAirwallex(env) { if (window.Airwallex) { window.Airwallex.init({ env }); return Promise.resolve(window.Airwallex); } const src = `${airwallexHost(env)}/assets/elements.bundle.min.js?version=1.160.0`; const existing = document.querySelector(`[data-airwallex-script="${env}"]`); const script = existing || document.createElement("script"); if (!existing) { script.src = src; script.crossOrigin = "anonymous"; script.dataset.airwallexScript = env; document.head.appendChild(script); } return new Promise((resolve, reject) => { script.addEventListener("load", () => { if (!window.Airwallex) { reject(new Error("Failed to load Airwallex")); return; } window.Airwallex.init({ env }); resolve(window.Airwallex); }, { once: true }); script.addEventListener("error", () => reject(new Error("Failed to load Airwallex")), { once: true }); }); } function parseExpand(value) { if (!value) return {}; if (typeof value === "object") return value; try { return JSON.parse(value); } catch (error) { return {}; } } function paymentResultURL(status) { const type = params.get("type") || ""; const query = new URLSearchParams({ redirect: "recharge", appType: type, appId: RECHARGE_APPLICATION_ID, appStatus: status }); return `${window.location.origin}/#/pay-result?${query.toString()}`; } async function redirectAirwallex(result) { const env = payEnvironment(); const expand = parseExpand(result.expand); if (!expand.id || !expand.client_secret) throw new Error(message("payment_not_available")); await loadAirwallex(env); window.Airwallex.redirectToCheckout({ env, mode: "payment", currency: result.currency, intent_id: expand.id, client_secret: expand.client_secret, methods: result.factoryChannelCode ? [result.factoryChannelCode] : undefined, recurringOptions: { card: { next_triggered_by: "customer", merchant_trigger_reason: "unscheduled", currency: result.currency } }, logoUrl: window.sysOriginLog || "", successUrl: paymentResultURL("0"), failUrl: paymentResultURL("1"), theme: { fonts: [ { src: "https://checkout.airwallex.com/fonts/CircularXXWeb/CircularXXWeb-Regular.woff2", family: "AxLLCircular", weight: 400 } ] } }); } async function handlePaymentResponse(result) { if (!result) throw new Error(message("payment_not_available")); if (result.factoryCode === "AIRWALLEX") { setPaymentStatus(message("redirecting_payment")); await redirectAirwallex(result); return; } if (result.requestUrl) { setPaymentStatus(message("redirecting_payment")); window.location.href = decodeURIComponent(result.requestUrl); return; } setPaymentStatus(message("order_created")); showToast(message("order_created")); } async function placeOrder(channel, goods) { if (state.ordering || state.loadingConfig) return; const country = selectedCountry(); const code = channelCode(channel); const userId = pickProfileId(state.payProfile || state.profile); if (!country?.id || !goods?.id || !userId || !code) { showToast(message("payment_not_available")); return; } state.ordering = true; state.activeOrderKey = packageKey(channel, goods); setPaymentStatus(message("creating_order")); renderAll(); try { const result = await requestJSON("/order/web/pay/recharge", { method: "POST", body: { applicationId: RECHARGE_APPLICATION_ID, payCountryId: String(country.id), goodsId: String(goods.id), userId: String(userId), channelCode: code } }); await handlePaymentResponse(result); } catch (error) { console.error("Recharge order failed:", error); const text = error.response?.errorMsg || error.message || message("payment_not_available"); setPaymentStatus(text, "error"); showToast(text); } finally { state.ordering = false; state.activeOrderKey = ""; renderAll(); } } function changeTarget() { state.profile = null; state.payProfile = null; state.countryList = []; state.selectedCountryId = ""; state.regionId = ""; state.commodity = []; state.channels = []; state.paymentStatusText = ""; state.paymentStatusType = ""; renderAll(); window.setTimeout(() => document.querySelector("#accountInput")?.focus(), 60); } 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 recharge 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)); }); } function applyLanguage(lang) { currentLang = normalizeLanguage(lang); currentMessages = messages[currentLang] || messages.en; document.documentElement.lang = currentLang; document.documentElement.dir = currentLang === "ar" ? "rtl" : "ltr"; document.title = message("document_title", "Recharge Center"); renderMessages(currentMessages); renderLanguageControls(); renderAll(); } 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.querySelector("#accountInput")?.addEventListener("input", (event) => { state.query = String(event.target.value || ""); if (!state.query.trim()) setSearchStatus(""); renderSearch(); }); document.querySelector("#searchForm")?.addEventListener("submit", searchTarget); document.querySelector("[data-change-target]")?.addEventListener("click", changeTarget); document.querySelector("[data-help-open]")?.addEventListener("click", () => setModalOpen("#helpModal", true)); document.querySelectorAll("[data-help-close]").forEach((node) => { node.addEventListener("click", () => setModalOpen("#helpModal", false)); }); document.addEventListener("keydown", (event) => { if (event.key === "Escape") setModalOpen("#helpModal", false); }); } async function initializePage() { setLoading(true); bindEvents(); applyLanguage(currentLang); renderAll(); setLoading(false); if (!readRawParam("token")) { setSearchStatus(message("missing_token"), "error"); renderAll(); return; } if (state.query) { await searchTarget(); } } initializePage(); })();