agency center
This commit is contained in:
parent
527484d3d8
commit
da6d029a27
@ -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',
|
||||
|
||||
@ -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">›</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">›</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"
|
||||
>
|
||||
×
|
||||
</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>
|
||||
|
||||
@ -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') {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user