205 lines
7.4 KiB
JavaScript
205 lines
7.4 KiB
JavaScript
(function () {
|
|
var ASSET_BASE = './assets/recharge-activity/';
|
|
var viewport = document.getElementById('appViewport');
|
|
var rewardSections = document.getElementById('rewardSections');
|
|
var countNodes = {
|
|
days: document.querySelector('[data-count="days"]'),
|
|
hours: document.querySelector('[data-count="hours"]'),
|
|
minutes: document.querySelector('[data-count="minutes"]'),
|
|
seconds: document.querySelector('[data-count="seconds"]'),
|
|
};
|
|
|
|
var DESIGN_WIDTH = 1080;
|
|
var DESIGN_HEIGHT = 3273;
|
|
var VIEWPORT_WIDTH = 375;
|
|
var countdownEndAt = resolveCountdownEndAt();
|
|
var activityData = {
|
|
user: {
|
|
name: 'nanfangjian',
|
|
id: '12345678',
|
|
avatar: ASSET_BASE + 'profile-avatar.png',
|
|
accumulatedRecharge: '5998',
|
|
},
|
|
rewards: [
|
|
{
|
|
amount: '$100',
|
|
top: 1776,
|
|
background: ASSET_BASE + 'reward-section-a.png',
|
|
claim: { text: 'Receive', claimable: true, claimed: false },
|
|
cards: [
|
|
{ price: '$100', icon: ASSET_BASE + 'reward-icon.png', left: 111, top: 293 },
|
|
{ price: '$100', icon: ASSET_BASE + 'reward-icon.png', left: 560, top: 293 },
|
|
],
|
|
},
|
|
{
|
|
amount: '$100',
|
|
top: 2466,
|
|
background: ASSET_BASE + 'reward-section-b.png',
|
|
claim: { text: 'Receive', claimable: true, claimed: false },
|
|
cards: [
|
|
{ price: '$100', icon: ASSET_BASE + 'reward-icon.png', left: 70.5, top: 278 },
|
|
{ price: '$100', icon: ASSET_BASE + 'reward-icon.png', left: 339.5, top: 278 },
|
|
{ price: '$100', icon: ASSET_BASE + 'reward-icon.png', left: 608.5, top: 278 },
|
|
],
|
|
},
|
|
],
|
|
};
|
|
|
|
function getParams() {
|
|
return new URLSearchParams(window.location.search || '');
|
|
}
|
|
|
|
function t(key, fallback) {
|
|
return window.HyAppI18n && window.HyAppI18n.t
|
|
? window.HyAppI18n.t(key, fallback)
|
|
: fallback || key;
|
|
}
|
|
|
|
function escapeHTML(value) {
|
|
return String(value || '')
|
|
.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"')
|
|
.replace(/'/g, ''');
|
|
}
|
|
|
|
function twoDigits(value) {
|
|
return String(Math.max(0, value)).padStart(2, '0');
|
|
}
|
|
|
|
function resolveCountdownEndAt() {
|
|
var params = getParams();
|
|
var explicitEnd = Date.parse(params.get('end_at') || params.get('endAt') || '');
|
|
if (Number.isFinite(explicitEnd) && explicitEnd > Date.now()) return explicitEnd;
|
|
|
|
var hours = Number(params.get('hours'));
|
|
if (Number.isFinite(hours) && hours > 0) return Date.now() + hours * 60 * 60 * 1000;
|
|
|
|
// This page is intentionally interface-free for now; when an API is added,
|
|
// use the server period end time here and do not recover failed requests with mock data.
|
|
return Date.now() + 25 * 60 * 60 * 1000 + 61 * 1000;
|
|
}
|
|
|
|
function updateScale() {
|
|
var scale = Math.min(window.innerWidth / VIEWPORT_WIDTH, 1);
|
|
var scaledHeight = Math.ceil(DESIGN_HEIGHT * (VIEWPORT_WIDTH / DESIGN_WIDTH));
|
|
|
|
document.documentElement.style.setProperty('--app-scale', String(scale));
|
|
viewport.style.minHeight = scaledHeight + 'px';
|
|
document.body.style.minHeight = Math.ceil(scaledHeight * scale) + 'px';
|
|
}
|
|
|
|
function updateCountdown() {
|
|
var diff = Math.max(0, countdownEndAt - Date.now());
|
|
var totalSeconds = Math.floor(diff / 1000);
|
|
var days = Math.floor(totalSeconds / 86400);
|
|
var hours = Math.floor((totalSeconds % 86400) / 3600);
|
|
var minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
var seconds = totalSeconds % 60;
|
|
|
|
countNodes.days.textContent = twoDigits(days);
|
|
countNodes.hours.textContent = twoDigits(hours);
|
|
countNodes.minutes.textContent = twoDigits(minutes);
|
|
countNodes.seconds.textContent = twoDigits(seconds);
|
|
}
|
|
|
|
function renderProfile(user) {
|
|
document.querySelector('[data-profile-avatar]').src = user.avatar;
|
|
document.querySelector('[data-profile-name]').textContent = user.name;
|
|
document.querySelector('[data-profile-id]').textContent =
|
|
t('rechargeReward.idPrefix', 'ID:') + ' ' + user.id;
|
|
document.querySelector('[data-profile-recharge]').textContent =
|
|
t('rechargeReward.accumulatedRecharge', 'Accumlated Recharge:') +
|
|
user.accumulatedRecharge;
|
|
}
|
|
|
|
function renderRewardCard(card) {
|
|
return [
|
|
'<div class="reward-card" style="left:',
|
|
card.left,
|
|
'px;top:',
|
|
card.top,
|
|
'px">',
|
|
'<img class="reward-frame" src="',
|
|
ASSET_BASE,
|
|
'reward-card-frame.png',
|
|
'" alt="" />',
|
|
'<img class="reward-icon" src="',
|
|
escapeHTML(card.icon),
|
|
'" alt="" />',
|
|
'<span class="reward-price">',
|
|
escapeHTML(card.price),
|
|
'</span>',
|
|
'</div>',
|
|
].join('');
|
|
}
|
|
|
|
function renderClaimButton(claim) {
|
|
var stateClass = claim.claimed ? ' is-claimed' : claim.claimable ? ' is-claimable' : ' is-disabled';
|
|
return [
|
|
'<button class="claim-button',
|
|
stateClass,
|
|
'" type="button"',
|
|
claim.claimable && !claim.claimed ? '' : ' disabled',
|
|
'>',
|
|
'<img class="claim-button-bg" src="',
|
|
ASSET_BASE,
|
|
'receive-button-bg.png" alt="" />',
|
|
'<span>',
|
|
escapeHTML(claim.text || 'Receive'),
|
|
'</span>',
|
|
'</button>',
|
|
].join('');
|
|
}
|
|
|
|
function renderRewards(rewards) {
|
|
rewardSections.innerHTML = rewards
|
|
.map(function (section) {
|
|
var title = t('rechargeReward.rechargeTitle', 'Recharge {amount}').replace(
|
|
'{amount}',
|
|
section.amount
|
|
);
|
|
return [
|
|
'<section class="reward-section" style="--section-top:',
|
|
section.top,
|
|
'px">',
|
|
'<img class="reward-section-bg" src="',
|
|
escapeHTML(section.background),
|
|
'" alt="" />',
|
|
'<div class="title-pill">',
|
|
'<span>',
|
|
escapeHTML(title),
|
|
'</span>',
|
|
'</div>',
|
|
section.cards
|
|
.map(function (card) {
|
|
return renderRewardCard(card);
|
|
})
|
|
.join(''),
|
|
renderClaimButton(section.claim || { text: 'Receive', claimable: false }),
|
|
'</section>',
|
|
].join('');
|
|
})
|
|
.join('');
|
|
}
|
|
|
|
function renderPage() {
|
|
document.title = t('rechargeReward.pageTitle', 'Recharge Reward');
|
|
renderProfile(activityData.user);
|
|
renderRewards(activityData.rewards);
|
|
}
|
|
|
|
function init() {
|
|
updateScale();
|
|
updateCountdown();
|
|
renderPage();
|
|
|
|
window.setInterval(updateCountdown, 1000);
|
|
window.addEventListener('resize', updateScale);
|
|
window.addEventListener('hyapp:i18n-ready', renderPage);
|
|
}
|
|
|
|
init();
|
|
})();
|