2026-06-18 18:03:49 +08:00

1197 lines
43 KiB
JavaScript

(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',
'add-bd-leader': 'Add BD Leader',
'add-admin': 'Add Admin',
'add-superadmin': 'Add Superadmin',
};
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 ACTION_PERMISSION_KEYS = {
'send-frame': 'canGrantAvatarFrame',
'send-car': 'canGrantVehicle',
'update-user-level': 'canUpdateUserLevel',
'add-bd-leader': 'canAddBdLeader',
'add-admin': 'canAddAdmin',
'add-superadmin': 'canAddSuperadmin',
'block-user': 'canBlockUser',
};
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,
permissions: {},
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,
};
var bdLeaderState = {
action: '',
title: '',
searchedUser: null,
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 normalizePermissions(raw) {
raw = raw || {};
return {
canGrantAvatarFrame:
raw.canGrantAvatarFrame !== undefined
? Boolean(raw.canGrantAvatarFrame)
: raw.can_grant_avatar_frame !== undefined
? Boolean(raw.can_grant_avatar_frame)
: true,
canGrantVehicle:
raw.canGrantVehicle !== undefined
? Boolean(raw.canGrantVehicle)
: raw.can_grant_vehicle !== undefined
? Boolean(raw.can_grant_vehicle)
: true,
canUpdateUserLevel:
raw.canUpdateUserLevel !== undefined
? Boolean(raw.canUpdateUserLevel)
: raw.can_update_user_level !== undefined
? Boolean(raw.can_update_user_level)
: true,
canAddBdLeader:
raw.canAddBdLeader !== undefined
? Boolean(raw.canAddBdLeader)
: raw.can_add_bd_leader !== undefined
? Boolean(raw.can_add_bd_leader)
: true,
canAddAdmin:
raw.canAddAdmin !== undefined
? Boolean(raw.canAddAdmin)
: raw.can_add_admin !== undefined
? Boolean(raw.can_add_admin)
: true,
canAddSuperadmin:
raw.canAddSuperadmin !== undefined
? Boolean(raw.canAddSuperadmin)
: raw.can_add_superadmin !== undefined
? Boolean(raw.can_add_superadmin)
: true,
canBlockUser:
raw.canBlockUser !== undefined
? Boolean(raw.canBlockUser)
: raw.can_block_user !== undefined
? Boolean(raw.can_block_user)
: true,
};
}
function canUseAction(action) {
var key = ACTION_PERMISSION_KEYS[action];
if (!key) return true;
return pageState.permissions[key] !== false;
}
function renderActionPermissions() {
document.querySelectorAll('[data-action]').forEach(function (button) {
var action = button.getAttribute('data-action');
button.hidden = !canUseAction(action);
});
}
function ensureActionAllowed(action) {
if (canUseAction(action)) return true;
toast('Permission denied.');
return false;
}
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 || {};
pageState.permissions = normalizePermissions(
pageState.overview.permissions || pageState.overview
);
renderActionPermissions();
setDenied(false);
return canUseAction('block-user') ? refreshBlocks() : Promise.resolve();
})
.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;
}
if (!ensureActionAllowed('block-user')) 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;
}
if (!ensureActionAllowed('update-user-level')) 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 =
'<button class="block-backdrop" id="grantBackdrop" type="button" aria-label="Close"></button>' +
'<section class="block-dialog" role="dialog" aria-modal="true" aria-labelledby="grantDialogTitle">' +
'<div class="block-dialog-header"><h2 id="grantDialogTitle">Send</h2>' +
'<button class="block-close" id="grantCloseButton" type="button" aria-label="Close"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18"/></svg></button></div>' +
'<div class="block-dialog-body"><div class="block-field"><label for="grantSearchInput">User ID</label>' +
'<div class="block-search-row"><input id="grantSearchInput" type="text" inputmode="numeric" autocomplete="off" placeholder="Enter user ID"/><button id="grantSearchButton" type="button">Search</button></div></div>' +
'<div class="block-search-result" id="grantSearchResult" aria-live="polite"></div>' +
'<div class="level-panel" id="grantPanel" hidden><div class="block-section-title" id="grantOptionTitle">Select item</div><div class="grant-option-grid" id="grantOptionGrid"></div><div class="block-section-title" id="grantDurationTitle" hidden>Select duration</div><div class="duration-grid grant-duration-grid" id="grantDurationGrid" hidden></div><button class="confirm-level-button" id="confirmGrantButton" type="button" disabled>Send now</button></div></div></section>';
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;
}
if (!ensureActionAllowed(action)) 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 ensureBDLeaderModal() {
if ($('bdLeaderModal')) return;
var modal = createNode('div', 'block-modal bd-leader-modal');
modal.id = 'bdLeaderModal';
modal.hidden = true;
modal.setAttribute('aria-hidden', 'true');
modal.innerHTML =
'<button class="block-backdrop" id="bdLeaderBackdrop" type="button" aria-label="Close"></button>' +
'<section class="block-dialog" role="dialog" aria-modal="true" aria-labelledby="bdLeaderDialogTitle">' +
'<div class="block-dialog-header"><h2 id="bdLeaderDialogTitle">Add BD Leader</h2>' +
'<button class="block-close" id="bdLeaderCloseButton" type="button" aria-label="Close"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18"/></svg></button></div>' +
'<div class="block-dialog-body"><div class="block-field"><label for="bdLeaderSearchInput">User ID</label>' +
'<div class="block-search-row"><input id="bdLeaderSearchInput" type="text" inputmode="numeric" autocomplete="off" placeholder="Enter user ID"/><button id="bdLeaderSearchButton" type="button">Search</button></div></div>' +
'<div class="block-search-result" id="bdLeaderSearchResult" aria-live="polite"></div>' +
'<div class="level-panel" id="bdLeaderPanel" hidden><div class="block-section-title">Add this user as BD Leader</div>' +
'<button class="confirm-level-button" id="confirmBDLeaderButton" type="button" disabled>Add BD Leader</button></div></div></section>';
document.querySelector('.manager-center').appendChild(modal);
$('bdLeaderBackdrop').addEventListener('click', closeBDLeaderModal);
$('bdLeaderCloseButton').addEventListener('click', closeBDLeaderModal);
$('bdLeaderSearchButton').addEventListener('click', searchBDLeaderUser);
$('bdLeaderSearchInput').addEventListener('keydown', function (event) {
if (event.key === 'Enter') searchBDLeaderUser();
});
$('confirmBDLeaderButton').addEventListener('click', confirmBDLeader);
}
function openBDLeaderModal(action) {
if (pageState.denied) {
toast('Permission denied.');
return;
}
if (!ensureActionAllowed(action)) return;
ensureBDLeaderModal();
bdLeaderState.action = action;
bdLeaderState.title = ACTION_LABELS[action] || 'Add BD Leader';
bdLeaderState.searchedUser = null;
bdLeaderState.submitting = false;
$('bdLeaderDialogTitle').textContent = bdLeaderState.title;
$('confirmBDLeaderButton').textContent = bdLeaderState.title;
$('bdLeaderSearchInput').value = '';
$('bdLeaderSearchResult').innerHTML = '';
$('bdLeaderPanel').hidden = true;
renderBDLeaderActions();
$('bdLeaderModal').hidden = false;
$('bdLeaderModal').setAttribute('aria-hidden', 'false');
setTimeout(function () {
$('bdLeaderSearchInput').focus();
}, 30);
}
function closeBDLeaderModal() {
var modal = $('bdLeaderModal');
if (!modal) return;
modal.hidden = true;
modal.setAttribute('aria-hidden', 'true');
}
function searchBDLeaderUser() {
var value = $('bdLeaderSearchInput').value.trim();
if (!value) {
toast('Enter user ID.');
return;
}
apiSearchUser(value)
.then(function (items) {
if (!items.length) {
bdLeaderState.searchedUser = null;
$('bdLeaderSearchResult').innerHTML = '';
$('bdLeaderPanel').hidden = true;
renderBDLeaderActions();
toast('No user found.');
return;
}
bdLeaderState.searchedUser = items[0];
var container = $('bdLeaderSearchResult');
container.innerHTML = '';
container.appendChild(
renderUserRow(
bdLeaderState.searchedUser,
'Select',
function () {
$('bdLeaderPanel').hidden = false;
renderBDLeaderActions();
}
)
);
$('bdLeaderPanel').hidden = false;
renderBDLeaderActions();
})
.catch(showError);
}
function renderBDLeaderActions() {
var confirm = $('confirmBDLeaderButton');
if (!confirm) return;
confirm.disabled =
!bdLeaderState.searchedUser || bdLeaderState.submitting;
}
function confirmBDLeader() {
if (!bdLeaderState.searchedUser) {
toast('Search a user first.');
return;
}
if (!api || !api.createBDLeader) {
toast('API not available.');
return;
}
if (bdLeaderState.submitting) return;
bdLeaderState.submitting = true;
renderBDLeaderActions();
api.createBDLeader({
command_id: commandId('manager-bd-leader'),
target_user_id: userId(bdLeaderState.searchedUser),
reason: 'manager_center',
})
.then(function () {
toast('BD Leader added.');
closeBDLeaderModal();
})
.catch(showError)
.finally(function () {
bdLeaderState.submitting = false;
renderBDLeaderActions();
});
}
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 (!ensureActionAllowed(action)) {
return;
}
if (action === 'block-user') {
openBlockModal();
return;
}
if (action === 'update-user-level') {
openLevelModal();
return;
}
if (
action === 'add-bd-leader' ||
action === 'add-admin' ||
action === 'add-superadmin'
) {
openBDLeaderModal(action);
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();
}
})();