1223 lines
39 KiB
JavaScript
Raw 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.

(function () {
var SELLER_ASSET_TYPE = 'COIN_SELLER_COIN';
var query = new URLSearchParams(window.location.search);
var mock = {
profile: {
name: 'CoinSeller Mina',
uid: '163009',
region: 'Saudi Arabia',
avatar: avatarData('C', '#dbc8ff', '#7d57c7'),
},
balance: {
coins: 1285000,
},
users: [
{
uid: '2001',
userId: '9002001',
name: 'Alice',
avatar: avatarData('A', '#dbc8ff', '#7d57c7'),
},
{
uid: '2002',
userId: '9002002',
name: 'Bob',
avatar: avatarData('B', '#f4ebff', '#7d57c7'),
},
{
uid: '2003',
userId: '9002003',
name: 'Nora',
avatar: avatarData('N', '#efe4ff', '#7d57c7'),
},
],
quickAmounts: [10000, 50000, 100000],
records: [
{
id: 'tx-001',
type: 'income',
name: 'Stock transfer',
uid: 'System',
avatar: avatarData('S', '#e7f7f3', '#31a88f'),
coins: 300000,
amount: 36,
currency: 'USD',
time: '2026-06-04 10:30',
},
{
id: 'tx-002',
type: 'expenditure',
name: 'Alice',
uid: '2001',
avatar: avatarData('A', '#dbc8ff', '#7d57c7'),
coins: 110000,
amount: 12.5,
currency: 'USD',
time: '2026-06-04 10:10',
},
{
id: 'tx-003',
type: 'expenditure',
name: 'Bob',
uid: '2002',
avatar: avatarData('B', '#f4ebff', '#7d57c7'),
coins: 88000,
amount: 9.25,
currency: 'USD',
time: '2026-06-04 09:20',
},
{
id: 'tx-004',
type: 'income',
name: 'Manager recharge',
uid: 'System',
avatar: avatarData('M', '#e7f7f3', '#31a88f'),
coins: 180000,
amount: 22,
currency: 'USD',
time: '2026-06-03 18:42',
},
],
};
var data = {
profile: emptyProfile(),
balance: { coins: 0 },
users: [],
quickAmounts: mock.quickAmounts.slice(),
records: [],
};
var state = {
target: null,
coinAmount: '',
historyTab: 'income',
historyQuery: '',
historyLimit: 3,
isMock: query.get('mock') === '1',
loading: query.get('mock') !== '1',
searching: false,
submitting: false,
};
function $(id) {
return document.getElementById(id);
}
function t(key, fallback) {
return window.HyAppI18n && window.HyAppI18n.t
? window.HyAppI18n.t(key, fallback)
: fallback || key;
}
function avatarData(text, background, foreground) {
var value =
String(text || 'C')
.trim()
.charAt(0) || 'C';
var letter = value.replace(/[<>&"']/g, '');
var svg =
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96">' +
'<rect width="96" height="96" rx="48" fill="' +
background +
'"/>' +
'<text x="50%" y="54%" text-anchor="middle" dominant-baseline="middle" fill="' +
foreground +
'" font-family="Arial, sans-serif" font-size="38" font-weight="800">' +
letter +
'</text>' +
'</svg>';
return 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg);
}
function emptyProfile() {
return {
name: '',
uid: '',
region: '',
avatar: '',
};
}
function initial(text) {
return String(text || '')
.trim()
.charAt(0)
.toUpperCase();
}
function count(value) {
return Number(value || 0).toLocaleString('en-US', {
maximumFractionDigits: 0,
});
}
function toNumber(value) {
var number = Number(value);
return Number.isFinite(number) ? number : 0;
}
function positiveNumber(value) {
var number = toNumber(value);
return number > 0 ? number : 0;
}
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 unwrapData(payload) {
if (!payload || typeof payload !== 'object') return payload;
return Object.prototype.hasOwnProperty.call(payload, 'data')
? payload.data
: payload;
}
function replaceChildren(node, children) {
node.textContent = '';
children.forEach(function (child) {
node.appendChild(child);
});
}
function toast(message) {
if (!message) return;
if (window.HyAppToast && window.HyAppToast.show) {
window.HyAppToast.show(message);
return;
}
window.alert(message);
}
function setStatus(node, message, type) {
node.hidden = !message;
node.textContent = message || '';
node.className = 'form-status' + (type ? ' ' + type : '');
}
function setSkeleton(element, loading, text) {
if (!element) return;
element.classList.toggle('skeleton-line', !!loading);
if (loading) {
element.textContent = '';
return;
}
element.textContent = text || '';
}
function hasAPI() {
return (
window.HyAppAPI && window.HyAppAPI.user && window.HyAppAPI.wallet
);
}
function setImage(image, fallback, src, name) {
if (!image || !fallback) return;
fallback.textContent = initial(name) || 'C';
if (!src) {
image.hidden = true;
image.removeAttribute('src');
fallback.hidden = false;
return;
}
image.onload = function () {
image.hidden = false;
fallback.hidden = true;
};
image.onerror = function () {
image.hidden = true;
fallback.hidden = false;
};
image.src = src;
}
function renderAvatar(container, item) {
container.textContent = '';
if (item.avatar) {
var image = document.createElement('img');
image.src = item.avatar;
image.alt = '';
image.addEventListener('error', function () {
container.textContent = initial(item.name || item.uid) || 'U';
});
container.appendChild(image);
return;
}
container.textContent = initial(item.name || item.uid) || 'U';
}
function normalizeProfile(payload) {
var source = unwrapData(payload) || {};
return {
name:
firstValue(source, [
'username',
'nickname',
'name',
'display_user_id',
'displayUserID',
'user_id',
'userId',
]) || '-',
uid:
firstValue(source, [
'display_user_id',
'displayUserID',
'displayUserId',
'user_id',
'userId',
]) || '-',
region:
firstValue(source, [
'country_display_name',
'countryDisplayName',
'country_name',
'countryName',
'region_name',
'regionName',
'country',
'region',
]) || '',
avatar:
firstValue(source, [
'avatar',
'avatar_url',
'avatarUrl',
'profile_picture_url',
'profilePictureUrl',
]) || '',
};
}
function normalizeBalance(payload) {
var source = unwrapData(payload) || {};
var balances = Array.isArray(source.balances)
? source.balances
: Array.isArray(source)
? source
: [];
var matched =
balances.find(function (item) {
return item && item.asset_type === SELLER_ASSET_TYPE;
}) ||
balances.find(function (item) {
return item && item.assetType === SELLER_ASSET_TYPE;
}) ||
balances[0] ||
{};
return {
coins: toNumber(
firstValue(matched, [
'available_amount',
'availableAmount',
'available',
'amount',
])
),
};
}
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 normalizeTransferAmount(item) {
// 转账美金来自服务端账务 metadata不同入账来源汇率可能不同前端不能用金币数反推缺字段时保持不展示。
var minor = positiveNumber(
firstValue(item, [
'transfer_usd_minor',
'transferUsdMinor',
'salary_usd_minor',
'salaryUsdMinor',
'recharge_usd_minor',
'rechargeUsdMinor',
'usd_minor_amount',
'usdMinorAmount',
])
);
if (minor > 0) return minor / 100;
var micro = positiveNumber(
firstValue(item, [
'paid_amount_micro',
'paidAmountMicro',
'amount_usdt_micro',
'amountUsdtMicro',
])
);
if (micro > 0) return micro / 1000000;
return positiveNumber(
firstValue(item, [
'amount_usd',
'amountUsd',
'transfer_amount_usd',
'transferAmountUsd',
])
);
}
function normalizeTransferCurrency(item, amount) {
return amount > 0
? String(
firstValue(item, [
'transfer_currency_code',
'transferCurrencyCode',
'recharge_currency_code',
'rechargeCurrencyCode',
'paid_currency_code',
'paidCurrencyCode',
'currency_code',
'currencyCode',
]) || 'USD'
).toUpperCase()
: '';
}
function formatTransferAmount(amount, currency) {
if (!amount || amount <= 0) return '';
var code = String(currency || 'USD').toUpperCase();
var value = Number(amount).toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
return code + ' ' + value;
}
function normalizeResolvedUser(payload, keyword) {
var source = unwrapData(payload) || {};
var identity = source.identity || source.user_identity || source;
var profile = source.profile || source.user || source;
var displayID =
firstValue(identity, [
'display_user_id',
'displayUserID',
'displayUserId',
'display_id',
'displayId',
]) ||
firstValue(profile, [
'display_user_id',
'displayUserID',
'displayUserId',
'display_id',
'displayId',
]) ||
String(keyword || '').trim();
var userID =
firstValue(identity, ['user_id', 'userId', 'id']) ||
firstValue(profile, ['user_id', 'userId', 'id']) ||
'';
return {
uid: displayID,
userId: userID,
name:
firstValue(profile, ['username', 'nickname', 'name']) ||
firstValue(identity, ['username', 'nickname', 'name']) ||
t('coinseller_center.user_name_template', 'User {id}').replace(
'{id}',
displayID
),
avatar:
firstValue(profile, [
'avatar',
'avatar_url',
'avatarUrl',
'profile_picture_url',
'profilePictureUrl',
]) ||
firstValue(identity, [
'avatar',
'avatar_url',
'avatarUrl',
'profile_picture_url',
'profilePictureUrl',
]) ||
'',
};
}
function normalizeTransactionRecord(item, index) {
var delta = toNumber(
firstValue(item, ['available_delta', 'availableDelta'])
);
var type = delta >= 0 ? 'income' : 'expenditure';
var counterpartyUserID = String(
firstValue(item, ['counterparty_user_id', 'counterpartyUserId']) ||
''
);
var counterpartyDisplayID = String(
firstValue(item, [
'counterparty_display_user_id',
'counterpartyDisplayUserId',
'counterpartyDisplayUserID',
]) || ''
);
var counterpartyName = firstValue(item, [
'counterparty_username',
'counterpartyUsername',
'counterparty_name',
'counterpartyName',
]);
var counterpartyAvatar = firstValue(item, [
'counterparty_avatar',
'counterpartyAvatar',
]);
var counterpartyUID = counterpartyDisplayID || counterpartyUserID;
// 入账流水也可能来自某个用户的工资转币商,标题必须优先展示对方资料;只有后台进货这类没有对方用户的流水才展示库存入账。
var name =
counterpartyName ||
(counterpartyUID
? t(
'coinseller_center.user_name_template',
'User {id}'
).replace('{id}', counterpartyUID)
: type === 'income'
? t('coinseller_center.stock_transfer', 'Stock transfer')
: t('coinseller_center.transfer_out', 'Transfer out'));
var uid =
counterpartyUID ||
(type === 'income' ? t('coinseller_center.system', 'System') : '-');
var transferAmount = normalizeTransferAmount(item);
return {
id:
firstValue(item, ['transaction_id', 'transactionId']) ||
String(firstValue(item, ['entry_id', 'entryId']) || index),
type: type,
name: name,
uid: uid,
avatar:
counterpartyAvatar ||
avatarData(
name,
type === 'income' ? '#e7f7f3' : '#dbc8ff',
type === 'income' ? '#31a88f' : '#7d57c7'
),
coins: Math.abs(delta),
amount: transferAmount,
currency: normalizeTransferCurrency(item, transferAmount),
time: timeLabelFromMS(
firstValue(item, ['created_at_ms', 'createdAtMs'])
),
};
}
function normalizeTransactions(payload) {
var source = unwrapData(payload) || {};
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 normalizeTransactionRecord(item || {}, index);
});
}
function applyMockData() {
data.profile = Object.assign({}, mock.profile);
data.balance = Object.assign({}, mock.balance);
data.users = mock.users.slice();
data.quickAmounts = mock.quickAmounts.slice();
data.records = mock.records.slice();
}
function applyEmptyData() {
data.profile = emptyProfile();
data.balance = { coins: 0 };
data.users = [];
data.quickAmounts = mock.quickAmounts.slice();
data.records = [];
}
function loadRealData() {
if (!hasAPI()) {
toast(
t(
'coinseller_center.load_failed',
'Load failed. Try again later.'
)
);
return Promise.resolve();
}
state.loading = true;
render();
return Promise.all([
window.HyAppAPI.user.me(),
window.HyAppAPI.wallet.balances(SELLER_ASSET_TYPE),
window.HyAppAPI.wallet.transactions
? window.HyAppAPI.wallet
.transactions({
asset_type: SELLER_ASSET_TYPE,
page: 1,
page_size: 20,
})
.catch(function (error) {
if (window.console && window.console.warn) {
window.console.warn(
'[coinseller-center] records api failed',
error
);
}
return null;
})
: Promise.resolve(null),
])
.then(function (results) {
data.profile = normalizeProfile(results[0]);
data.balance = normalizeBalance(results[1]);
data.records = normalizeTransactions(results[2]);
})
.catch(function (error) {
if (window.console && window.console.warn) {
window.console.warn(
'[coinseller-center] api failed',
error
);
}
toast(
t(
'coinseller_center.load_failed',
'Load failed. Try again later.'
)
);
})
.finally(function () {
state.loading = false;
render();
});
}
function renderProfile() {
var image = $('profileAvatar');
var fallback = $('profileAvatarFallback');
var profile = data.profile;
var loading = !!state.loading;
setSkeleton($('profileName'), loading, profile.name || '');
setSkeleton(
$('profileUID'),
loading,
profile.uid
? t('coinseller_center.uid_prefix', 'UID: {id}').replace(
'{id}',
profile.uid
)
: ''
);
fallback.classList.toggle('avatar-skeleton', loading);
if (loading) {
image.hidden = true;
image.removeAttribute('src');
fallback.hidden = false;
fallback.textContent = '';
return;
}
setImage(image, fallback, profile.avatar, profile.name || profile.uid);
}
function renderBalance() {
setSkeleton($('coinBalance'), state.loading, count(data.balance.coins));
var coinIcon = document.querySelector('.balance-value .coin-icon');
if (coinIcon) {
coinIcon.classList.toggle('skeleton-coin', !!state.loading);
}
}
function renderQuickAmounts() {
replaceChildren(
$('quickAmounts'),
data.quickAmounts.map(function (amount) {
var button = document.createElement('button');
button.className =
'quick-amount' +
(String(amount) === state.coinAmount ? ' is-active' : '');
button.type = 'button';
button.textContent = count(amount);
button.addEventListener('click', function () {
state.coinAmount = String(amount);
$('coinAmountInput').value = state.coinAmount;
setStatus($('rechargeStatus'), '', '');
renderRechargeState();
});
return button;
})
);
}
function renderTarget() {
var card = $('targetCard');
if (!state.target) {
card.hidden = true;
$('rechargeTargetName').textContent = '-';
return;
}
card.hidden = false;
renderAvatar($('targetAvatar'), state.target);
$('targetName').textContent = state.target.name;
$('targetUID').textContent = t(
'coinseller_center.uid_prefix',
'UID: {id}'
).replace('{id}', state.target.uid);
$('rechargeTargetName').textContent =
t('coinseller_center.target_user', 'Target user') +
': ' +
state.target.name;
}
function parsedCoinAmount() {
var input = $('coinAmountInput');
if (input) {
var sanitized = String(input.value || '').replace(/[^\d]/g, '');
if (input.value !== sanitized) input.value = sanitized;
state.coinAmount = sanitized;
}
return Number(state.coinAmount || 0);
}
function renderRechargeState() {
var amount = parsedCoinAmount();
var disabled =
state.loading ||
state.submitting ||
state.searching ||
!state.target ||
amount <= 0;
$('rechargeButton').disabled = disabled;
$('searchButton').disabled = state.searching;
renderQuickAmounts();
}
function recordMatchesQuery(record) {
if (!state.historyQuery) return true;
var keyword = state.historyQuery.toLowerCase();
return (
String(record.name || '')
.toLowerCase()
.indexOf(keyword) >= 0 ||
String(record.uid || '')
.toLowerCase()
.indexOf(keyword) >= 0
);
}
function visibleHistoryRecords() {
return data.records
.filter(function (record) {
return (
record.type === state.historyTab &&
recordMatchesQuery(record)
);
})
.slice(0, state.historyLimit);
}
function createRecordRow(record) {
var row = document.createElement('article');
var avatar = document.createElement('div');
var main = document.createElement('div');
var title = document.createElement('div');
var metaGroup = document.createElement('div');
var meta = document.createElement('div');
var transfer = document.createElement('span');
var side = document.createElement('div');
var amount = document.createElement('strong');
var time = document.createElement('span');
row.className = 'record-row';
avatar.className = 'record-avatar';
main.className = 'record-main';
title.className = 'record-title';
metaGroup.className = 'record-meta-group';
meta.className = 'record-meta';
transfer.className = 'record-transfer';
side.className =
'record-side' + (record.type === 'income' ? ' is-income' : '');
renderAvatar(avatar, record);
title.textContent = record.name || '-';
meta.textContent = t(
'coinseller_center.uid_prefix',
'UID: {id}'
).replace('{id}', record.uid || '-');
transfer.textContent = formatTransferAmount(
record.amount,
record.currency
);
amount.textContent =
(record.type === 'income' ? '+' : '-') +
count(record.coins) +
' ' +
t('coinseller_center.coins_lower', 'coins');
time.textContent = record.time || '';
main.appendChild(title);
metaGroup.appendChild(meta);
if (transfer.textContent) metaGroup.appendChild(transfer);
main.appendChild(metaGroup);
side.appendChild(amount);
side.appendChild(time);
row.appendChild(avatar);
row.appendChild(main);
row.appendChild(side);
return row;
}
function renderRecent() {
replaceChildren(
$('recentList'),
data.records.slice(0, 3).map(function (record) {
return createRecordRow(record);
})
);
}
function renderHistory() {
document.querySelectorAll('[data-history-tab]').forEach(function (tab) {
var active =
tab.getAttribute('data-history-tab') === state.historyTab;
tab.classList.toggle('is-active', active);
tab.setAttribute('aria-selected', String(active));
});
var all = data.records.filter(function (record) {
return (
record.type === state.historyTab && recordMatchesQuery(record)
);
});
var records = visibleHistoryRecords();
$('loadMoreButton').hidden = records.length >= all.length;
setStatus(
$('historyStatus'),
all.length
? ''
: t(
'coinseller_center.no_transaction_records',
'No transaction records'
),
all.length ? '' : 'warning'
);
replaceChildren(
$('historyList'),
records.map(function (record) {
return createRecordRow(record);
})
);
}
function findMockUser(keyword) {
var normalized = String(keyword || '')
.trim()
.toLowerCase();
return data.users.find(function (user) {
return (
String(user.uid || '')
.toLowerCase()
.indexOf(normalized) >= 0 ||
String(user.name || '')
.toLowerCase()
.indexOf(normalized) >= 0
);
});
}
function findUser(keyword) {
if (state.isMock) {
return Promise.resolve(findMockUser(keyword) || null);
}
if (!hasAPI() || !window.HyAppAPI.user.resolveDisplayUserID) {
return Promise.reject(new Error('api_not_ready'));
}
return window.HyAppAPI.user
.resolveDisplayUserID(keyword)
.then(function (payload) {
return normalizeResolvedUser(payload, keyword);
});
}
function handleSearch(value) {
state.searching = true;
setStatus(
$('searchStatus'),
t('coinseller_center.loading', 'Loading...'),
''
);
renderRechargeState();
findUser(value)
.then(function (user) {
if (!user) {
state.target = null;
renderTarget();
renderRechargeState();
setStatus(
$('searchStatus'),
t(
'coinseller_center.user_not_found',
'User not found.'
),
'warning'
);
return;
}
state.target = user;
renderTarget();
renderRechargeState();
setStatus($('searchStatus'), '', '');
})
.catch(function (error) {
if (window.console && window.console.warn) {
window.console.warn(
'[coinseller-center] user search failed',
error
);
}
state.target = null;
renderTarget();
renderRechargeState();
setStatus(
$('searchStatus'),
t('coinseller_center.user_not_found', 'User not found.'),
'warning'
);
})
.finally(function () {
state.searching = false;
renderRechargeState();
});
}
function commandID() {
return [
'coin-seller-transfer',
Date.now(),
Math.random().toString(36).slice(2, 8),
].join('-');
}
function buildTransferPayload(amount) {
return {
command_id: commandID(),
target_display_user_id: String(state.target.uid || '').trim(),
amount: amount,
reason: 'player recharge',
};
}
function appendTransferRecord(amount, response) {
var payload = unwrapData(response) || {};
var coins = toNumber(
firstValue(payload, ['amount', 'coin_amount', 'coinAmount'])
);
var transferAmount = normalizeTransferAmount(payload);
data.records.unshift({
id:
firstValue(payload, ['transaction_id', 'transactionId']) ||
'tx-' + Date.now(),
type: 'expenditure',
name: state.target.name,
uid: state.target.uid,
avatar: state.target.avatar,
coins: coins || amount,
amount: transferAmount,
currency: normalizeTransferCurrency(payload, transferAmount),
time: currentTimeLabel(),
});
}
function rechargeNow() {
var amount = parsedCoinAmount();
if (!state.target) {
setStatus(
$('rechargeStatus'),
t(
'coinseller_center.select_user_first',
'Select a user first.'
),
'warning'
);
return;
}
if (amount <= 0) {
setStatus(
$('rechargeStatus'),
t(
'coinseller_center.valid_amount_required',
'Please enter a valid amount.'
),
'warning'
);
return;
}
if (amount > data.balance.coins) {
setStatus(
$('rechargeStatus'),
t(
'coinseller_center.amount_exceeds_stock',
'Amount exceeds stock.'
),
'warning'
);
return;
}
if (state.isMock) {
data.balance.coins -= amount;
appendTransferRecord(amount, {});
finishRecharge();
return;
}
if (!hasAPI() || !window.HyAppAPI.wallet.transferCoinFromSeller) {
setStatus($('rechargeStatus'), '', '');
toast(t('coinseller_center.transfer_failed', 'Transfer failed.'));
return;
}
state.submitting = true;
setStatus(
$('rechargeStatus'),
t('coinseller_center.loading', 'Loading...'),
''
);
renderRechargeState();
window.HyAppAPI.wallet
.transferCoinFromSeller(buildTransferPayload(amount))
.then(function (response) {
var payload = unwrapData(response) || {};
var balanceAfter = toNumber(
firstValue(payload, [
'seller_balance_after',
'sellerBalanceAfter',
])
);
if (balanceAfter > 0 || payload.seller_balance_after === 0) {
data.balance.coins = balanceAfter;
} else {
data.balance.coins -= amount;
}
appendTransferRecord(amount, response);
finishRecharge();
})
.catch(function (error) {
if (window.console && window.console.warn) {
window.console.warn(
'[coinseller-center] transfer failed',
error
);
}
setStatus($('rechargeStatus'), '', '');
toast(
error && error.message
? error.message
: t(
'coinseller_center.transfer_failed',
'Transfer failed.'
)
);
})
.finally(function () {
state.submitting = false;
renderRechargeState();
});
}
function finishRecharge() {
state.coinAmount = '';
$('coinAmountInput').value = '';
setStatus(
$('rechargeStatus'),
t('coinseller_center.recharge_success', 'Recharge success.'),
'success'
);
renderBalance();
renderRecent();
renderRechargeState();
if (!$('historyModal').hidden) renderHistory();
closeModal('rechargeModal');
toast(t('coinseller_center.recharge_success', 'Recharge success.'));
}
function currentTimeLabel() {
var now = new Date();
return (
now.getFullYear() +
'-' +
String(now.getMonth() + 1).padStart(2, '0') +
'-' +
String(now.getDate()).padStart(2, '0') +
' ' +
String(now.getHours()).padStart(2, '0') +
':' +
String(now.getMinutes()).padStart(2, '0')
);
}
function openModal(id) {
var modal = $(id);
if (!modal) return;
modal.hidden = false;
modal.setAttribute('aria-hidden', 'false');
document.body.classList.add('modal-open');
}
function closeModal(id) {
var modal = $(id);
if (!modal) return;
modal.hidden = true;
modal.setAttribute('aria-hidden', 'true');
var hasOpen = Array.prototype.some.call(
document.querySelectorAll('.sheet-modal'),
function (node) {
return !node.hidden;
}
);
document.body.classList.toggle('modal-open', hasOpen);
}
function bindEvents() {
$('backButton').addEventListener('click', function () {
if (window.HyAppBridge) window.HyAppBridge.back();
});
$('historyButton').addEventListener('click', function () {
state.historyLimit = 3;
renderHistory();
openModal('historyModal');
});
$('viewAllHistoryButton').addEventListener('click', function () {
state.historyLimit = 3;
renderHistory();
openModal('historyModal');
});
$('helpButton').addEventListener('click', function () {
openModal('helpModal');
});
document
.querySelectorAll('[data-close-modal]')
.forEach(function (node) {
node.addEventListener('click', function () {
closeModal(node.getAttribute('data-close-modal'));
});
});
$('searchForm').addEventListener('submit', function (event) {
event.preventDefault();
var value = $('userSearchInput').value.trim();
if (!value) {
setStatus(
$('searchStatus'),
t('coinseller_center.enter_user_id', 'Enter user ID'),
'warning'
);
return;
}
handleSearch(value);
});
$('openRechargeButton').addEventListener('click', function () {
if (!state.target) return;
state.coinAmount = '';
$('coinAmountInput').value = '';
setStatus($('rechargeStatus'), '', '');
renderRechargeState();
openModal('rechargeModal');
window.setTimeout(function () {
$('coinAmountInput').focus();
}, 80);
});
$('coinAmountInput').addEventListener('input', function () {
state.coinAmount = $('coinAmountInput').value.replace(/[^\d]/g, '');
$('coinAmountInput').value = state.coinAmount;
setStatus($('rechargeStatus'), '', '');
renderRechargeState();
});
$('rechargeForm').addEventListener('submit', function (event) {
event.preventDefault();
rechargeNow();
});
document.querySelectorAll('[data-history-tab]').forEach(function (tab) {
tab.addEventListener('click', function () {
state.historyTab = tab.getAttribute('data-history-tab');
state.historyLimit = 3;
renderHistory();
});
});
$('historySearchForm').addEventListener('submit', function (event) {
event.preventDefault();
state.historyQuery = $('historySearchInput').value.trim();
state.historyLimit = 3;
renderHistory();
});
$('historyClearButton').addEventListener('click', function () {
state.historyQuery = '';
$('historySearchInput').value = '';
state.historyLimit = 3;
renderHistory();
});
$('loadMoreButton').addEventListener('click', function () {
state.historyLimit += 3;
renderHistory();
});
document.addEventListener('keydown', function (event) {
if (event.key !== 'Escape') return;
closeModal('historyModal');
closeModal('helpModal');
});
}
function render() {
renderProfile();
renderBalance();
renderQuickAmounts();
renderTarget();
renderRechargeState();
renderRecent();
}
function init() {
if (state.isMock) {
applyMockData();
} else {
applyEmptyData();
}
render();
bindEvents();
if (window.HyAppBridge) {
window.HyAppBridge.ready({
page: 'coinseller-center',
mock: state.isMock,
});
}
if (!state.isMock) loadRealData();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
window.addEventListener('hyapp:i18n-ready', function () {
render();
if (!$('historyModal').hidden) renderHistory();
});
})();