(function () { var FIRST_BILL_MONTH = '2026-06'; var BD_SALARY_ASSET = 'BD_SALARY_USD'; var data = { profile: null, balance: { available: 0 }, billMonth: currentMonth(), agencyBill: { agencyNumber: 0, totalSalary: 0, totalRecharge: 0, memberBillList: [], }, inviteRecords: [], }; var state = { billMonth: normalizeBillMonth(data.billMonth), inviteQuery: '', inviteMode: 'records', inviteStatus: '', inviteStatusType: '', searched: [], inviting: {}, searching: false, loading: true, }; function $(id) { return document.getElementById(id); } function api() { return window.HyAppAPI || {}; } function centerAPI() { return api().bdCenter || null; } function t(key, fallback) { return window.HyAppI18n && window.HyAppI18n.t ? window.HyAppI18n.t(key, fallback) : fallback || key; } function avatarData(text, background, foreground) { var raw = String(text || 'B') .trim() .charAt(0) || 'B'; var letter = raw.replace(/[<>&"']/g, ''); var svg = '' + '' + '' + letter + '' + ''; return 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(svg); } function currentMonth() { var now = new Date(); return ( String(now.getFullYear()) + '-' + String(now.getMonth() + 1).padStart(2, '0') ); } function monthDate(value) { var parts = String(value || currentMonth()).split('-'); var year = Number(parts[0]) || new Date().getFullYear(); var month = Number(parts[1]) || new Date().getMonth() + 1; return new Date(year, month - 1, 1); } function monthValue(date) { return ( String(date.getFullYear()) + '-' + String(date.getMonth() + 1).padStart(2, '0') ); } function monthTime(value) { return monthDate(value).getTime(); } function normalizeBillMonth(value) { if (monthTime(value) < monthTime(FIRST_BILL_MONTH)) { return FIRST_BILL_MONTH; } if (monthTime(value) > monthTime(currentMonth())) { return currentMonth(); } return monthValue(monthDate(value)); } function monthLabel(value) { var date = monthDate(value); return ( String(date.getFullYear()) + '年' + String(date.getMonth() + 1).padStart(2, '0') + '月' ); } function monthOptions() { var options = []; var cursor = monthDate(currentMonth()); var first = monthDate(FIRST_BILL_MONTH); while (cursor.getTime() >= first.getTime()) { options.push(new Date(cursor.getFullYear(), cursor.getMonth(), 1)); cursor = new Date(cursor.getFullYear(), cursor.getMonth() - 1, 1); } return options; } function money(value) { var number = Number(value || 0); return number.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2, }); } function count(value) { return Number(value || 0).toLocaleString('en-US', { maximumFractionDigits: 0, }); } function initial(text) { return String(text || '') .trim() .charAt(0) .toUpperCase(); } function firstValue(item, keys) { if (!item) return ''; for (var i = 0; i < keys.length; i += 1) { var value = item[keys[i]]; if (value !== undefined && value !== null && value !== '') { return value; } } return ''; } function displayName(user, fallback) { return ( firstValue(user, ['username', 'name', 'display_user_id']) || fallback || '-' ); } function displayID(user, fallback) { return ( firstValue(user, ['display_user_id', 'displayUserID']) || firstValue(user, ['user_id', 'userId', 'id']) || fallback || '-' ); } function salaryAmount(salary) { if (!salary) return 0; if (salary.display_amount !== undefined) return Number(salary.display_amount); if (salary.displayAmount !== undefined) return Number(salary.displayAmount); if (salary.available_amount !== undefined) { return Number(salary.available_amount || 0) / 100; } if (salary.availableAmount !== undefined) { return Number(salary.availableAmount || 0) / 100; } return 0; } function toast(message) { if (window.HyAppToast) { window.HyAppToast.show(message); return; } window.alert(message); } function replaceChildren(node, children) { node.textContent = ''; children.forEach(function (child) { node.appendChild(child); }); } function setSkeleton(element, loading, text) { if (!element) return; element.classList.toggle('skeleton-line', Boolean(loading)); if (loading) { element.textContent = ''; return; } element.textContent = text || ''; } function renderImageAvatar(container, src, name, fallbackClass) { container.textContent = ''; if (!src) { var fallback = document.createElement('span'); fallback.className = fallbackClass || 'member-fallback'; fallback.textContent = initial(name) || 'B'; container.appendChild(fallback); return; } var image = document.createElement('img'); image.src = src; image.alt = ''; image.addEventListener('error', function () { container.textContent = ''; var fallback = document.createElement('span'); fallback.className = fallbackClass || 'member-fallback'; fallback.textContent = initial(name) || 'B'; container.appendChild(fallback); }); container.appendChild(image); } function normalizeProfile(payload) { var profile = payload && payload.profile ? payload.profile : payload || {}; var name = displayName(profile, 'BD'); return { name: name, uid: displayID(profile), avatar: firstValue(profile, ['avatar']) || avatarData(initial(name) || 'B', '#dbc8ff', '#7d57c7'), }; } function normalizeAgencyItem(item) { var agency = (item && item.agency) || item || {}; var owner = (item && item.owner) || {}; var name = firstValue(agency, ['name']) || displayName(owner, 'Agency ' + displayID(owner, displayID(agency))); var account = firstValue(agency, ['agency_id', 'agencyId']) || displayID(owner, displayID(agency)); return { name: name, account: account, avatar: firstValue(agency, ['avatar']) || firstValue(owner, ['avatar']) || avatarData(initial(name) || 'A', '#dbc8ff', '#7d57c7'), teamSalaryAmount: Number(firstValue(item, ['team_salary', 'teamSalary']) || 0), teamRechargeAmount: Number(firstValue(item, ['team_recharge', 'teamRecharge']) || 0), teamMemberCount: Number( firstValue(item, ['host_count', 'hostCount']) || firstValue(agency, ['host_count', 'hostCount']) || 0 ), }; } function applyOverview(payload) { var overview = payload && payload.overview ? payload.overview : {}; data.profile = normalizeProfile(payload || {}); data.balance = { available: salaryAmount(payload && payload.salary) }; data.agencyBill.agencyNumber = Number( firstValue(overview, ['total_agency', 'totalAgency']) || 0 ); } function applyAgencies(payload) { var items = payload && (payload.items || payload.agencies) ? payload.items || payload.agencies : []; var rows = items.map(normalizeAgencyItem); data.agencyBill.memberBillList = rows; data.agencyBill.agencyNumber = rows.length; data.agencyBill.totalSalary = rows.reduce(function (sum, item) { return sum + Number(item.teamSalaryAmount || 0); }, 0); data.agencyBill.totalRecharge = rows.reduce(function (sum, item) { return sum + Number(item.teamRechargeAmount || 0); }, 0); } function normalizeInviteProfile(payload, fallbackID) { var user = payload && (payload.user || payload.profile || payload); if (!user) return null; var userID = firstValue(user, ['user_id', 'userId', 'id']); if (!userID) return null; var account = displayID(user, fallbackID); var name = displayName(user, 'User ' + account); return { userId: String(userID), id: String(userID), name: name, account: account, avatar: firstValue(user, ['avatar']) || avatarData(initial(name) || 'U', '#dbc8ff', '#7d57c7'), }; } function renderProfile() { var image = $('profileAvatar'); var fallback = $('profileAvatarFallback'); var profile = data.profile || {}; var loading = Boolean(state.loading); setSkeleton($('profileName'), loading, profile.name || '-'); setSkeleton( $('profileUID'), loading, 'UID: ' + (profile.uid || '-') ); fallback.classList.toggle('avatar-skeleton', loading); if (loading) { image.hidden = true; image.removeAttribute('src'); fallback.hidden = false; fallback.textContent = ''; return; } fallback.textContent = initial(profile.name) || 'B'; image.onload = function () { image.hidden = false; fallback.hidden = true; }; image.onerror = function () { image.hidden = true; fallback.hidden = false; }; image.src = profile.avatar || ''; if (!profile.avatar) { image.hidden = true; fallback.hidden = false; } } function renderBalance() { var loading = Boolean(state.loading); var coinIcon = document.querySelector('.salary-value .coin-icon'); if (coinIcon) coinIcon.classList.toggle('skeleton-coin', loading); setSkeleton( $('availableBalance'), loading, money(data.balance && data.balance.available) ); } function summaryCell(label, value) { var cell = document.createElement('div'); var labelNode = document.createElement('span'); var valueNode = document.createElement('strong'); labelNode.textContent = label; valueNode.textContent = value; cell.appendChild(labelNode); cell.appendChild(valueNode); return cell; } function summarySkeletonCell() { var cell = document.createElement('div'); var labelNode = document.createElement('span'); var valueNode = document.createElement('strong'); labelNode.className = 'skeleton-line'; valueNode.className = 'skeleton-line'; cell.appendChild(labelNode); cell.appendChild(valueNode); return cell; } function skeletonMemberRow() { var row = document.createElement('article'); var avatar = document.createElement('div'); var main = document.createElement('div'); var name = document.createElement('div'); var meta = document.createElement('div'); var side = document.createElement('div'); row.className = 'member-row is-skeleton'; avatar.className = 'member-avatar avatar-skeleton'; main.className = 'member-main'; name.className = 'member-name skeleton-line'; meta.className = 'member-meta skeleton-line'; side.className = 'member-side'; for (var i = 0; i < 3; i += 1) { var line = document.createElement('div'); line.className = 'skeleton-line'; side.appendChild(line); } main.appendChild(name); main.appendChild(meta); row.appendChild(avatar); row.appendChild(main); row.appendChild(side); return row; } function memberRow(item) { var row = document.createElement('article'); var avatar = document.createElement('div'); var main = document.createElement('div'); var name = document.createElement('div'); var meta = document.createElement('div'); var side = document.createElement('div'); row.className = 'member-row'; avatar.className = 'member-avatar'; main.className = 'member-main'; name.className = 'member-name'; meta.className = 'member-meta'; side.className = 'member-side'; renderImageAvatar(avatar, item.avatar, item.name); name.textContent = item.name || '-'; meta.textContent = 'UID: ' + (item.account || '-'); [ t('bd_center.team_salary', 'Team salary') + ': $' + money(item.teamSalaryAmount), t('bd_center.recharge', 'Recharge') + ': $' + money(item.teamRechargeAmount), t('bd_center.host', 'Host') + ': ' + count(item.teamMemberCount), ].forEach(function (line) { var node = document.createElement('div'); node.textContent = line; side.appendChild(node); }); main.appendChild(name); main.appendChild(meta); row.appendChild(avatar); row.appendChild(main); row.appendChild(side); return row; } function renderTeamList() { var bill = data.agencyBill; $('billMonthText').textContent = monthLabel(state.billMonth); $('billRange').textContent = state.billMonth.replace('-', '.'); if (state.loading) { replaceChildren($('teamListSummary'), [ summarySkeletonCell(), summarySkeletonCell(), ]); replaceChildren($('teamListContent'), [ skeletonMemberRow(), skeletonMemberRow(), skeletonMemberRow(), ]); return; } replaceChildren($('teamListSummary'), [ summaryCell( t('bd_center.agency_number', 'Agency number'), count(bill.agencyNumber) ), summaryCell( t('bd_center.team_salary', 'Team salary'), '$' + money(bill.totalSalary) ), ]); var rows = (bill.memberBillList || []).map(memberRow); if (!rows.length) { var empty = document.createElement('div'); empty.className = 'empty-state'; empty.textContent = t('bd_center.no_data', 'No data'); rows = [empty]; } replaceChildren($('teamListContent'), rows); } function monthOption(date) { var value = monthValue(date); var option = document.createElement('button'); option.className = 'month-option'; option.type = 'button'; option.setAttribute('role', 'option'); option.setAttribute('data-month', value); option.setAttribute('aria-selected', String(value === state.billMonth)); option.textContent = monthLabel(value); if (value === state.billMonth) option.classList.add('is-selected'); return option; } function renderMonthSheet() { replaceChildren( $('monthOptionList'), monthOptions().map(function (date) { return monthOption(date); }) ); } function openMonthSheet() { renderMonthSheet(); $('monthSheet').hidden = false; $('monthSheet').setAttribute('aria-hidden', 'false'); document.body.classList.add('modal-open'); window.setTimeout(function () { var selected = $('monthOptionList').querySelector('.is-selected'); if (selected && selected.scrollIntoView) { selected.scrollIntoView({ block: 'center' }); } }, 0); } function closeMonthSheet() { $('monthSheet').hidden = true; $('monthSheet').setAttribute('aria-hidden', 'true'); document.body.classList.remove('modal-open'); } function selectMonth(value) { var nextMonth = normalizeBillMonth(value); if (!nextMonth || nextMonth === state.billMonth) { closeMonthSheet(); return; } state.billMonth = nextMonth; closeMonthSheet(); renderTeamList(); } function inviteProfile(item) { return item.profile || item; } function statusLabel(status) { if (status === 'success' || status === 'Success' || status === 'accepted') { return t('bd_center.success', 'Success'); } if (status === 'pending' || status === 'Pending') return t('bd_center.pending', 'Pending'); return ''; } function commandID(prefix, targetUserID) { return [ prefix, targetUserID, Date.now(), Math.random().toString(16).slice(2), ].join('-'); } function inviteCard(item) { var profile = inviteProfile(item); var status = item.status || ''; var card = document.createElement('article'); var avatar = document.createElement('div'); var main = document.createElement('div'); var name = document.createElement('div'); var meta = document.createElement('div'); var side = document.createElement('div'); card.className = 'invite-user-card'; avatar.className = 'invite-user-avatar'; main.className = 'invite-user-main'; name.className = 'invite-user-name'; meta.className = 'invite-user-meta'; side.className = 'invite-user-side'; renderImageAvatar( avatar, profile.avatar, profile.name, 'invite-avatar-fallback' ); name.textContent = profile.name || '-'; meta.textContent = 'UID: ' + (profile.account || '-'); main.appendChild(name); main.appendChild(meta); if (status) { var badge = document.createElement('span'); badge.className = 'invite-badge ' + (status === 'pending' || status === 'Pending' ? 'pending' : 'success'); badge.textContent = statusLabel(status); side.appendChild(badge); } else { var targetUserID = String(profile.userId || profile.id || ''); var invite = document.createElement('button'); invite.className = 'invite-action'; invite.type = 'button'; invite.disabled = Boolean(state.inviting[targetUserID]); invite.textContent = state.inviting[targetUserID] ? t('bd_center.pending', 'Pending') : t('bd_center.invite', 'Invite'); invite.addEventListener('click', function () { submitInvite(profile); }); side.appendChild(invite); } card.appendChild(avatar); card.appendChild(main); card.appendChild(side); return card; } function setInviteStatus(text, type) { var node = $('inviteStatus'); node.textContent = text || ''; node.hidden = !text; node.classList.toggle('is-error', type === 'error'); node.classList.toggle('is-success', type === 'success'); } function renderInviteModal() { var rows = state.inviteMode === 'search' ? state.searched.map(inviteCard) : data.inviteRecords.map(inviteCard); setInviteStatus(state.inviteStatus, state.inviteStatusType); replaceChildren($('inviteList'), rows); $('inviteEmpty').hidden = rows.length > 0 || Boolean(state.inviteStatus); $('inviteSearchButton').disabled = !state.inviteQuery.trim() || Boolean(state.searching); } function openInviteModal() { state.inviteQuery = ''; state.inviteMode = 'records'; state.searched = []; state.inviteStatus = ''; state.inviteStatusType = ''; state.searching = false; $('inviteSearchInput').value = ''; $('inviteModal').hidden = false; $('inviteModal').setAttribute('aria-hidden', 'false'); document.body.classList.add('modal-open'); renderInviteModal(); window.setTimeout(function () { $('inviteSearchInput').focus(); }, 80); } function closeInviteModal() { $('inviteModal').hidden = true; $('inviteModal').setAttribute('aria-hidden', 'true'); document.body.classList.remove('modal-open'); } function searchInvite(event) { event.preventDefault(); var queryValue = state.inviteQuery.trim(); state.inviteMode = 'search'; state.inviteStatus = ''; state.inviteStatusType = ''; state.searched = []; if (!queryValue) { renderInviteModal(); return; } if (!api().user || !api().user.resolveDisplayUserID) { state.inviteStatus = t( 'bd_center.api_not_ready', 'API module is not ready.' ); state.inviteStatusType = 'error'; renderInviteModal(); return; } state.inviteStatus = t('bd_center.searching', 'Searching...'); state.searching = true; renderInviteModal(); api() .user.resolveDisplayUserID(queryValue) .then(function (payload) { var profile = normalizeInviteProfile(payload, queryValue); state.inviteStatus = profile ? '' : t('bd_center.no_users_found', 'No users found'); state.inviteStatusType = ''; state.searched = profile ? [profile] : []; renderInviteModal(); }) .catch(function (error) { state.inviteStatus = (error && error.message) || t('bd_center.search_failed', 'Search failed. Try again later.'); state.inviteStatusType = 'error'; state.searched = []; renderInviteModal(); }) .finally(function () { state.searching = false; renderInviteModal(); }); } function submitInvite(profile) { var targetUserID = String(profile.userId || profile.id || ''); if (!targetUserID) return; if (!centerAPI() || !centerAPI().inviteAgency) { state.inviteStatus = t( 'bd_center.api_not_ready', 'API module is not ready.' ); state.inviteStatusType = 'error'; renderInviteModal(); return; } state.inviting[targetUserID] = true; renderInviteModal(); centerAPI() .inviteAgency({ command_id: commandID('bd-agency', targetUserID), target_user_id: targetUserID, agency_name: profile.name, }) .then(function () { data.inviteRecords.unshift({ id: 'inv-' + Date.now(), status: 'success', profile: profile, }); state.inviteMode = 'records'; state.searched = []; state.inviteStatus = t('bd_center.agency_added', 'Agency added.'); state.inviteStatusType = 'success'; loadRealData().catch(function () {}); renderInviteModal(); }) .catch(function (error) { state.inviteStatus = (error && error.message) || t('bd_center.invite_failed', 'Invite failed. Try again later.'); state.inviteStatusType = 'error'; renderInviteModal(); }) .finally(function () { delete state.inviting[targetUserID]; renderInviteModal(); }); } function navigateToWithdrawExchange() { var params = new URLSearchParams(window.location.search); params.set('identity', 'BD'); params.set('salaryType', BD_SALARY_ASSET); params.set('asset_type', BD_SALARY_ASSET); if (!params.has('mode')) params.set('mode', 'withdraw'); window.location.href = '../withdraw-exchange/index.html?' + params.toString(); } function setLoading(loading) { state.loading = Boolean(loading); render(); } function loadRealData() { var service = centerAPI(); setLoading(true); if ( !service || !service.overview || !service.agencies || !service.inviteAgency ) { setLoading(false); return Promise.reject( new Error(t('bd_center.api_not_ready', 'API module is not ready.')) ); } return Promise.all([ service.overview(), service.agencies(50), ]).then(function (results) { applyOverview(results[0] || {}); applyAgencies(results[1] || {}); return true; }).catch(function (error) { data.profile = null; data.balance = { available: 0 }; data.agencyBill = { agencyNumber: 0, totalSalary: 0, totalRecharge: 0, memberBillList: [], }; throw error; }).finally(function () { setLoading(false); }); } function bindEvents() { $('backButton').addEventListener('click', function () { if (window.HyAppBridge) { window.HyAppBridge.back(); return; } if (window.history.length > 1) window.history.back(); }); $('withdrawExchangeButton').addEventListener( 'click', navigateToWithdrawExchange ); $('inviteAgentButton').addEventListener('click', openInviteModal); $('inviteBackdrop').addEventListener('click', closeInviteModal); $('inviteCloseButton').addEventListener('click', closeInviteModal); $('inviteSearchInput').addEventListener('input', function (event) { state.inviteQuery = event.target.value; if (!state.inviteQuery.trim()) { state.inviteMode = 'records'; state.searched = []; state.inviteStatus = ''; state.inviteStatusType = ''; } renderInviteModal(); }); $('inviteSearchForm').addEventListener('submit', searchInvite); $('billMonthButton').addEventListener('click', openMonthSheet); $('monthSheetBackdrop').addEventListener('click', closeMonthSheet); $('monthSheetCloseButton').addEventListener('click', closeMonthSheet); $('monthOptionList').addEventListener('click', function (event) { var option = event.target.closest('[data-month]'); if (!option) return; selectMonth(option.getAttribute('data-month')); }); } function render() { renderProfile(); renderBalance(); renderTeamList(); renderInviteModal(); } document.addEventListener('DOMContentLoaded', function () { render(); bindEvents(); loadRealData().catch(function (error) { toast( (error && error.message) || t('bd_center.load_failed', 'Load failed. Try again later.') ); }); if (window.HyAppBridge) { window.HyAppBridge.ready({ page: 'bd-center', }); } }); window.addEventListener('hyapp:i18n-ready', function () { render(); }); })();