413 lines
16 KiB
JavaScript
413 lines
16 KiB
JavaScript
(function () {
|
|
var page = document.getElementById('page');
|
|
var tabs = Array.prototype.slice.call(document.querySelectorAll('[data-tab-target]'));
|
|
var panels = Array.prototype.slice.call(document.querySelectorAll('[data-panel]'));
|
|
var stageWrap = document.getElementById('stageWrap');
|
|
var dateText = document.querySelector('.date-text');
|
|
var note = document.querySelector('.note');
|
|
var historyDate = document.querySelector('.history-date');
|
|
var COIN_IMAGE = './assets/coin.png';
|
|
|
|
var mockRanks = [
|
|
{ rank: 1, name: 'hanneem', score: '337700', avatar: './assets/avatar-top.png' },
|
|
{ rank: 2, name: 'hanneem', score: '337700', avatar: './assets/avatar-user.png' },
|
|
{ rank: 3, name: 'hanneem', score: '337700', avatar: './assets/avatar-user.png' },
|
|
{ rank: 4, name: 'hanneem', score: '337700', avatar: './assets/avatar-user.png' },
|
|
{ rank: 5, name: 'hanneem', score: '337700', avatar: './assets/avatar-user.png' },
|
|
];
|
|
var mockRewards = [
|
|
{ rank_no: 1, resource_group_id: 1001, top: 1488 },
|
|
{ rank_no: 2, resource_group_id: 1002, top: 1985 },
|
|
{ rank_no: 3, resource_group_id: 1003, top: 2482 },
|
|
];
|
|
var state = {
|
|
current: null,
|
|
weeklyEntries: [],
|
|
historyCycles: [],
|
|
error: '',
|
|
loading: true,
|
|
};
|
|
|
|
function rankMedal(rank) {
|
|
if (rank === 1) return './assets/medal-1.png';
|
|
if (rank === 2) return './assets/medal-2.png';
|
|
if (rank === 3) return './assets/medal-3.png';
|
|
return '';
|
|
}
|
|
|
|
function renderRankList(targetID, top, items, emptyText) {
|
|
var list = document.getElementById(targetID);
|
|
var rows = (items || []).slice(0, 8);
|
|
if (!rows.length) {
|
|
list.innerHTML =
|
|
'<div class="rank-empty" style="top:' + top + 'px">' + escapeHTML(emptyText || 'No ranking data yet.') + '</div>';
|
|
return;
|
|
}
|
|
list.innerHTML = rows
|
|
.map(function (item, index) {
|
|
var medal = rankMedal(item.rank);
|
|
return [
|
|
'<article class="rank-row ',
|
|
index % 2 === 0 ? 'is-odd' : 'is-even',
|
|
'" style="top:',
|
|
top + index * 140,
|
|
'px">',
|
|
medal
|
|
? '<img class="rank-medal" src="' + medal + '" alt="No. ' + item.rank + '" />'
|
|
: '<span class="rank-number">' + item.rank + '</span>',
|
|
'<img class="rank-avatar" src="' + escapeAttr(item.avatar || './assets/avatar-user.png') + '" alt="" />',
|
|
'<div class="rank-name">',
|
|
escapeHTML(item.name || '-'),
|
|
'</div>',
|
|
'<div class="rank-score">',
|
|
escapeHTML(formatNumber(item.score)),
|
|
'</div>',
|
|
'</article>',
|
|
].join('');
|
|
})
|
|
.join('');
|
|
}
|
|
|
|
function rewardItem(item) {
|
|
var img = item.image || './assets/gift-ball.png';
|
|
var label = item.label || 'Resource Group #' + (item.resource_group_id || '-');
|
|
var labelHTML = item.coin ? '<div class="reward-label">' + escapeHTML(label) + '</div>' : '';
|
|
return [
|
|
'<div class="reward-item',
|
|
item.single ? ' is-single' : '',
|
|
item.coin ? ' is-coin' : '',
|
|
'">',
|
|
'<div class="gift-card">',
|
|
'<img class="gift-frame" src="./assets/gift-card.png" alt="" />',
|
|
'<img class="gift-glow" src="./assets/gift-glow.png" alt="" />',
|
|
'<img class="gift-img" src="' + escapeAttr(img) + '" alt="Reward" />',
|
|
'</div>',
|
|
labelHTML,
|
|
'</div>',
|
|
].join('');
|
|
}
|
|
|
|
function renderRewards(rewards) {
|
|
var root = document.getElementById('rewardGroups');
|
|
var groups = normalizeRewards(rewards);
|
|
root.innerHTML = groups
|
|
.map(function (group) {
|
|
return [
|
|
'<section class="reward-group" style="top:',
|
|
group.top,
|
|
'px">',
|
|
'<h2 class="reward-title">',
|
|
'<img src="./assets/reward-title-bar.png" alt="" />',
|
|
'<span>TOP',
|
|
group.rank_no,
|
|
'</span>',
|
|
'</h2>',
|
|
group.items.map(rewardItem).join(''),
|
|
'</section>',
|
|
].join('');
|
|
})
|
|
.join('');
|
|
}
|
|
|
|
function normalizeRewards(rewards) {
|
|
var tops = [1488, 1985, 2482];
|
|
var input = rewards && rewards.length ? rewards : [];
|
|
return [1, 2, 3].map(function (rankNo, index) {
|
|
var reward =
|
|
input.find(function (item) {
|
|
return Number(item.rank_no || item.rankNo) === rankNo;
|
|
}) || {};
|
|
var items = normalizeRewardItems(reward);
|
|
if (!items.length) {
|
|
items = [
|
|
{
|
|
label: reward.name || 'Resource Group #' + (reward.resource_group_id || reward.resourceGroupId || '-'),
|
|
resource_group_id: reward.resource_group_id || reward.resourceGroupId,
|
|
image: reward.image_url || reward.imageUrl || reward.icon_url || reward.iconUrl,
|
|
single: true,
|
|
},
|
|
];
|
|
}
|
|
return { rank_no: rankNo, top: tops[index], items: items.slice(0, 3) };
|
|
});
|
|
}
|
|
|
|
function normalizeRewardItems(reward) {
|
|
var group = reward.resource_group || reward.resourceGroup || reward.reward_resource_group || reward.rewardResourceGroup || {};
|
|
var items = reward.items || reward.resources || group.items || [];
|
|
return (items || []).map(function (item) {
|
|
var resource = item.resource || {};
|
|
var quantity = Number(item.quantity || 0);
|
|
var walletAmount = Number(item.wallet_asset_amount || item.walletAssetAmount || 0);
|
|
var walletType = String(item.wallet_asset_type || item.walletAssetType || '').toUpperCase();
|
|
var name =
|
|
item.label ||
|
|
resource.name ||
|
|
item.name ||
|
|
(walletType ? walletType.replace(/_/g, ' ') : '') ||
|
|
group.name ||
|
|
reward.name ||
|
|
'Reward';
|
|
var suffix = quantity > 1 ? ' x' + quantity : walletAmount > 0 ? ' x' + formatNumber(walletAmount) : '';
|
|
return {
|
|
label: name + suffix,
|
|
resource_group_id: reward.resource_group_id || reward.resourceGroupId || group.group_id || group.groupId,
|
|
coin: walletType === 'COIN',
|
|
image:
|
|
walletType === 'COIN'
|
|
? COIN_IMAGE
|
|
: item.image ||
|
|
item.image_url ||
|
|
item.imageUrl ||
|
|
resource.preview_url ||
|
|
resource.previewUrl ||
|
|
resource.asset_url ||
|
|
resource.assetUrl ||
|
|
resource.animation_url ||
|
|
resource.animationUrl,
|
|
single: false,
|
|
};
|
|
});
|
|
}
|
|
|
|
function renderGiftStrip(gifts) {
|
|
var cards = Array.prototype.slice.call(document.querySelectorAll('.gift-strip .gift-card'));
|
|
cards.forEach(function (card, index) {
|
|
var gift = (gifts || [])[index] || {};
|
|
var resource = gift.resource || {};
|
|
var img =
|
|
gift.image_url ||
|
|
gift.imageUrl ||
|
|
gift.cover_url ||
|
|
gift.coverUrl ||
|
|
gift.preview_url ||
|
|
gift.previewUrl ||
|
|
gift.icon_url ||
|
|
gift.iconUrl ||
|
|
resource.preview_url ||
|
|
resource.previewUrl ||
|
|
gift.asset_url ||
|
|
gift.assetUrl ||
|
|
resource.asset_url ||
|
|
resource.assetUrl;
|
|
var image = card.querySelector('.gift-img');
|
|
if (image && img) image.src = img;
|
|
var labelNode = card.querySelector('.gift-name');
|
|
if (labelNode) {
|
|
labelNode.remove();
|
|
}
|
|
});
|
|
}
|
|
|
|
function renderActivity() {
|
|
var cycle = state.current && state.current.cycle;
|
|
var historyCycle = state.historyCycles[0] || {};
|
|
var historyEntries = normalizeEntries(historyCycle.top_entries || historyCycle.topEntries || []);
|
|
var weeklyEntries = normalizeEntries(state.weeklyEntries);
|
|
|
|
if (cycle) {
|
|
dateText.textContent = formatRangeUTC(cycle.start_ms || cycle.startMs, cycle.end_ms || cycle.endMs);
|
|
note.innerHTML =
|
|
'Note: Send the following three gifts to participate in the<br />ranking. Users who rank in the top 3 of the leaderboard<br />will receive rewards.';
|
|
renderGiftStrip(cycle.gifts || []);
|
|
renderRewards(cycle.rewards || []);
|
|
} else {
|
|
dateText.textContent = 'No active cycle';
|
|
note.textContent = state.error || 'No Weekly Star activity is configured for your region.';
|
|
renderGiftStrip([]);
|
|
renderRewards([]);
|
|
}
|
|
|
|
if (historyCycle.cycle) {
|
|
historyDate.textContent = formatDateRange(historyCycle.cycle.start_ms || historyCycle.cycle.startMs, historyCycle.cycle.end_ms || historyCycle.cycle.endMs);
|
|
} else {
|
|
historyDate.textContent = 'Previous Top 3 Records';
|
|
}
|
|
|
|
renderRankList('historyList', 1607, historyEntries, 'No previous ranking records.');
|
|
renderRankList('weeklyList', 1496, weeklyEntries, state.loading ? 'Loading...' : 'No ranking data yet.');
|
|
}
|
|
|
|
function normalizeEntries(entries) {
|
|
return (entries || []).map(function (entry, index) {
|
|
var user = entry.user || {};
|
|
return {
|
|
rank: Number(entry.rank_no || entry.rankNo || index + 1),
|
|
name: user.username || user.display_user_id || user.displayUserId || entry.user_id || entry.userId || '-',
|
|
score: entry.score || 0,
|
|
avatar: user.avatar || (Number(entry.rank_no || entry.rankNo) === 1 ? './assets/avatar-top.png' : './assets/avatar-user.png'),
|
|
};
|
|
});
|
|
}
|
|
|
|
function setTab(tabName) {
|
|
var next = tabName || 'history';
|
|
page.setAttribute('data-tab', next);
|
|
tabs.forEach(function (tab) {
|
|
var active = tab.getAttribute('data-tab-target') === next;
|
|
tab.classList.toggle('is-active', active);
|
|
tab.setAttribute('aria-selected', active ? 'true' : 'false');
|
|
});
|
|
panels.forEach(function (panel) {
|
|
panel.hidden = panel.getAttribute('data-panel') !== next;
|
|
});
|
|
updateBodyHeight();
|
|
}
|
|
|
|
function normalizeTab(value) {
|
|
if (value === 'weekly' || value === 'rewards' || value === 'history') return value;
|
|
return 'history';
|
|
}
|
|
|
|
function updateBodyHeight() {
|
|
var scale = window.innerWidth / 1080;
|
|
var designHeight = page.getAttribute('data-tab') === 'rewards' ? 3138 : 2310;
|
|
document.documentElement.style.setProperty('--design-scale', String(scale));
|
|
stageWrap.style.height = Math.ceil(designHeight * scale) + 'px';
|
|
document.body.style.minHeight = stageWrap.offsetHeight + 'px';
|
|
}
|
|
|
|
function loadMock() {
|
|
state.loading = false;
|
|
state.current = {
|
|
cycle: {
|
|
start_ms: Date.UTC(2025, 11, 28, 0, 0, 0),
|
|
end_ms: Date.UTC(2026, 0, 3, 23, 59, 0),
|
|
gifts: [{ gift_id: 'gift_1' }, { gift_id: 'gift_2' }, { gift_id: 'gift_3' }],
|
|
rewards: mockRewards,
|
|
},
|
|
};
|
|
state.weeklyEntries = mockRanks.map(function (item) {
|
|
return {
|
|
rank_no: item.rank,
|
|
score: item.score,
|
|
user: { username: item.name, avatar: item.avatar },
|
|
};
|
|
});
|
|
state.historyCycles = [
|
|
{
|
|
cycle: {
|
|
start_ms: Date.UTC(2025, 11, 7, 0, 0, 0),
|
|
end_ms: Date.UTC(2025, 11, 14, 23, 59, 0),
|
|
},
|
|
top_entries: state.weeklyEntries.slice(0, 3),
|
|
},
|
|
];
|
|
renderActivity();
|
|
}
|
|
|
|
function loadReal() {
|
|
if (!window.HyAppAPI || !window.HyAppAPI.weeklyStar) {
|
|
state.loading = false;
|
|
state.error = 'API module is not available.';
|
|
renderActivity();
|
|
return;
|
|
}
|
|
renderRankList('weeklyList', 1496, [], 'Loading...');
|
|
window.HyAppAPI.weeklyStar
|
|
.current()
|
|
.then(function (current) {
|
|
state.current = current || {};
|
|
var cycle = state.current.cycle || {};
|
|
var cycleID = cycle.cycle_id || cycle.cycleId || '';
|
|
return Promise.all([
|
|
cycleID
|
|
? window.HyAppAPI.weeklyStar.leaderboard({ cycle_id: cycleID, page_size: 20 })
|
|
: Promise.resolve({ entries: [] }),
|
|
window.HyAppAPI.weeklyStar.history(10),
|
|
]);
|
|
})
|
|
.then(function (results) {
|
|
state.weeklyEntries = results[0].entries || [];
|
|
state.historyCycles = results[1].cycles || [];
|
|
state.error = '';
|
|
})
|
|
.catch(function (error) {
|
|
state.error = error.message || 'Unable to load Weekly Star.';
|
|
state.weeklyEntries = [];
|
|
state.historyCycles = [];
|
|
})
|
|
.finally(function () {
|
|
state.loading = false;
|
|
renderActivity();
|
|
});
|
|
}
|
|
|
|
function isMockMode() {
|
|
return new URLSearchParams(window.location.search).get('mock') === '1';
|
|
}
|
|
|
|
function formatRangeUTC(start, end) {
|
|
return formatDateTimeUTC(start) + '-' + formatDateTimeUTC(end) + '(UTC)';
|
|
}
|
|
|
|
function formatDateRange(start, end) {
|
|
return formatDateUTC(start).replace(/-/g, '/') + '-' + formatDateUTC(end).replace(/-/g, '/');
|
|
}
|
|
|
|
function formatDateTimeUTC(value) {
|
|
var date = new Date(Number(value || 0));
|
|
if (!Number(value || 0)) return '-';
|
|
return (
|
|
date.getUTCFullYear() +
|
|
'-' +
|
|
(date.getUTCMonth() + 1) +
|
|
'-' +
|
|
date.getUTCDate() +
|
|
' ' +
|
|
pad(date.getUTCHours()) +
|
|
':' +
|
|
pad(date.getUTCMinutes())
|
|
);
|
|
}
|
|
|
|
function formatDateUTC(value) {
|
|
var date = new Date(Number(value || 0));
|
|
if (!Number(value || 0)) return '-';
|
|
return date.getUTCFullYear() + '-' + pad(date.getUTCMonth() + 1) + '-' + pad(date.getUTCDate());
|
|
}
|
|
|
|
function formatNumber(value) {
|
|
return new Intl.NumberFormat('en-US').format(Number(value || 0));
|
|
}
|
|
|
|
function pad(value) {
|
|
return String(value).padStart(2, '0');
|
|
}
|
|
|
|
function escapeHTML(value) {
|
|
return String(value == null ? '' : value)
|
|
.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"')
|
|
.replace(/'/g, ''');
|
|
}
|
|
|
|
function escapeAttr(value) {
|
|
return escapeHTML(value);
|
|
}
|
|
|
|
function init() {
|
|
tabs.forEach(function (tab) {
|
|
tab.addEventListener('click', function () {
|
|
var next = tab.getAttribute('data-tab-target');
|
|
setTab(next);
|
|
if (window.history && window.history.replaceState) {
|
|
window.history.replaceState(null, '', '#' + next);
|
|
}
|
|
});
|
|
});
|
|
|
|
window.addEventListener('resize', updateBodyHeight);
|
|
setTab(normalizeTab(window.location.hash.replace('#', '')));
|
|
if (isMockMode()) {
|
|
loadMock();
|
|
} else {
|
|
loadReal();
|
|
}
|
|
}
|
|
|
|
init();
|
|
})();
|