(function () { var EXCHANGE_RATE = 80000; var WITHDRAW_MIN_AMOUNT = 50; var params = new URLSearchParams(window.location.search); var isMock = params.get('mock') === '1'; var currentMode = normalizeMode(params.get('mode')) || 'transfer'; var identity = String(params.get('identity') || '').trim(); var salaryAssetType = String( params.get('salaryType') || params.get('asset_type') || '' ).trim(); var state = { balance: 0, paymentInfo: null, selectedPayee: null, isSearching: false, isSaving: false, isEditingAddress: false, isSavingContact: false, isSubmitting: false, contactInfo: '', historyItems: [], transferRateTiers: [], }; var lastSearchTriggerAt = 0; var autoSearchTimer = 0; var mockBalances = { HOST_SALARY_USD: 30650.75, AGENCY_SALARY_USD: 30650.75, BD_SALARY_USD: 48620.8, ADMIN_SALARY_USD: 168250.5, }; var mock = { balance: mockBalances[salaryAssetType] || 30650.75, paymentInfo: null, payees: { 163003: { id: 'payee_163003', name: 'Yumi Star Agency', account: '163003', avatar: '', }, 163000: { id: 'payee_163000', name: 'quick_1780052629537', account: '163000', avatar: '', }, }, history: [ { key: historyTitleKey(), title: historyTitle(), amount: 18400.25, balance: mockBalances[salaryAssetType] || 30650.75, type: 0, date: '2026-06-01 12:10', }, { key: 'withdraw_exchange.history_exchange_to_golds', title: 'Exchange to golds', amount: 800, balance: 12250.5, type: 1, date: '2026-05-30 20:42', }, { key: 'withdraw_exchange.history_gift_reward', title: 'Gift reward', amount: 8250.5, balance: 13050.5, type: 0, date: '2026-05-28 18:30', }, ], }; var inputs = { withdraw: $('withdrawAmount'), exchange: $('exchangeAmount'), transfer: $('transferAmount'), }; function $(id) { return document.getElementById(id); } function t(key, fallback) { return window.HyAppI18n && window.HyAppI18n.t ? window.HyAppI18n.t(key, fallback) : fallback || key; } function toast(message) { if (window.HyAppToast) { window.HyAppToast.show(message); return; } window.alert(message); } function normalizeMode(mode) { var value = String(mode || '').trim(); return ['withdraw', 'exchange', 'transfer'].indexOf(value) >= 0 ? value : ''; } function normalizeIdentity(value) { value = String(value || '') .trim() .toUpperCase() .replace(/-/g, '_'); if (value === 'ADMIN') return 'BD_LEADER'; if (['HOST', 'AGENCY', 'BD', 'BD_LEADER'].indexOf(value) >= 0) return value; if (salaryAssetType === 'AGENCY_SALARY_USD') return 'AGENCY'; if (salaryAssetType === 'BD_SALARY_USD') return 'BD'; if (salaryAssetType === 'ADMIN_SALARY_USD') return 'BD_LEADER'; return 'HOST'; } function api() { if (window.HyAppAPI && window.HyAppAPI.salaryWallet) return window.HyAppAPI.salaryWallet; return window.HyApp && window.HyApp.api ? window.HyApp.api.salaryWallet : null; } function userApi() { if (window.HyAppAPI && window.HyAppAPI.user) return window.HyAppAPI.user; return window.HyApp && window.HyApp.api ? window.HyApp.api.user : null; } function commandId(prefix) { return ( prefix + '-' + Date.now() + '-' + Math.random().toString(16).slice(2) ); } function money(value) { var number = Number(value || 0); return number.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2, }); } function moneyInput(value) { var number = Number(value || 0); return Number.isFinite(number) ? number.toFixed(2) : '0.00'; } function amount() { var input = inputs[currentMode]; return Number(input && input.value ? input.value : 0) || 0; } function amountText(value) { return moneyInput(value); } function usdMinorToNumber(value) { return Number(value || 0) / 100; } function salaryBalanceAfterToNumber(value) { if (value && typeof value === 'object') { return usdMinorToNumber(value.available_amount); } return usdMinorToNumber(value); } function findTransferRate(value) { var minor = Math.round(Number(value || 0) * 100); return (state.transferRateTiers || []).find(function (tier) { return ( String(tier.status || 'active') === 'active' && minor >= Number(tier.min_usd_minor || 0) && minor <= Number(tier.max_usd_minor || 0) ); }); } function delay(value) { return new Promise(function (resolve) { window.setTimeout(function () { resolve(value); }, 260); }); } function mockRequest(action, payload) { if (action === 'balance') return delay(mock.balance); if (action === 'payment') return delay(mock.paymentInfo); if (action === 'history') return delay(mock.history.slice()); if (action === 'saveAddress') { mock.paymentInfo = { id: 'usdt_mock_1', cardNo: payload.cardNo, }; return delay(mock.paymentInfo); } if (action === 'searchPayee') { var account = String(payload.account || '').trim(); var payee = mock.payees[account]; if (!payee && account && account !== '000000') { payee = { id: 'payee_' + account, name: 'User ' + account, nameKey: 'withdraw_exchange.mock_user_name', account: account, avatar: '', }; } return delay(payee || null); } if (action === 'submit') { mock.balance = Math.max(0, mock.balance - payload.amount); mock.history.unshift({ title: titleForMode(payload.mode), amount: payload.amount, balance: mock.balance, type: 1, date: new Date().toISOString().replace('T', ' ').slice(0, 16), }); return delay({ ok: true }); } return delay(null); } function titleForMode(mode) { if (mode === 'withdraw') return t('withdraw_exchange.withdraw', 'Withdraw'); if (mode === 'exchange') return t('withdraw_exchange.exchange', 'Exchange'); return t('withdraw_exchange.transfer', 'Transfer'); } function historyTitleKey() { if (salaryAssetType === 'BD_SALARY_USD') return 'withdraw_exchange.history_bd_salary'; if (salaryAssetType === 'ADMIN_SALARY_USD') return 'withdraw_exchange.history_admin_salary'; if (salaryAssetType === 'AGENCY_SALARY_USD') return 'withdraw_exchange.history_agency_salary'; return 'withdraw_exchange.history_host_salary'; } function historyTitle() { if (salaryAssetType === 'BD_SALARY_USD') return 'BD salary'; if (salaryAssetType === 'ADMIN_SALARY_USD') return 'Admin salary'; if (salaryAssetType === 'AGENCY_SALARY_USD') return 'Agency salary'; return 'Host salary'; } function firstValue(source, keys) { if (!source) return ''; for (var i = 0; i < keys.length; i += 1) { var value = source[keys[i]]; if (value !== undefined && value !== null && value !== '') return value; } return ''; } function contactFrom(value) { if (!value || typeof value !== 'object') return ''; var source = value.profile || value.user || value; return String( firstValue(source, [ 'contact_info', 'contactInfo', 'whatsapp_phone', 'whatsappPhone', 'contact', ]) || '' ).trim(); } function withdrawAddressFrom(value) { if (typeof value === 'string') return value.trim(); if (!value || typeof value !== 'object') return ''; if (typeof value.withdraw_address === 'string') return value.withdraw_address.trim(); var source = value.withdraw_address || value.user || value.profile || value; return String( firstValue(source, [ 'cardNo', 'withdraw_usdt_trc20_address', 'withdrawUsdtTrc20Address', 'usdt_trc20_address', 'usdtTrc20Address', 'payment_address', 'paymentAddress', 'address', ]) || '' ).trim(); } function paymentInfoFrom(value) { var address = withdrawAddressFrom(value); if (!address) return null; return { id: 'usdt_trc20', cardNo: address, }; } function timeLabelFromMS(value) { var number = Number(value || 0); if (!Number.isFinite(number) || number <= 0) return ''; var date = new Date(number); if (Number.isNaN(date.getTime())) return ''; return ( date.getFullYear() + '-' + String(date.getMonth() + 1).padStart(2, '0') + '-' + String(date.getDate()).padStart(2, '0') + ' ' + String(date.getHours()).padStart(2, '0') + ':' + String(date.getMinutes()).padStart(2, '0') ); } function historyLabelForBizType(bizType, delta) { if (bizType === 'salary_exchange_to_coin') { return { key: 'withdraw_exchange.history_exchange_to_golds', title: 'Exchange to golds', }; } if (bizType === 'salary_transfer_to_coin_seller') { return { key: 'withdraw_exchange.transfer', title: 'Transfer', }; } if (bizType === 'host_salary_settlement' || delta >= 0) { return { key: historyTitleKey(), title: historyTitle(), }; } return { key: 'withdraw_exchange.withdraw', title: 'Withdraw', }; } function normalizeHistoryItem(item, index) { var delta = Number( firstValue(item, ['available_delta', 'availableDelta']) ); if (!Number.isFinite(delta)) delta = 0; var balance = Number( firstValue(item, ['available_after', 'availableAfter']) ); if (!Number.isFinite(balance)) balance = 0; var label = historyLabelForBizType( String(firstValue(item, ['biz_type', 'bizType']) || ''), delta ); return { id: firstValue(item, ['transaction_id', 'transactionId']) || String(firstValue(item, ['entry_id', 'entryId']) || index), key: label.key, title: label.title, amount: Math.abs(usdMinorToNumber(delta)), balance: usdMinorToNumber(balance), type: delta < 0 ? 1 : 0, date: timeLabelFromMS( firstValue(item, ['created_at_ms', 'createdAtMs']) ), }; } function normalizeHistoryItems(payload) { var source = payload || {}; if (source.identity) identity = normalizeIdentity(source.identity); if (source.salary_asset_type) { salaryAssetType = source.salary_asset_type; } var items = Array.isArray(source.items) ? source.items : Array.isArray(source.transactions) ? source.transactions : Array.isArray(source) ? source : []; return items.map(function (item, index) { return normalizeHistoryItem(item || {}, index); }); } function isValidTrc20(value) { return /^T[1-9A-HJ-NP-Za-km-z]{33}$/.test(String(value || '').trim()); } function activeSubmitLabel() { if (currentMode === 'withdraw') return t('withdraw_exchange.withdraw_now', 'Withdraw now'); if (currentMode === 'exchange') return t('withdraw_exchange.exchange_now', 'Exchange now'); return t('withdraw_exchange.transfer_now', 'Transfer now'); } function renderBalance() { $('balanceAmount').textContent = money(state.balance); Object.keys(inputs).forEach(function (key) { if (inputs[key]) inputs[key].max = moneyInput(state.balance); }); } function renderMode() { document.querySelectorAll('.mode-tab').forEach(function (tab) { var active = tab.getAttribute('data-mode') === currentMode; tab.classList.toggle('active', active); tab.setAttribute('aria-selected', String(active)); }); document.querySelectorAll('.mode-panel').forEach(function (panel) { panel.classList.toggle( 'active', panel.getAttribute('data-panel') === currentMode ); }); $('paymentSection').hidden = currentMode !== 'withdraw'; updateSubmit(); } function renderPaymentInfo() { var payment = state.paymentInfo; var hasPayment = Boolean(payment); $('emptyAddressState').hidden = hasPayment || state.isEditingAddress; $('addressForm').hidden = hasPayment && !state.isEditingAddress; $('boundAddressCard').hidden = !hasPayment || state.isEditingAddress; if (payment) $('boundAddress').textContent = payment.cardNo || '-'; updateSubmit(); } function renderPayee() { var result = $('payeeResult'); result.textContent = ''; if (!state.selectedPayee) { result.hidden = true; updateSubmit(); return; } var payee = state.selectedPayee; var payeeName = payee.nameKey ? t(payee.nameKey, payee.name || 'User {account}').replace( '{account}', payee.account ) : payee.name; var avatar = document.createElement('div'); var copy = document.createElement('div'); var name = document.createElement('div'); var id = document.createElement('div'); avatar.className = 'payee-avatar'; copy.className = 'payee-copy'; name.className = 'payee-name'; id.className = 'payee-id'; if (payee.avatar) { var avatarImage = document.createElement('img'); avatarImage.src = payee.avatar; avatarImage.alt = ''; avatar.appendChild(avatarImage); } else { avatar.textContent = String(payeeName || 'U') .charAt(0) .toUpperCase(); } name.textContent = payeeName || '-'; id.textContent = t('withdraw_exchange.uid_prefix', 'UID:') + ' ' + payee.account; copy.appendChild(name); copy.appendChild(id); result.appendChild(avatar); result.appendChild(copy); result.hidden = false; updateSubmit(); } function renderHistory() { $('salaryHistoryTotal').textContent = '$' + money(state.balance); var list = $('salaryHistoryList'); list.textContent = ''; if (!state.historyItems.length) { var empty = document.createElement('div'); empty.className = 'salary-history-empty'; empty.textContent = t( 'withdraw_exchange.no_salary_history', 'No salary history' ); list.appendChild(empty); return; } state.historyItems.forEach(function (item) { var row = document.createElement('article'); var main = document.createElement('div'); var title = document.createElement('div'); var meta = document.createElement('div'); var value = document.createElement('div'); var isOut = Number(item.type) === 1; row.className = 'salary-history-item'; main.className = 'salary-history-item-main'; title.className = 'salary-history-item-title'; meta.className = 'salary-history-item-meta'; value.className = 'salary-history-amount' + (isOut ? ' is-out' : ''); title.textContent = item.key ? t(item.key, item.title) : item.title; meta.textContent = item.date + ' ' + t('withdraw_exchange.balance', 'Balance') + ': $' + money(item.balance); value.textContent = (isOut ? '-' : '+') + '$' + money(item.amount); main.appendChild(title); main.appendChild(meta); row.appendChild(main); row.appendChild(value); list.appendChild(row); }); } function updateSubmit() { var button = $('submitButton'); if (state.isSubmitting) { button.textContent = t( 'withdraw_exchange.submitting', 'Submitting...' ); button.disabled = true; return; } var value = amount(); var transferRateMissing = currentMode === 'transfer' && value > 0 && !findTransferRate(value); var disabled = value <= 0 || value > state.balance || (currentMode === 'withdraw' && (!state.paymentInfo || value < WITHDRAW_MIN_AMOUNT)) || (currentMode === 'transfer' && (!state.selectedPayee || transferRateMissing)); button.textContent = activeSubmitLabel(); button.disabled = disabled; } function needsContactForSubmit() { return currentMode === 'exchange' || currentMode === 'transfer'; } function normalizeAmount(event) { var input = event.target; var raw = String(input.value || '').replace(/[^\d.]/g, ''); var parts = raw.split('.'); var next = parts.length > 2 ? parts[0] + '.' + parts.slice(1).join('') : raw; var value = Number(next); if (Number.isFinite(value) && value > state.balance) next = moneyInput(state.balance); input.value = next; updateSubmit(); } function setMode(mode) { currentMode = normalizeMode(mode) || 'transfer'; renderMode(); } function openHistory() { $('salaryHistoryModal').hidden = false; document.body.classList.add('modal-open'); $('salaryHistoryList').textContent = t( 'withdraw_exchange.loading', 'Loading...' ); var historyRequest = isMock ? mockRequest('history') : api() && api().history ? api().history(identity, 30).then(normalizeHistoryItems) : Promise.resolve([]); historyRequest .then(function (items) { state.historyItems = items || []; renderHistory(); }) .catch(function (err) { state.historyItems = []; renderHistory(); toast( err && err.message ? err.message : t( 'withdraw_exchange.load_failed', 'Load failed. Try again later.' ) ); }); } function closeHistory() { $('salaryHistoryModal').hidden = true; document.body.classList.remove('modal-open'); } function setContactStatus(message) { var node = $('contactStatus'); node.textContent = message || ''; node.hidden = !message; } function setContactSaving(saving) { state.isSavingContact = saving; $('saveContactButton').disabled = saving; $('saveContactButton').textContent = saving ? t('contact_card.saving', 'Saving...') : t('contact_card.save', 'Save'); } function openContactModal() { $('contactInput').value = state.contactInfo || ''; setContactStatus(''); $('contactModal').hidden = false; $('contactModal').setAttribute('aria-hidden', 'false'); document.body.classList.add('modal-open'); window.setTimeout(function () { $('contactInput').focus(); }, 0); } function closeContactModal() { $('contactModal').hidden = true; $('contactModal').setAttribute('aria-hidden', 'true'); document.body.classList.remove('modal-open'); } function saveContact(event) { if (event) event.preventDefault(); var contact = String($('contactInput').value || '').trim(); if (!contact) { setContactStatus( t('contact_card.required', 'Enter WhatsApp contact.') ); return; } var apiClient = userApi(); if (!apiClient || !apiClient.updateContact) { setContactStatus( t('contact_card.api_unavailable', 'Contact API unavailable.') ); return; } // Exchange/Transfer 需要运营联系方式用于后台跟进;联系方式是用户主资料,保存成功后才允许继续提交工资兑换或转账请求。 setContactSaving(true); setContactStatus(''); apiClient .updateContact({ contact_info: contact }) .then(function (response) { state.contactInfo = contactFrom(response) || contact; closeContactModal(); updateSubmit(); toast(t('contact_card.saved', 'Saved.')); }) .catch(function () { setContactStatus(t('contact_card.save_failed', 'Save failed.')); }) .finally(function () { setContactSaving(false); }); } function saveAddress() { var address = String($('trc20Address').value || '').trim(); if (!isValidTrc20(address)) { toast( t( 'withdraw_exchange.invalid_address', 'Please enter a valid TRC20 USDT address' ) ); return; } state.isSaving = true; $('saveAddressButton').disabled = true; $('saveAddressButton').textContent = t( 'withdraw_exchange.saving', 'Saving...' ); var saveRequest = isMock ? mockRequest('saveAddress', { cardNo: address }) : api() && api().saveWithdrawAddress ? api() .saveWithdrawAddress({ payment_address: address, }) .then(paymentInfoFrom) : Promise.reject( new Error( t('withdraw_exchange.submit_failed', 'Submit failed.') ) ); saveRequest .then(function (payment) { state.paymentInfo = payment || { id: 'usdt_trc20', cardNo: address, }; state.isEditingAddress = false; $('trc20Address').value = ''; renderPaymentInfo(); toast(t('withdraw_exchange.address_saved', 'Address saved')); }) .catch(function (err) { toast( err && err.message ? err.message : t('withdraw_exchange.submit_failed', 'Submit failed.') ); }) .finally(function () { state.isSaving = false; $('saveAddressButton').disabled = false; $('saveAddressButton').textContent = t( 'withdraw_exchange.save_address', 'Save address' ); }); } function editAddress() { if (!state.paymentInfo) return; state.isEditingAddress = true; $('trc20Address').value = state.paymentInfo.cardNo || ''; renderPaymentInfo(); window.setTimeout(function () { $('trc20Address').focus(); }, 0); } function searchPayee() { var now = Date.now(); if (now - lastSearchTriggerAt < 240) return; lastSearchTriggerAt = now; var account = String($('transferAccount').value || '').trim(); if (!account) { toast( t( 'withdraw_exchange.missing_payee', 'Please search and select a user' ) ); return; } state.selectedPayee = null; renderPayee(); if (!isMock && !api()) { toast( t( 'withdraw_exchange.search_failed', 'Search failed. Try again later.' ) ); return; } state.isSearching = true; $('searchPayeeButton').disabled = true; $('searchPayeeButton').textContent = t( 'withdraw_exchange.searching', 'Searching...' ); var request = isMock ? mockRequest('searchPayee', { account: account }) : api() .searchCoinSeller(account, identity) .then(function (data) { var seller = data && data.seller; if (!seller) return null; return { id: seller.user_id || seller.userId, name: seller.username || seller.display_user_id || account, account: seller.display_user_id || account, avatar: seller.avatar || '', }; }); request .then(function (payee) { state.isSearching = false; $('searchPayeeButton').disabled = false; $('searchPayeeButton').textContent = t( 'withdraw_exchange.search', 'Search' ); if (!payee) { toast( t('withdraw_exchange.payee_not_found', 'User not found') ); return; } state.selectedPayee = payee; renderPayee(); }) .catch(function (err) { state.isSearching = false; $('searchPayeeButton').disabled = false; $('searchPayeeButton').textContent = t( 'withdraw_exchange.search', 'Search' ); toast( err && err.message ? err.message : t( 'withdraw_exchange.payee_not_found', 'User not found' ) ); }); } function validateSubmit() { var value = amount(); if (value <= 0) return t( 'withdraw_exchange.invalid_amount', 'Please enter a valid amount' ); if (value > state.balance) return t( 'withdraw_exchange.amount_exceeds_balance', 'Amount exceeds salary' ); if (currentMode === 'withdraw' && !state.paymentInfo) return t( 'withdraw_exchange.missing_payment_info', 'Please add a TRC20 USDT address' ); if (currentMode === 'withdraw' && value < WITHDRAW_MIN_AMOUNT) return t( 'withdraw_exchange.amount_too_low', 'Minimum withdrawal amount is 50 USD' ); if (currentMode === 'transfer' && !state.selectedPayee) return t( 'withdraw_exchange.missing_payee', 'Please search and select a user' ); if (currentMode === 'transfer' && !findTransferRate(value)) return t( 'withdraw_exchange.rate_not_configured', 'Exchange rate not configured.' ); return ''; } function submit() { var error = validateSubmit(); if (error) { toast(error); return; } if (needsContactForSubmit() && !state.contactInfo) { openContactModal(); return; } state.isSubmitting = true; updateSubmit(); submitRequest() .then(function (result) { var input = inputs[currentMode]; if (input) input.value = ''; if (currentMode === 'transfer') { state.selectedPayee = null; $('transferAccount').value = ''; renderPayee(); } if (isMock) { state.balance = mock.balance; } else if (currentMode === 'withdraw') { state.balance = salaryBalanceAfterToNumber( result.salary_balance_after ); } else if (currentMode === 'exchange') { state.balance = salaryBalanceAfterToNumber( result.salary_balance_after ); } else if (currentMode === 'transfer') { state.balance = usdMinorToNumber( result.source_salary_balance_after ); } state.isSubmitting = false; renderBalance(); updateSubmit(); var key = currentMode === 'withdraw' ? 'withdraw_exchange.withdraw_success' : currentMode === 'exchange' ? 'withdraw_exchange.exchange_success' : 'withdraw_exchange.transfer_success'; toast(t(key, 'Submitted')); }) .catch(function (err) { state.isSubmitting = false; updateSubmit(); toast( err && err.message ? err.message : t('withdraw_exchange.submit_failed', 'Submit failed.') ); }); } function submitRequest() { var value = amount(); if (isMock) { return mockRequest('submit', { mode: currentMode, amount: value, payee: state.selectedPayee, paymentInfo: state.paymentInfo, }); } if (!api()) { return Promise.reject( new Error( t('withdraw_exchange.submit_failed', 'Submit failed.') ) ); } if (currentMode === 'exchange') { return api().exchange({ command_id: commandId('salary-exchange'), identity: identity, amount_usd: amountText(value), reason: 'salary exchange', }); } if (currentMode === 'withdraw') { return api().withdraw({ command_id: commandId('salary-withdraw'), identity: identity, amount_usd: amountText(value), payment_address: state.paymentInfo && state.paymentInfo.cardNo, }); } return api().transferToCoinSeller({ command_id: commandId('salary-transfer'), identity: identity, target_display_user_id: state.selectedPayee.account, amount_usd: amountText(value), reason: 'salary transfer', }); } function goBack() { if (window.history.length > 1) { window.history.back(); return; } var nextParams = new URLSearchParams(window.location.search); nextParams.delete('mode'); var query = nextParams.toString(); var centerPath = '../host-center/index.html'; if (identity === 'BD') centerPath = '../bd-center/index.html'; if (identity === 'BD_LEADER') centerPath = '../superadmin-center/index.html'; if (identity === 'AGENCY') centerPath = '../agency-center/index.html'; window.location.href = centerPath + (query ? '?' + query : ''); } function bindEvents() { function bindTap(id, handler) { var node = $(id); var last = 0; function run(event) { var now = Date.now(); if (now - last < 220) { if (event) event.preventDefault(); return; } last = now; // 只能在 click 阶段变更弹窗状态:WebView 里 pointerdown 先打开遮罩后,同一次触摸生成的 click 会落到新遮罩上,导致详情弹窗刚打开又被关闭。 if (event) event.preventDefault(); handler(event); } node.addEventListener('click', run); } bindTap('backButton', goBack); document.querySelectorAll('.mode-tab').forEach(function (tab) { tab.addEventListener('click', function () { setMode(tab.getAttribute('data-mode')); }); }); Object.keys(inputs).forEach(function (key) { if (inputs[key]) inputs[key].addEventListener('input', normalizeAmount); }); bindTap('allButton', function () { inputs.withdraw.value = moneyInput(state.balance); updateSubmit(); }); $('transferAccount').addEventListener('input', function () { state.selectedPayee = null; renderPayee(); window.clearTimeout(autoSearchTimer); if (String($('transferAccount').value || '').trim().length >= 3) { autoSearchTimer = window.setTimeout(searchPayee, 260); } }); $('transferAccount').addEventListener('keydown', function (event) { if (event.key === 'Enter') searchPayee(); }); bindTap('searchPayeeButton', searchPayee); bindTap('saveAddressButton', saveAddress); bindTap('editAddressButton', editAddress); bindTap('submitButton', submit); bindTap('salaryHistoryButton', openHistory); bindTap('salaryHistoryBackdrop', closeHistory); bindTap('salaryHistoryCloseButton', closeHistory); bindTap('contactBackdrop', closeContactModal); bindTap('contactCloseButton', closeContactModal); $('contactForm').addEventListener('submit', saveContact); } function renderStaticDynamicText() { $('exchangeRateText').textContent = t( 'withdraw_exchange.exchange_rate_value', '1$ = {amount} golds' ).replace('{amount}', EXCHANGE_RATE.toLocaleString('en-US')); if (!$('salaryHistoryModal').hidden) renderHistory(); if (!$('contactModal').hidden && !state.isSavingContact) { $('saveContactButton').textContent = t('contact_card.save', 'Save'); } updateSubmit(); renderPayee(); } function init() { identity = normalizeIdentity(identity); bindEvents(); setMode(currentMode); renderStaticDynamicText(); loadOverview(); loadPaymentInfo(); loadContactInfo(); if (window.HyAppBridge) { window.HyAppBridge.ready({ page: 'withdraw-exchange', mock: isMock, }); } } function loadOverview() { if (isMock) { mockRequest('balance').then(function (balance) { state.balance = balance; state.transferRateTiers = [ { min_usd_minor: 100, max_usd_minor: 1000, coin_per_usd: 90000, status: 'active', }, { min_usd_minor: 1100, max_usd_minor: 5000, coin_per_usd: 92000, status: 'active', }, ]; renderBalance(); updateSubmit(); }); return; } if (!api()) { toast( t( 'withdraw_exchange.load_failed', 'Load failed. Try again later.' ) ); return; } api() .overview(identity) .then(function (data) { identity = normalizeIdentity(data.identity || identity); salaryAssetType = data.salary_asset_type || salaryAssetType; EXCHANGE_RATE = Number(data.exchange_rate || EXCHANGE_RATE); var payment = paymentInfoFrom(data); if (payment) state.paymentInfo = payment; state.balance = usdMinorToNumber( data.salary && data.salary.available_amount ); state.transferRateTiers = data.transfer_rate_tiers || []; renderStaticDynamicText(); renderBalance(); renderPaymentInfo(); updateSubmit(); }) .catch(function (err) { toast( err && err.message ? err.message : t( 'withdraw_exchange.load_failed', 'Load failed. Try again later.' ) ); }); } function loadPaymentInfo() { if (isMock) { mockRequest('payment').then(function (payment) { state.paymentInfo = payment; renderPaymentInfo(); }); return; } state.paymentInfo = null; state.isEditingAddress = false; renderPaymentInfo(); if (!api() || !api().getWithdrawAddress) return; api() .getWithdrawAddress() .then(function (data) { state.paymentInfo = paymentInfoFrom(data); renderPaymentInfo(); }) .catch(function () { renderPaymentInfo(); }); } function loadContactInfo() { if (isMock) { state.contactInfo = String(params.get('contact') || '').trim(); updateSubmit(); return; } var apiClient = userApi(); if (!apiClient || !apiClient.me) { state.contactInfo = ''; updateSubmit(); return; } apiClient .me() .then(function (profile) { state.contactInfo = contactFrom(profile); updateSubmit(); }) .catch(function () { state.contactInfo = ''; updateSubmit(); }); } document.addEventListener('DOMContentLoaded', init); window.addEventListener('hyapp:i18n-ready', renderStaticDynamicText); })();