(function () { var ACTION_LABELS = { 'block-user': 'Block User', 'send-frame': 'Send Frame', 'send-car': 'Send Car', 'send-vip': 'Send VIP', 'update-user-level': 'Update User Level', }; var DAY_MS = 24 * 60 * 60 * 1000; var PERMANENT_BLOCK_MS = 10 * 365 * DAY_MS; var RESOURCE_TYPES = { 'send-frame': 'avatar_frame', 'send-car': 'vehicle', }; var RESOURCE_GRANT_DURATIONS = [ { label: '7 days', ms: 7 * DAY_MS }, { label: '30 days', ms: 30 * DAY_MS }, { label: '90 days', ms: 90 * DAY_MS }, ]; var DEFAULT_RESOURCE_GRANT_DURATION_MS = RESOURCE_GRANT_DURATIONS[0].ms; var TRACK_LABELS = { wealth: 'Wealth', charm: 'Charm', game: 'Game', }; var api = window.HyAppAPI && window.HyAppAPI.managerCenter; var pageState = { loading: true, denied: false, overview: null, resourcesByType: {}, }; var blockState = { searchedUser: null, selectedDurationMs: 0, selectedDurationLabel: '', blockedUsers: [], submitting: false, }; var levelState = { searchedUser: null, selectedTrack: 'wealth', selectedLevel: 0, submitting: false, }; var grantState = { action: '', resourceType: '', title: '', searchedUser: null, selectedResourceId: '', selectedResourceDurationMs: DEFAULT_RESOURCE_GRANT_DURATION_MS, selectedVipLevel: 0, submitting: false, }; function $(id) { return document.getElementById(id); } function root() { return document.querySelector('.manager-center'); } 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) { window.HyAppToast.show(message); return; } window.alert(message); } function showError(error) { var message = error && error.status === 403 ? 'Permission denied.' : (error && error.message) || 'Request failed.'; toast(message); } function commandId(prefix) { return [ prefix || 'manager', Date.now(), Math.random().toString(16).slice(2, 10), ].join('-'); } function userName(user) { return ( user.username || user.name || user.target_username || user.display_user_id || user.target_display_user_id || 'User' ); } function userDisplayId(user) { return user.display_user_id || user.target_display_user_id || ''; } function userId(user) { return user.user_id || user.target_user_id || ''; } function avatarUrl(user) { return user.avatar || user.target_avatar || ''; } function initial(text) { return String(text || 'M') .trim() .charAt(0) .toUpperCase(); } function createNode(tag, className, text) { var node = document.createElement(tag); if (className) node.className = className; if (text !== undefined) node.textContent = text; return node; } function setAvatar(node, user) { var url = avatarUrl(user); node.innerHTML = ''; if (url) { var img = document.createElement('img'); img.src = url; img.alt = ''; node.appendChild(img); return; } node.textContent = initial(userName(user) || userDisplayId(user)); } function formatDateTime(ms) { if (!ms) return 'Never'; var date = new Date(Number(ms)); var year = date.getFullYear(); var month = String(date.getMonth() + 1).padStart(2, '0'); var day = String(date.getDate()).padStart(2, '0'); var hour = String(date.getHours()).padStart(2, '0'); var minute = String(date.getMinutes()).padStart(2, '0'); return year + '-' + month + '-' + day + ' ' + hour + ':' + minute; } function setPageLoading(loading) { pageState.loading = loading; var container = root(); if (!container) return; container.classList.toggle('is-loading', loading); } function setDenied(denied) { pageState.denied = denied; var container = root(); if (!container) return; container.classList.toggle('is-denied', denied); } function normalizeUser(item) { return { user_id: item.user_id || item.userId || item.target_user_id || '', display_user_id: item.display_user_id || item.displayUserId || item.target_display_user_id || '', username: item.username || item.name || item.target_username || '', avatar: item.avatar || item.target_avatar || '', country: item.country || '', levels: item.levels || {}, }; } function normalizeBlock(item) { return { block_id: item.block_id || item.blockId || '', target_user_id: item.target_user_id || item.targetUserId || '', target_display_user_id: item.target_display_user_id || item.targetDisplayUserId || '', target_username: item.target_username || item.targetUsername || '', target_avatar: item.target_avatar || item.targetAvatar || '', country: item.country || '', blocked_until_ms: item.blocked_until_ms || item.blockedUntilMs || item.unblockAtMs || 0, status: item.status || 'active', }; } function apiSearchUser(keyword) { if (!api || !api.searchUsers) { return Promise.reject(new Error('API not available.')); } return api.searchUsers(keyword, 20).then(function (data) { var items = (data && data.items) || []; return items.map(normalizeUser); }); } function loadOverview() { if (!api || !api.overview) { setDenied(true); toast('Permission denied.'); return Promise.resolve(); } setPageLoading(true); return api .overview() .then(function (data) { pageState.overview = data || {}; setDenied(false); return refreshBlocks(); }) .catch(function (error) { setDenied(true); showError(error); }) .finally(function () { setPageLoading(false); }); } function refreshBlocks() { if (!api || !api.listBlocks) return Promise.resolve(); return api .listBlocks('active', 50) .then(function (data) { blockState.blockedUsers = ((data && data.items) || []).map( normalizeBlock ); renderBlockedList(); }) .catch(showError); } function goBack() { if (window.HyAppBridge && window.HyAppBridge.back) { window.HyAppBridge.back(); return; } if (window.history.length > 1) { window.history.back(); } } function renderUserRow(user, actionText, onAction) { var row = createNode('div', 'searched-user'); var avatar = createNode('div', 'searched-avatar'); setAvatar(avatar, user); var copy = createNode('div', 'blocked-row-main'); copy.appendChild(createNode('div', 'searched-name', userName(user))); copy.appendChild( createNode('div', 'searched-meta', 'UID: ' + userDisplayId(user)) ); var button = createNode('button', 'user-block-button', actionText); button.type = 'button'; button.addEventListener('click', onAction); row.appendChild(avatar); row.appendChild(copy); row.appendChild(button); return row; } function renderSearchResult() { var container = $('blockSearchResult'); if (!container) return; container.innerHTML = ''; if (!blockState.searchedUser) return; container.appendChild( renderUserRow(blockState.searchedUser, 'Block', function () { selectDuration('86400000', '1 day'); var panel = $('blockDurationPanel'); if (panel) panel.hidden = false; }) ); } function setupLevelGrid() { var grid = $('levelGrid'); if (!grid || grid.children.length) return; for (var level = 1; level <= 11; level += 1) { var button = createNode('button', '', 'Lv. ' + level); button.type = 'button'; button.setAttribute('data-level', String(level)); grid.appendChild(button); } } function ensureTrackSelector() { var panel = $('levelPanel'); if (!panel || $('levelTrackGrid')) return; var title = createNode('div', 'block-section-title', 'Select level type'); var grid = createNode('div', 'track-grid'); grid.id = 'levelTrackGrid'; Object.keys(TRACK_LABELS).forEach(function (track) { var button = createNode('button', '', TRACK_LABELS[track]); button.type = 'button'; button.setAttribute('data-track', track); button.addEventListener('click', function () { levelState.selectedTrack = track; renderLevelButtons(); renderLevelSearchResult(); }); grid.appendChild(button); }); panel.insertBefore(grid, panel.firstChild); panel.insertBefore(title, grid); } function currentTrackLevel(user) { var track = levelState.selectedTrack; var levels = (user && user.levels) || {}; return levels[track] && levels[track].level ? levels[track].level : 0; } function renderLevelSearchResult() { var container = $('levelSearchResult'); if (!container) return; container.innerHTML = ''; if (!levelState.searchedUser) return; var user = levelState.searchedUser; var row = createNode('div', 'searched-user'); var avatar = createNode('div', 'searched-avatar'); setAvatar(avatar, user); var copy = createNode('div', 'blocked-row-main'); copy.appendChild(createNode('div', 'searched-name', userName(user))); copy.appendChild( createNode( 'div', 'searched-meta', 'UID: ' + userDisplayId(user) + ' ยท ' + TRACK_LABELS[levelState.selectedTrack] + ' Lv. ' + currentTrackLevel(user) ) ); var badge = createNode( 'div', 'block-list-count', 'Lv. ' + currentTrackLevel(user) ); row.appendChild(avatar); row.appendChild(copy); row.appendChild(badge); container.appendChild(row); } function renderLevelButtons() { var trackButtons = document.querySelectorAll('#levelTrackGrid [data-track]'); trackButtons.forEach(function (button) { button.classList.toggle( 'is-selected', button.getAttribute('data-track') === levelState.selectedTrack ); }); var buttons = document.querySelectorAll('#levelGrid [data-level]'); buttons.forEach(function (button) { var isSelected = Number(button.getAttribute('data-level')) === levelState.selectedLevel; button.classList.toggle('is-selected', isSelected); }); var confirmButton = $('confirmLevelButton'); if (confirmButton) { confirmButton.disabled = !levelState.searchedUser || !levelState.selectedLevel || levelState.submitting; } } function selectLevel(level) { levelState.selectedLevel = Number(level) || 0; renderLevelButtons(); } function renderDurationButtons() { var buttons = document.querySelectorAll('#durationGrid [data-duration-ms]'); buttons.forEach(function (button) { var isSelected = Number(button.getAttribute('data-duration-ms')) === blockState.selectedDurationMs; button.classList.toggle('is-selected', isSelected); }); var confirmButton = $('confirmBlockButton'); if (confirmButton) { confirmButton.disabled = !blockState.searchedUser || blockState.submitting; } } function selectDuration(durationMs, label) { blockState.selectedDurationMs = Number(durationMs) || 0; blockState.selectedDurationLabel = label || 'Permanent'; renderDurationButtons(); } function renderBlockedList() { var container = $('blockedList'); var count = $('blockListCount'); if (!container) return; container.innerHTML = ''; if (count) count.textContent = String(blockState.blockedUsers.length); if (!blockState.blockedUsers.length) { container.appendChild( createNode('div', 'blocked-empty', 'No blocked users.') ); return; } blockState.blockedUsers.forEach(function (user) { var row = createNode('div', 'blocked-row'); var avatar = createNode('div', 'blocked-avatar'); setAvatar(avatar, user); var copy = createNode('div', 'blocked-row-main'); copy.appendChild(createNode('div', 'blocked-name', userName(user))); copy.appendChild( createNode('div', 'blocked-meta', 'UID: ' + userDisplayId(user)) ); copy.appendChild( createNode( 'div', 'blocked-time', 'Unblock time: ' + formatDateTime(user.blocked_until_ms) ) ); var unblockButton = createNode( 'button', 'user-unblock-button', 'Unblock' ); unblockButton.type = 'button'; unblockButton.addEventListener('click', function () { unblockUser(user.block_id); }); row.appendChild(avatar); row.appendChild(copy); row.appendChild(unblockButton); container.appendChild(row); }); } function unblockUser(blockId) { if (!blockId || blockState.submitting) return; blockState.submitting = true; api.unblockUser(blockId, { reason: 'manager_center' }) .then(function () { toast('User unblocked.'); return refreshBlocks(); }) .catch(showError) .finally(function () { blockState.submitting = false; }); } function resetBlockSearch() { var input = $('blockSearchInput'); var panel = $('blockDurationPanel'); blockState.searchedUser = null; blockState.selectedDurationMs = 0; blockState.selectedDurationLabel = ''; if (input) input.value = ''; if (panel) panel.hidden = true; renderSearchResult(); renderDurationButtons(); } function openBlockModal() { if (pageState.denied) { toast('Permission denied.'); return; } var modal = $('blockModal'); if (!modal) return; resetBlockSearch(); refreshBlocks(); modal.hidden = false; modal.setAttribute('aria-hidden', 'false'); setTimeout(function () { var input = $('blockSearchInput'); if (input) input.focus(); }, 30); } function closeBlockModal() { var modal = $('blockModal'); if (!modal) return; modal.hidden = true; modal.setAttribute('aria-hidden', 'true'); } function resetLevelSearch() { var input = $('levelSearchInput'); var panel = $('levelPanel'); levelState.searchedUser = null; levelState.selectedTrack = 'wealth'; levelState.selectedLevel = 0; if (input) input.value = ''; if (panel) panel.hidden = true; renderLevelSearchResult(); renderLevelButtons(); } function openLevelModal() { if (pageState.denied) { toast('Permission denied.'); return; } var modal = $('levelModal'); if (!modal) return; resetLevelSearch(); modal.hidden = false; modal.setAttribute('aria-hidden', 'false'); setTimeout(function () { var input = $('levelSearchInput'); if (input) input.focus(); }, 30); } function closeLevelModal() { var modal = $('levelModal'); if (!modal) return; modal.hidden = true; modal.setAttribute('aria-hidden', 'true'); } function searchBlockUser() { var input = $('blockSearchInput'); var value = input ? input.value.trim() : ''; var panel = $('blockDurationPanel'); if (!value) { toast('Enter user ID.'); return; } apiSearchUser(value) .then(function (items) { if (!items.length) { blockState.searchedUser = null; toast('No user found.'); return; } blockState.searchedUser = items[0]; blockState.selectedDurationMs = 0; blockState.selectedDurationLabel = ''; if (panel) panel.hidden = true; renderSearchResult(); renderDurationButtons(); }) .catch(showError); } function confirmBlockUser() { if (!blockState.searchedUser) { toast('Search a user first.'); return; } if (blockState.submitting) return; var durationMs = blockState.selectedDurationMs || PERMANENT_BLOCK_MS; blockState.submitting = true; renderDurationButtons(); api.blockUser({ command_id: commandId('manager-block'), target_user_id: userId(blockState.searchedUser), blocked_until_ms: Date.now() + durationMs, reason: 'manager_center', }) .then(function () { toast('User blocked.'); resetBlockSearch(); return refreshBlocks(); }) .catch(showError) .finally(function () { blockState.submitting = false; renderDurationButtons(); }); } function searchLevelUser() { var input = $('levelSearchInput'); var value = input ? input.value.trim() : ''; var panel = $('levelPanel'); if (!value) { toast('Enter user ID.'); return; } apiSearchUser(value) .then(function (items) { if (!items.length) { levelState.searchedUser = null; toast('No user found.'); return; } levelState.searchedUser = items[0]; levelState.selectedLevel = 0; if (panel) panel.hidden = false; renderLevelSearchResult(); renderLevelButtons(); }) .catch(showError); } function confirmLevelUpdate() { if (!levelState.searchedUser) { toast('Search a user first.'); return; } if (!levelState.selectedLevel) { toast('Select a user level.'); return; } if (levelState.submitting) return; levelState.submitting = true; renderLevelButtons(); api.updateLevel({ command_id: commandId('manager-level'), target_user_id: userId(levelState.searchedUser), track: levelState.selectedTrack, level: levelState.selectedLevel, reason: 'manager_center', }) .then(function () { toast('User level updated.'); closeLevelModal(); }) .catch(showError) .finally(function () { levelState.submitting = false; renderLevelButtons(); }); } function ensureGrantModal() { if ($('grantModal')) return; var modal = createNode('div', 'block-modal grant-modal'); modal.id = 'grantModal'; modal.hidden = true; modal.setAttribute('aria-hidden', 'true'); modal.innerHTML = '' + ''; document.querySelector('.manager-center').appendChild(modal); $('grantBackdrop').addEventListener('click', closeGrantModal); $('grantCloseButton').addEventListener('click', closeGrantModal); $('grantSearchButton').addEventListener('click', searchGrantUser); $('grantSearchInput').addEventListener('keydown', function (event) { if (event.key === 'Enter') searchGrantUser(); }); $('confirmGrantButton').addEventListener('click', confirmGrant); } function openGrantModal(action) { if (pageState.denied) { toast('Permission denied.'); return; } ensureGrantModal(); grantState.action = action; grantState.resourceType = RESOURCE_TYPES[action] || ''; grantState.title = ACTION_LABELS[action] || 'Send'; grantState.searchedUser = null; grantState.selectedResourceId = ''; grantState.selectedResourceDurationMs = DEFAULT_RESOURCE_GRANT_DURATION_MS; grantState.selectedVipLevel = 0; $('grantDialogTitle').textContent = grantState.title; $('grantSearchInput').value = ''; $('grantSearchResult').innerHTML = ''; $('grantPanel').hidden = true; $('grantModal').hidden = false; $('grantModal').setAttribute('aria-hidden', 'false'); renderGrantOptions(); if (grantState.resourceType) loadGrantResources(grantState.resourceType); setTimeout(function () { $('grantSearchInput').focus(); }, 30); } function closeGrantModal() { var modal = $('grantModal'); if (!modal) return; modal.hidden = true; modal.setAttribute('aria-hidden', 'true'); } function loadGrantResources(resourceType) { if (pageState.resourcesByType[resourceType]) { renderGrantOptions(); return; } api.listResources(resourceType, 20) .then(function (data) { pageState.resourcesByType[resourceType] = (data && data.items) || []; renderGrantOptions(); }) .catch(showError); } function searchGrantUser() { var value = $('grantSearchInput').value.trim(); if (!value) { toast('Enter user ID.'); return; } apiSearchUser(value) .then(function (items) { if (!items.length) { grantState.searchedUser = null; toast('No user found.'); return; } grantState.searchedUser = items[0]; var container = $('grantSearchResult'); container.innerHTML = ''; container.appendChild( renderUserRow(grantState.searchedUser, 'Select', function () { $('grantPanel').hidden = false; renderGrantOptions(); }) ); $('grantPanel').hidden = false; renderGrantOptions(); }) .catch(showError); } function renderGrantOptions() { var grid = $('grantOptionGrid'); if (!grid) return; grid.innerHTML = ''; var durationTitle = $('grantDurationTitle'); var durationGrid = $('grantDurationGrid'); if (durationTitle) { durationTitle.hidden = false; durationTitle.textContent = grantState.action === 'send-vip' ? 'Duration: 30 days' : 'Select duration'; } if (durationGrid) { durationGrid.innerHTML = ''; durationGrid.hidden = grantState.action === 'send-vip'; } if (grantState.action === 'send-vip') { $('grantOptionTitle').textContent = 'Select VIP level'; [1, 2, 3].forEach(function (level) { var button = createNode('button', '', 'VIP ' + level); button.type = 'button'; button.classList.toggle( 'is-selected', grantState.selectedVipLevel === level ); button.addEventListener('click', function () { grantState.selectedVipLevel = level; renderGrantOptions(); }); grid.appendChild(button); }); } else { $('grantOptionTitle').textContent = 'Select resource'; var resources = pageState.resourcesByType[grantState.resourceType] || []; if (!resources.length) { grid.appendChild(createNode('div', 'blocked-empty', 'No resource available.')); } resources.forEach(function (resource) { var button = createNode('button', 'grant-resource-option'); button.type = 'button'; button.classList.toggle( 'is-selected', String(grantState.selectedResourceId) === String(resource.resource_id) ); button.textContent = resource.name || 'Resource #' + resource.resource_id; button.addEventListener('click', function () { grantState.selectedResourceId = resource.resource_id; renderGrantOptions(); }); grid.appendChild(button); }); if (durationGrid) { RESOURCE_GRANT_DURATIONS.forEach(function (item) { var durationButton = createNode('button', '', item.label); durationButton.type = 'button'; durationButton.classList.toggle( 'is-selected', grantState.selectedResourceDurationMs === item.ms ); durationButton.addEventListener('click', function () { grantState.selectedResourceDurationMs = item.ms; renderGrantOptions(); }); durationGrid.appendChild(durationButton); }); } } var confirm = $('confirmGrantButton'); if (confirm) { confirm.disabled = !grantState.searchedUser || grantState.submitting || (grantState.action === 'send-vip' ? !grantState.selectedVipLevel : !grantState.selectedResourceId || !grantState.selectedResourceDurationMs); } } function confirmGrant() { if (!grantState.searchedUser || grantState.submitting) return; grantState.submitting = true; renderGrantOptions(); var payload = { command_id: commandId('manager-grant'), target_user_id: userId(grantState.searchedUser), reason: 'manager_center', }; var request; if (grantState.action === 'send-vip') { payload.level = grantState.selectedVipLevel; request = api.grantVip(payload); } else { payload.resource_id = grantState.selectedResourceId; payload.duration_ms = grantState.selectedResourceDurationMs; request = api.grantResource(payload); } request .then(function () { toast('Sent successfully.'); closeGrantModal(); }) .catch(showError) .finally(function () { grantState.submitting = false; renderGrantOptions(); }); } function bindEvents() { var backButton = $('backButton'); if (backButton) backButton.addEventListener('click', goBack); document.querySelectorAll('[data-action]').forEach(function (button) { button.addEventListener('click', function () { var action = button.getAttribute('data-action'); if (action === 'block-user') { openBlockModal(); return; } if (action === 'update-user-level') { openLevelModal(); return; } openGrantModal(action); }); }); setupLevelGrid(); ensureTrackSelector(); var closeButton = $('blockCloseButton'); var backdrop = $('blockBackdrop'); var searchButton = $('blockSearchButton'); var searchInput = $('blockSearchInput'); var confirmButton = $('confirmBlockButton'); var levelCloseButton = $('levelCloseButton'); var levelBackdrop = $('levelBackdrop'); var levelSearchButton = $('levelSearchButton'); var levelSearchInput = $('levelSearchInput'); var confirmLevelButton = $('confirmLevelButton'); if (closeButton) closeButton.addEventListener('click', closeBlockModal); if (backdrop) backdrop.addEventListener('click', closeBlockModal); if (levelCloseButton) levelCloseButton.addEventListener('click', closeLevelModal); if (levelBackdrop) levelBackdrop.addEventListener('click', closeLevelModal); if (searchButton) searchButton.addEventListener('click', searchBlockUser); if (searchInput) { searchInput.addEventListener('keydown', function (event) { if (event.key === 'Enter') searchBlockUser(); }); } if (levelSearchButton) levelSearchButton.addEventListener('click', searchLevelUser); if (levelSearchInput) { levelSearchInput.addEventListener('keydown', function (event) { if (event.key === 'Enter') searchLevelUser(); }); } if (confirmButton) confirmButton.addEventListener('click', confirmBlockUser); if (confirmLevelButton) { confirmLevelButton.addEventListener('click', confirmLevelUpdate); } document .querySelectorAll('#durationGrid [data-duration-ms]') .forEach(function (button) { button.addEventListener('click', function () { selectDuration( button.getAttribute('data-duration-ms'), button.getAttribute('data-duration-label') ); }); }); document.querySelectorAll('#levelGrid [data-level]').forEach(function (button) { button.addEventListener('click', function () { selectLevel(button.getAttribute('data-level')); }); }); } function init() { bindEvents(); renderBlockedList(); loadOverview(); if (window.HyAppBridge && window.HyAppBridge.ready) { window.HyAppBridge.ready({ page: 'manager-center' }); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();