agency center

This commit is contained in:
zhx 2026-06-05 15:09:35 +08:00
parent 527484d3d8
commit da6d029a27
4 changed files with 758 additions and 364 deletions

View File

@ -331,6 +331,11 @@ var default_api = 'https://api.global-interaction.com/';
method: 'GET',
});
},
platformPolicy: function () {
return request('/api/v1/agency-center/platform-policy', {
method: 'GET',
});
},
hosts: function () {
return request('/api/v1/agency-center/hosts', {
method: 'GET',

View File

@ -9,7 +9,10 @@
<title>Agency Center</title>
<link rel="stylesheet" href="../../common/theme.css" />
<link rel="stylesheet" href="../common/center.css" />
<link rel="stylesheet" href="./style.css" />
<link
rel="stylesheet"
href="./style.css?v=20260605-agency-real-policy"
/>
</head>
<body>
@ -64,8 +67,8 @@
</div>
</div>
<div class="profile-copy">
<div class="name" id="agencyName">Yumi Star Agency</div>
<div class="meta" id="agencyShortId">ID: 163003</div>
<div class="name" id="agencyName">-</div>
<div class="meta" id="agencyShortId">ID: -</div>
<div class="bd-row" id="bdRow" hidden>
<span
class="bd-label"
@ -86,9 +89,7 @@
>B</span
>
</span>
<span class="bd-short-id" id="bdShortId"
>880001</span
>
<span class="bd-short-id" id="bdShortId"></span>
</div>
</div>
<button
@ -169,24 +170,6 @@
<span class="menu-count" id="hostCount">0</span>
<span class="chevron" aria-hidden="true">&rsaquo;</span>
</button>
<button
class="menu-row"
type="button"
data-action="team-bill"
>
<span class="menu-icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
<path d="M6 3h12v18H6Z" />
<path d="M9 8h6M9 12h5M9 16h6" />
</svg>
</span>
<span
class="menu-label"
data-i18n="agency_center.salary_bills"
>Salary Bills</span
>
<span class="chevron" aria-hidden="true">&rsaquo;</span>
</button>
<button class="menu-row" type="button" data-action="policy">
<span class="menu-icon" aria-hidden="true">
<svg viewBox="0 0 24 24">
@ -316,38 +299,57 @@
</section>
</div>
<div class="sheet-modal" id="billSheet" hidden aria-hidden="true">
<div
class="sheet-modal"
id="policyModal"
hidden
aria-hidden="true"
>
<button
class="modal-backdrop"
type="button"
data-close-sheet="billSheet"
data-close-policy
aria-label="Close"
data-i18n-aria="agency_center.close"
></button>
<section
class="bottom-sheet"
class="bottom-sheet policy-sheet"
role="dialog"
aria-modal="true"
aria-labelledby="billTitle"
aria-labelledby="policyTitle"
>
<div class="sheet-head">
<h2
id="billTitle"
data-i18n="agency_center.salary_bills"
id="policyTitle"
data-i18n="agency_center.agency_policy"
>
Salary Bills
Agency Policy
</h2>
<button
class="sheet-close"
type="button"
data-close-sheet="billSheet"
data-close-policy
aria-label="Close"
data-i18n-aria="agency_center.close"
>
&times;
</button>
</div>
<div class="bill-list" id="billList"></div>
<div class="policy-sheet-body">
<div class="policy-summary">
<strong id="policyName">Current policy</strong>
<span id="policyMeta"></span>
</div>
<div
class="policy-empty"
id="policyEmpty"
hidden
></div>
<div
class="policy-level-list"
id="policyLevelList"
></div>
</div>
</section>
</div>
@ -454,10 +456,10 @@
</div>
<script src="../../common/toast.js"></script>
<script src="../../common/api.js?v=20260603-agency-center"></script>
<script src="../../common/api.js?v=20260605-agency-real-policy"></script>
<script src="../../common/params.js?v=20260603-agency-center"></script>
<script src="../../common/jsbridge.js"></script>
<script src="../../common/i18n.js"></script>
<script src="./script.js"></script>
<script src="./script.js?v=20260605-agency-real-policy"></script>
</body>
</html>

View File

@ -2,98 +2,45 @@
var AGENCY_SALARY_USD = 'AGENCY_SALARY_USD';
var HOST_SALARY_USD = 'HOST_SALARY_USD';
var mock = {
profile: {
name: 'Yumi Star Agency',
shortId: '163003',
avatar: avatarData('A', '#dbc8ff', '#7d57c7'),
bd: {
name: 'Mila BD',
shortId: '880001',
avatar: avatarData('M', '#efe4ff', '#7d57c7'),
},
},
metrics: {
salary: 12880.75,
},
hosts: [
{
id: '163000',
name: 'quick_1780052629537',
avatar: avatarData('Q', '#dbc8ff', '#7d57c7'),
workTime: 86,
gift: 2450,
salary: 3050.25,
},
{
id: '163011',
name: 'Lina_voice',
avatar: avatarData('L', '#f4ebff', '#7d57c7'),
workTime: 124,
gift: 3760,
salary: 4280.5,
},
{
id: '163024',
name: 'Nora_live',
avatar: avatarData('N', '#efe4ff', '#7d57c7'),
workTime: 98,
gift: 2990,
salary: 2298,
},
],
bills: [
{
month: '2026-06',
hostSalary: 8420.2,
agencySalary: 3260.55,
total: 11680.75,
status: 'In progress',
},
{
month: '2026-05',
hostSalary: 13240,
agencySalary: 5140.8,
total: 18380.8,
status: 'Completed',
},
],
messages: [
{
id: 'apply-1001',
applicationId: '1001',
name: 'Mona_host',
account: '163088',
avatar: avatarData('M', '#dbc8ff', '#7d57c7'),
},
{
id: 'apply-1002',
applicationId: '1002',
name: 'Sara_room',
account: '163099',
avatar: avatarData('S', '#f4ebff', '#7d57c7'),
},
],
};
var state = emptyState();
var state = {
hosts: mock.hosts.slice(),
messages: mock.messages.slice(),
function emptyState() {
return {
hosts: [],
messages: [],
hostSearch: '',
pendingRemoveHost: null,
profile: mock.profile,
salary: mock.metrics.salary,
loading: false,
isMock: shouldUseMock(),
profile: {
loading: true,
name: '',
shortId: '',
avatar: '',
bd: null,
},
salary: {
loading: true,
available: 0,
},
policy: {
loading: true,
loaded: false,
found: false,
policy: null,
},
loading: true,
};
}
function $(id) {
return document.getElementById(id);
}
function shouldUseMock() {
var params = new URLSearchParams(window.location.search);
return params.get('mock') === '1' || params.get('mock') === 'true';
function api() {
return window.HyAppAPI || {};
}
function agencyAPI() {
return api().agencyCenter || null;
}
function avatarData(text, background, foreground) {
@ -119,6 +66,7 @@
}
function toast(message) {
if (!message) return;
if (window.HyAppToast) {
window.HyAppToast.show(message);
return;
@ -137,7 +85,7 @@
function formatCount(value) {
var number = Number(value || 0);
return number.toLocaleString('en-US', {
maximumFractionDigits: 2,
maximumFractionDigits: 0,
});
}
@ -156,6 +104,24 @@
);
}
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 salaryDisplayAmount(salary, assetType) {
if (!salary) return 0;
if (
@ -177,11 +143,66 @@
.toUpperCase();
}
function currentLocale() {
var lang =
window.HyAppI18n && window.HyAppI18n.lang
? window.HyAppI18n.lang()
: 'en';
var map = {
en: 'en-US',
ar: 'ar',
tr: 'tr-TR',
es: 'es-ES',
zh: 'zh-CN',
id: 'id-ID',
};
return map[lang] || 'en-US';
}
function formatMode(value) {
var text = String(value || '')
.replace(/[_-]+/g, ' ')
.trim();
if (!text) return '-';
return text.replace(/\b\w/g, function (letter) {
return letter.toUpperCase();
});
}
function formatDate(ms) {
var value = toNumber(ms);
if (!value) return '';
try {
return new Date(value).toLocaleDateString(currentLocale(), {
year: 'numeric',
month: 'short',
day: 'numeric',
});
} catch (_) {
return '';
}
}
function policyAmount(minor) {
return '$' + formatMoney(toNumber(minor) / 100);
}
function setSkeleton(element, loading, text) {
if (!element) return;
element.classList.toggle('skeleton-line', Boolean(loading));
if (loading) {
element.textContent = '';
return;
}
element.textContent = text || '';
}
function setImage(image, fallback, src, name) {
if (!image || !fallback) return;
fallback.textContent = initial(name) || 'A';
if (!src) {
image.hidden = true;
image.removeAttribute('src');
fallback.hidden = false;
return;
}
@ -196,6 +217,16 @@
image.src = src;
}
function setAvatarSkeleton(image, fallback, loading) {
if (!image || !fallback) return;
fallback.classList.toggle('avatar-skeleton', Boolean(loading));
if (!loading) return;
image.hidden = true;
image.removeAttribute('src');
fallback.hidden = false;
fallback.textContent = '';
}
function makeAvatar(item) {
var avatar = document.createElement('div');
var fallback = document.createElement('span');
@ -214,40 +245,50 @@
return avatar;
}
function hasRealAPI() {
return !state.isMock && window.HyAppAPI && window.HyAppAPI.agencyCenter;
}
function displayName(user, fallback) {
if (!user) return fallback || '-';
return (
user.username ||
user.display_user_id ||
user.user_id ||
firstValue(user, ['username', 'name', 'display_user_id']) ||
fallback ||
'-'
);
}
function normalizeOverview(payload) {
var agency = payload && payload.agency ? payload.agency : {};
var bd = payload && payload.bd ? payload.bd : null;
var data = unwrapData(payload) || {};
var agency = data.agency || {};
var bd = data.bd || null;
state.profile = {
name: agency.name || mock.profile.name,
shortId: agency.agency_id || mock.profile.shortId,
avatar: agency.avatar || '',
loading: false,
name: agency.name || '-',
shortId:
firstValue(agency, [
'agency_id',
'agencyId',
'short_id',
'shortId',
'display_user_id',
]) || '-',
avatar:
agency.avatar ||
avatarData(initial(agency.name) || 'A', '#dbc8ff', '#7d57c7'),
bd: bd
? {
name: displayName(bd, ''),
shortId: bd.display_user_id || bd.user_id || '',
shortId: firstValue(bd, [
'display_user_id',
'displayUserID',
'user_id',
'userId',
]),
avatar: bd.avatar || '',
}
: null,
};
state.salary = salaryDisplayAmount(
payload ? payload.salary : null,
AGENCY_SALARY_USD
);
state.salary = {
loading: false,
available: salaryDisplayAmount(data.salary, AGENCY_SALARY_USD),
};
}
function normalizeHost(item) {
@ -276,51 +317,64 @@
};
}
function applyAgencyCenterPayload(overview, hosts, applications) {
normalizeOverview(overview || {});
state.hosts = ((hosts && hosts.items) || []).map(normalizeHost);
state.messages = ((applications && applications.items) || []).map(
normalizeMessage
);
function applyPolicy(payload) {
var data = unwrapData(payload);
if (!data || !data.found || !data.policy) {
state.policy = {
loading: false,
loaded: true,
found: false,
policy: null,
};
return;
}
state.policy = {
loading: false,
loaded: true,
found: true,
policy: data.policy,
};
}
function loadAgencyCenter() {
if (!hasRealAPI()) return Promise.resolve();
if (window.HyAppParams && window.HyAppParams.parse) {
window.HyAppParams.parse();
}
state.loading = true;
return Promise.all([
window.HyAppAPI.agencyCenter.overview(),
window.HyAppAPI.agencyCenter.hosts(),
window.HyAppAPI.agencyCenter.applications('pending'),
])
.then(function (results) {
applyAgencyCenterPayload(results[0], results[1], results[2]);
render();
})
.catch(function () {
toast(
t(
'agency_center.load_failed',
'Load failed. Try again later.'
)
);
})
.finally(function () {
function markLoadedEmpty() {
state.profile = {
loading: false,
name: '-',
shortId: '-',
avatar: '',
bd: null,
};
state.salary = { loading: false, available: 0 };
state.hosts = [];
state.messages = [];
state.policy = {
loading: false,
loaded: true,
found: false,
policy: null,
};
state.loading = false;
});
}
function renderProfile() {
var profile = state.profile || mock.profile;
var profile = state.profile;
var bd = profile.bd || null;
var bdRow = $('bdRow');
$('agencyName').textContent = profile.name;
$('agencyShortId').textContent = t(
'agency_center.agency_short_id',
'ID: {id}'
).replace('{id}', profile.shortId || '-');
var loading = Boolean(profile.loading);
setSkeleton($('agencyName'), loading, profile.name || '-');
setSkeleton(
$('agencyShortId'),
loading,
t('agency_center.agency_short_id', 'ID: {id}').replace(
'{id}',
profile.shortId || '-'
)
);
setAvatarSkeleton($('agencyAvatar'), $('agencyAvatarFallback'), loading);
if (loading) {
bdRow.hidden = true;
return;
}
if (bd && bd.shortId) {
bdRow.hidden = false;
$('bdShortId').textContent = bd.shortId;
@ -338,11 +392,22 @@
}
function renderSalary() {
$('currentSalary').textContent = formatMoney(state.salary);
var loading = Boolean(state.salary.loading);
var currency = document.querySelector('.salary-currency');
if (currency) currency.classList.toggle('skeleton-coin', loading);
setSkeleton(
$('currentSalary'),
loading,
formatMoney(state.salary.available)
);
}
function renderHostCount() {
$('hostCount').textContent = formatCount(state.hosts.length);
setSkeleton(
$('hostCount'),
Boolean(state.loading),
formatCount(state.hosts.length)
);
}
function renderUnread() {
@ -362,11 +427,42 @@
});
}
function skeletonHostRow() {
var row = document.createElement('div');
var user = document.createElement('div');
var avatar = document.createElement('div');
var copy = document.createElement('div');
var name = document.createElement('div');
var meta = document.createElement('div');
var side = document.createElement('div');
row.className = 'host-row is-skeleton';
user.className = 'host-user';
avatar.className = 'small-avatar avatar-skeleton';
copy.className = 'host-copy';
name.className = 'host-name skeleton-line';
meta.className = 'host-meta skeleton-line';
side.className = 'host-side-skeleton skeleton-line';
copy.appendChild(name);
copy.appendChild(meta);
user.appendChild(avatar);
user.appendChild(copy);
row.appendChild(user);
row.appendChild(side);
return row;
}
function renderHostList() {
var list = $('hostList');
var empty = $('hostListEmpty');
var hosts = filteredHosts();
list.textContent = '';
if (state.loading) {
empty.hidden = true;
list.appendChild(skeletonHostRow());
list.appendChild(skeletonHostRow());
list.appendChild(skeletonHostRow());
return;
}
empty.hidden = hosts.length > 0;
empty.textContent = t('agency_center.no_hosts', 'No hosts');
hosts.forEach(function (host) {
@ -420,9 +516,12 @@
function confirmRemoveHost() {
var host = state.pendingRemoveHost;
if (!host) return;
if (hasRealAPI()) {
window.HyAppAPI.agencyCenter
var service = agencyAPI();
if (!host || !service || !service.removeHost) {
toast(t('agency_center.api_not_ready', 'API module is not ready.'));
return;
}
service
.removeHost(host.userId || host.id, {
command_id: commandID('agency-remove-host'),
reason: 'agency_center',
@ -442,63 +541,6 @@
)
);
});
return;
}
state.hosts = state.hosts.filter(function (item) {
return item.id !== host.id;
});
state.pendingRemoveHost = null;
closeSheet('removeConfirmModal');
renderHostCount();
renderHostList();
toast(t('agency_center.host_removed', 'Host removed.'));
}
function createBillCell(label, value) {
var cell = document.createElement('div');
var title = document.createElement('span');
var strong = document.createElement('strong');
cell.className = 'bill-cell';
title.textContent = label;
strong.textContent = value;
cell.appendChild(title);
cell.appendChild(strong);
return cell;
}
function renderBillList() {
var list = $('billList');
list.textContent = '';
mock.bills.forEach(function (bill) {
var row = document.createElement('div');
var month = document.createElement('div');
var values = document.createElement('div');
row.className = 'bill-row';
month.className = 'bill-month';
values.className = 'bill-values';
month.textContent = bill.month + ' · ' + bill.status;
values.appendChild(
createBillCell(
t('agency_center.host_salary', 'Host salary'),
formatMoney(bill.hostSalary)
)
);
values.appendChild(
createBillCell(
t('agency_center.agency_salary', 'Agency salary'),
formatMoney(bill.agencySalary)
)
);
values.appendChild(
createBillCell(
t('agency_center.total', 'Total'),
formatMoney(bill.total)
)
);
row.appendChild(month);
row.appendChild(values);
list.appendChild(row);
});
}
function renderMessages() {
@ -549,9 +591,13 @@
}
function processMessage(message, action) {
if (hasRealAPI()) {
var service = agencyAPI();
if (!service || !service.reviewApplication) {
toast(t('agency_center.api_not_ready', 'API module is not ready.'));
return;
}
var decision = action === 'agree' ? 'approve' : 'reject';
window.HyAppAPI.agencyCenter
service
.reviewApplication(message.applicationId || message.id, {
command_id: commandID('agency-review-application'),
decision: decision,
@ -578,22 +624,113 @@
)
);
});
}
function appendPolicyCell(parent, label, value) {
var cell = document.createElement('div');
var labelNode = document.createElement('span');
var valueNode = document.createElement('strong');
cell.className = 'policy-cell';
labelNode.className = 'policy-cell-label';
labelNode.textContent = label;
valueNode.className = 'policy-cell-value';
valueNode.textContent = value;
cell.appendChild(labelNode);
cell.appendChild(valueNode);
parent.appendChild(cell);
}
function renderPolicy() {
var summary = state.policy || {};
var policy = summary.policy || {};
var list = $('policyLevelList');
var empty = $('policyEmpty');
if (!list || !empty) return;
list.textContent = '';
if (summary.loading) {
setSkeleton($('policyName'), true, '');
setSkeleton($('policyMeta'), true, '');
empty.hidden = false;
empty.textContent = '';
empty.classList.add('policy-skeleton-block');
return;
}
state.messages = state.messages.filter(function (item) {
return item.id !== message.id;
$('policyName').classList.remove('skeleton-line');
$('policyMeta').classList.remove('skeleton-line');
empty.classList.remove('policy-skeleton-block');
if (!summary.found || !policy || !policy.name) {
$('policyName').textContent = t(
'agency_center.agency_policy',
'Agency Policy'
);
$('policyMeta').textContent = '';
empty.hidden = false;
empty.textContent = 'No agency policy configured.';
return;
}
var from = formatDate(policy.effective_from_ms);
var to = formatDate(policy.effective_to_ms);
var meta = [
'Status: ' + formatMode(policy.status),
'Mode: ' + formatMode(policy.settlement_mode),
'Trigger: ' + formatMode(policy.settlement_trigger_mode),
'Gift ratio: ' + (policy.gift_coin_to_diamond_ratio || '-'),
'Residual rate: ' + (policy.residual_diamond_to_usd_rate || '-'),
];
if (from || to) {
meta.push('Effective: ' + (from || '-') + ' - ' + (to || 'No end'));
}
$('policyName').textContent = policy.name || 'Current policy';
$('policyMeta').textContent = meta.join(' / ');
empty.hidden = true;
empty.textContent = '';
var levels = Array.isArray(policy.levels) ? policy.levels : [];
if (!levels.length) {
empty.hidden = false;
empty.textContent = 'No policy levels configured.';
return;
}
levels.forEach(function (level) {
var row = document.createElement('div');
var head = document.createElement('div');
var title = document.createElement('strong');
var required = document.createElement('span');
var grid = document.createElement('div');
var levelNo = toNumber(level.level_no);
row.className = 'policy-level-row';
head.className = 'policy-row-head';
title.className = 'policy-level';
required.className = 'policy-effective';
grid.className = 'policy-grid';
title.textContent = 'Lv. ' + (levelNo || '-');
required.textContent =
formatCount(level.required_diamonds) + ' diamonds';
head.appendChild(title);
head.appendChild(required);
appendPolicyCell(
grid,
'Host salary',
policyAmount(level.host_salary_usd_minor)
);
appendPolicyCell(
grid,
'Host coin reward',
formatCount(level.host_coin_reward)
);
appendPolicyCell(
grid,
'Agency salary',
policyAmount(level.agency_salary_usd_minor)
);
appendPolicyCell(grid, 'Status', formatMode(level.status));
row.appendChild(head);
row.appendChild(grid);
list.appendChild(row);
});
renderUnread();
renderMessages();
var key =
action === 'agree'
? 'agency_center.approved_application'
: 'agency_center.rejected_application';
var fallback =
action === 'agree'
? "Approved {name}'s application."
: "Rejected {name}'s application.";
toast(t(key, fallback).replace('{name}', message.name));
}
function openSheet(id) {
@ -620,9 +757,29 @@
document.body.classList.toggle('modal-open', hasOpen);
}
function openPolicy() {
var modal = $('policyModal');
if (!modal) return;
modal.hidden = false;
modal.setAttribute('aria-hidden', 'false');
document.body.classList.add('modal-open');
renderPolicy();
if (!state.policy.loaded) loadPolicy();
}
function closePolicy() {
var modal = $('policyModal');
if (!modal) return;
modal.hidden = true;
modal.setAttribute('aria-hidden', 'true');
document.body.classList.remove('modal-open');
}
function closeAllSheets() {
document
.querySelectorAll('.sheet-modal, .message-modal, .confirm-modal')
.querySelectorAll(
'.sheet-modal, .message-modal, .confirm-modal'
)
.forEach(function (sheet) {
sheet.hidden = true;
sheet.setAttribute('aria-hidden', 'true');
@ -633,11 +790,146 @@
function navigateToWithdrawExchange() {
var params = new URLSearchParams(window.location.search);
if (!params.has('mode')) params.set('mode', 'transfer');
params.set('identity', 'AGENCY');
params.set('salaryType', AGENCY_SALARY_USD);
params.set('asset_type', AGENCY_SALARY_USD);
if (!params.has('mode')) params.set('mode', 'withdraw');
window.location.href =
'../withdraw-exchange/index.html?' + params.toString();
}
function safeRequest(factory) {
return factory().catch(function (error) {
if (window.console && window.console.warn) {
window.console.warn('[agency-center] api failed', error);
}
return null;
});
}
function setLoading(loading) {
state.loading = Boolean(loading);
state.profile.loading = Boolean(loading);
state.salary.loading = Boolean(loading);
state.policy = Object.assign({}, state.policy, {
loading: Boolean(loading),
});
render();
}
function applyAgencyCenterPayload(overview, hosts, applications, policy) {
if (overview) {
normalizeOverview(overview);
} else {
state.profile.loading = false;
state.salary.loading = false;
}
state.hosts = ((hosts && hosts.items) || []).map(normalizeHost);
state.messages = ((applications && applications.items) || []).map(
normalizeMessage
);
if (policy) {
applyPolicy(policy);
} else {
state.policy = {
loading: false,
loaded: true,
found: false,
policy: null,
};
}
}
function loadPolicy() {
var service = agencyAPI();
if (!service || !service.platformPolicy) {
state.policy = {
loading: false,
loaded: true,
found: false,
policy: null,
};
renderPolicy();
return Promise.resolve(false);
}
state.policy = Object.assign({}, state.policy, { loading: true });
renderPolicy();
return safeRequest(function () {
return service.platformPolicy();
}).then(function (payload) {
if (payload) {
applyPolicy(payload);
} else {
state.policy = {
loading: false,
loaded: true,
found: false,
policy: null,
};
}
renderPolicy();
return Boolean(payload);
});
}
function loadAgencyCenter() {
var service = agencyAPI();
setLoading(true);
if (
!service ||
!service.overview ||
!service.hosts ||
!service.applications ||
!service.platformPolicy
) {
markLoadedEmpty();
render();
toast(t('agency_center.api_not_ready', 'API module is not ready.'));
return Promise.resolve(false);
}
if (window.HyAppParams && window.HyAppParams.parse) {
window.HyAppParams.parse();
}
return Promise.all([
safeRequest(function () {
return service.overview();
}),
safeRequest(function () {
return service.hosts();
}),
safeRequest(function () {
return service.applications('pending');
}),
safeRequest(function () {
return service.platformPolicy();
}),
]).then(function (results) {
applyAgencyCenterPayload(
results[0],
results[1],
results[2],
results[3]
);
state.loading = false;
render();
if (
!results[0] &&
!results[1] &&
!results[2] &&
!results[3]
) {
toast(
t(
'agency_center.load_failed',
'Load failed. Try again later.'
)
);
return false;
}
return true;
});
}
function bindEvents() {
$('backButton').addEventListener('click', function () {
if (window.HyAppBridge) window.HyAppBridge.back();
@ -673,6 +965,11 @@
closeSheet(node.getAttribute('data-close-sheet'));
});
});
document
.querySelectorAll('[data-close-policy]')
.forEach(function (button) {
button.addEventListener('click', closePolicy);
});
document.querySelectorAll('.menu-row').forEach(function (button) {
button.addEventListener('click', function () {
var action = button.getAttribute('data-action');
@ -683,24 +980,13 @@
openSheet('hostSheet');
return;
}
if (action === 'team-bill') {
renderBillList();
openSheet('billSheet');
if (action === 'policy') {
openPolicy();
return;
}
if (action === 'invite') {
openSheet('inviteSheet');
return;
}
toast(
t(
'agency_center.mock_navigation',
'Mock navigation: {label}'
).replace(
'{label}',
t('agency_center.agency_policy', 'Agency Policy')
)
);
});
});
document.addEventListener('keydown', function (event) {
@ -714,20 +1000,20 @@
renderHostCount();
renderUnread();
renderHostList();
renderBillList();
renderMessages();
renderPolicy();
}
function initPage() {
render();
bindEvents();
loadAgencyCenter();
loadAgencyCenter().finally(function () {
if (window.HyAppBridge) {
window.HyAppBridge.ready({
page: 'agency-center',
mock: state.isMock,
});
}
});
}
if (document.readyState === 'loading') {

View File

@ -434,6 +434,12 @@ input:focus-visible {
line-height: 1;
}
.salary-value #currentSalary.skeleton-line {
width: 160px;
height: 40px;
border-radius: 10px;
}
.chevron {
display: inline-flex;
align-items: center;
@ -506,6 +512,12 @@ input:focus-visible {
white-space: nowrap;
}
.menu-count.skeleton-line {
width: 28px;
height: 16px;
border-radius: 7px;
}
.sheet-modal,
.message-modal,
.confirm-modal {
@ -661,7 +673,6 @@ input:focus-visible {
}
.host-list,
.bill-list,
.message-list,
.invite-steps {
display: grid;
@ -673,7 +684,6 @@ input:focus-visible {
}
.host-row,
.bill-row,
.message-card,
.invite-step {
border: 1px solid var(--line);
@ -681,46 +691,6 @@ input:focus-visible {
background: #fbfcfc;
}
.bill-row {
display: grid;
gap: 10px;
padding: 12px;
}
.bill-month {
color: var(--text);
font-size: 15px;
font-weight: 950;
line-height: 1.2;
}
.bill-values {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
}
.bill-cell span {
display: block;
overflow: hidden;
color: var(--muted);
font-size: 12px;
font-weight: 800;
line-height: 1.2;
text-overflow: ellipsis;
white-space: nowrap;
}
.bill-cell strong {
display: block;
margin-top: 4px;
overflow-wrap: anywhere;
color: #292d33;
font-size: 16px;
font-weight: 950;
line-height: 1.2;
}
.host-search {
display: grid;
grid-template-columns: minmax(0, 1fr) 82px;
@ -776,6 +746,32 @@ input:focus-visible {
padding: 12px;
}
.host-row.is-skeleton {
pointer-events: none;
}
.host-row.is-skeleton .small-avatar {
background: transparent;
}
.host-row.is-skeleton .host-name.skeleton-line {
width: min(148px, 100%);
height: 18px;
border-radius: 7px;
}
.host-row.is-skeleton .host-meta.skeleton-line {
width: min(190px, 100%);
height: 14px;
border-radius: 7px;
}
.host-side-skeleton.skeleton-line {
width: 58px;
height: 32px;
border-radius: 8px;
}
.host-user,
.message-user {
display: flex;
@ -908,6 +904,111 @@ input:focus-visible {
text-align: center;
}
.policy-sheet-body {
min-height: 180px;
overflow-y: auto;
padding: 16px;
-webkit-overflow-scrolling: touch;
}
.policy-summary {
display: flex;
flex-direction: column;
gap: 6px;
padding: 14px;
border-radius: 8px;
background: var(--primary-soft);
}
.policy-summary strong {
overflow-wrap: anywhere;
color: var(--text);
font-size: 17px;
font-weight: 950;
line-height: 1.25;
}
.policy-summary span {
color: var(--muted);
font-size: 12px;
font-weight: 800;
line-height: 1.45;
}
.policy-empty {
padding: 22px 10px;
color: var(--muted);
text-align: center;
font-size: 14px;
font-weight: 850;
line-height: 1.45;
}
.policy-level-list {
display: flex;
flex-direction: column;
gap: 10px;
margin-top: 12px;
}
.policy-level-row {
padding: 14px;
border: 1px solid var(--line);
border-radius: 8px;
background: #fff;
}
.policy-row-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
}
.policy-level {
color: var(--text);
font-size: 16px;
font-weight: 950;
line-height: 1.25;
}
.policy-effective {
color: var(--muted);
text-align: right;
font-size: 12px;
font-weight: 800;
line-height: 1.25;
}
.policy-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
margin-top: 12px;
}
.policy-cell {
min-width: 0;
}
.policy-cell-label {
display: block;
color: var(--muted);
font-size: 11px;
font-weight: 800;
line-height: 1.2;
}
.policy-cell-value {
display: block;
margin-top: 4px;
overflow-wrap: anywhere;
color: #292d33;
font-size: 14px;
font-weight: 950;
line-height: 1.25;
}
.modal-open {
overflow: hidden;
}
@ -976,7 +1077,7 @@ input:focus-visible {
margin-left: 14px;
}
.bill-values {
.policy-grid {
grid-template-columns: 1fr;
}