app邀请
BIN
activity/invite/assets/generated/copy-icon.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
activity/invite/assets/generated/invite-input-bg.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
activity/invite/assets/generated/inviter-card-bg.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
activity/invite/assets/generated/modal-bg.png
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
BIN
activity/invite/assets/generated/modal-bottom.png
Normal file
|
After Width: | Height: | Size: 676 KiB |
BIN
activity/invite/assets/generated/modal-button-active.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
activity/invite/assets/generated/modal-button-inactive.png
Normal file
|
After Width: | Height: | Size: 871 KiB |
BIN
activity/invite/assets/generated/modal-middle.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
activity/invite/assets/generated/modal-top.png
Normal file
|
After Width: | Height: | Size: 670 KiB |
BIN
activity/invite/assets/generated/panel-a-monthly-bg.png
Normal file
|
After Width: | Height: | Size: 3.9 MiB |
BIN
activity/invite/assets/generated/panel-a-monthly-quota-bg.png
Normal file
|
After Width: | Height: | Size: 3.8 MiB |
BIN
activity/invite/assets/generated/panel-a-stats-bg.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
activity/invite/assets/generated/panel-b-rank-bg.png
Normal file
|
After Width: | Height: | Size: 6.3 MiB |
BIN
activity/invite/assets/generated/reward-success-visual.png
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
activity/invite/assets/generated/reward-topup-visual.png
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
activity/invite/assets/generated/search-icon.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
@ -7,7 +7,7 @@
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
|
||||
/>
|
||||
<title>Invite Friends</title>
|
||||
<link rel="stylesheet" href="./style.css?v=20260611-1" />
|
||||
<link rel="stylesheet" href="./style.css?v=20260629-bind-invite" />
|
||||
</head>
|
||||
<body>
|
||||
<main
|
||||
@ -72,38 +72,28 @@
|
||||
(Earn for every friend you invite)
|
||||
</p>
|
||||
<div class="reward-grid">
|
||||
<article class="reward-item">
|
||||
<article class="reward-item reward-item-success">
|
||||
<img
|
||||
class="reward-orb"
|
||||
src="./assets/reward-orb-bg.png"
|
||||
class="reward-visual"
|
||||
src="./assets/generated/reward-success-visual.png"
|
||||
alt=""
|
||||
/>
|
||||
<img
|
||||
class="reward-gold"
|
||||
src="./assets/gold-stack.png"
|
||||
alt=""
|
||||
/>
|
||||
<strong>+2000</strong>
|
||||
<span data-i18n="invite.invitationReceived">
|
||||
Invitation received
|
||||
<strong id="rewardInviteAmount"> +1000 </strong>
|
||||
<span data-i18n="invite.successfulInvite">
|
||||
Successful Invite
|
||||
</span>
|
||||
</article>
|
||||
<img class="plus" src="./assets/plus.svg" alt="+" />
|
||||
<article class="reward-item">
|
||||
<article class="reward-item reward-item-topup">
|
||||
<img
|
||||
class="reward-orb"
|
||||
src="./assets/reward-orb-bg.png"
|
||||
class="reward-visual"
|
||||
src="./assets/generated/reward-topup-visual.png"
|
||||
alt=""
|
||||
/>
|
||||
<img
|
||||
class="reward-gold"
|
||||
src="./assets/gold-stack.png"
|
||||
alt=""
|
||||
/>
|
||||
<strong>+1000</strong>
|
||||
<span data-i18n="invite.topUpViaFriends">
|
||||
Top up via friends
|
||||
</span>
|
||||
<strong id="rewardTopUpPercent">1%</strong>
|
||||
<span data-i18n="invite.friendTopUp"
|
||||
>Friend's Top-Up</span
|
||||
>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
@ -116,31 +106,39 @@
|
||||
(Copy your invitation link and share it with your friends)
|
||||
</p>
|
||||
<div class="invite-fields">
|
||||
<div class="link-box" id="inviteLink">
|
||||
http://yourappbalbalanal
|
||||
<div class="invite-field">
|
||||
<div class="link-box" id="inviteLink">
|
||||
http://yourappbalbalanal
|
||||
</div>
|
||||
<button
|
||||
class="copy-icon-button"
|
||||
id="copyLinkButton"
|
||||
type="button"
|
||||
aria-label="Copy invitation link"
|
||||
data-i18n-aria="invite.copyInviteLink"
|
||||
></button>
|
||||
</div>
|
||||
<div class="link-box invite-code" id="inviteCode">
|
||||
ABC123
|
||||
<div class="invite-field is-code">
|
||||
<div class="link-box invite-code" id="inviteCode">
|
||||
ABC123
|
||||
</div>
|
||||
<button
|
||||
class="copy-icon-button"
|
||||
id="copyCodeButton"
|
||||
type="button"
|
||||
aria-label="Copy invitation code"
|
||||
data-i18n-aria="invite.copyInviteCode"
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="invite-actions">
|
||||
<button
|
||||
class="ornate-button"
|
||||
id="copyLinkButton"
|
||||
type="button"
|
||||
data-i18n="invite.copy"
|
||||
>
|
||||
Copy
|
||||
</button>
|
||||
<button
|
||||
class="ornate-button small-copy-button"
|
||||
id="copyCodeButton"
|
||||
type="button"
|
||||
data-i18n="invite.copy"
|
||||
>
|
||||
Copy
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
class="ornate-button bind-invite-button"
|
||||
id="bindInviteButton"
|
||||
type="button"
|
||||
data-i18n="invite.linkInviter"
|
||||
>
|
||||
Link Inviter
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<section class="ornate-panel stats-panel" aria-label="Invite stats">
|
||||
@ -234,6 +232,67 @@
|
||||
<h2 data-i18n="invite.rank">Rank</h2>
|
||||
<div class="rank-list" id="rankList"></div>
|
||||
</section>
|
||||
|
||||
<div
|
||||
class="invite-modal"
|
||||
id="bindInviteModal"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="bindInviteTitle"
|
||||
hidden
|
||||
>
|
||||
<div class="bind-card">
|
||||
<h2 id="bindInviteTitle" data-i18n="invite.bindInviteTitle">
|
||||
Bind Referrer
|
||||
</h2>
|
||||
<div class="bind-input-state" id="bindInputCard">
|
||||
<label class="bind-input-shell">
|
||||
<input
|
||||
id="bindInviteInput"
|
||||
type="text"
|
||||
inputmode="text"
|
||||
autocapitalize="characters"
|
||||
autocomplete="off"
|
||||
placeholder="Enter Invitation Code"
|
||||
data-i18n-placeholder="invite.bindInvitePlaceholder"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="bind-result-state" id="bindResultCard" hidden>
|
||||
<article class="inviter-card">
|
||||
<img
|
||||
id="inviterAvatar"
|
||||
src="./assets/rank-avatar.png"
|
||||
alt=""
|
||||
/>
|
||||
<div>
|
||||
<strong id="inviterName">--</strong>
|
||||
<span id="inviterDisplayId">--</span>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="bind-actions">
|
||||
<button
|
||||
class="bind-action-button bind-cancel-button"
|
||||
id="bindCancelButton"
|
||||
type="button"
|
||||
data-i18n="invite.cancel"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
class="bind-action-button bind-confirm-button"
|
||||
id="confirmBindButton"
|
||||
type="button"
|
||||
data-i18n="invite.confirm"
|
||||
>
|
||||
Confirm
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
@ -253,9 +312,9 @@
|
||||
})();
|
||||
</script>
|
||||
<script src="../../common/i18n.js?v=20260606-1"></script>
|
||||
<script src="../../common/api.js?v=20260611-invite-rank"></script>
|
||||
<script src="../../common/api.js?v=20260630-invite-code"></script>
|
||||
<script src="../../common/params.js?v=20260611-invite-referrer"></script>
|
||||
<script src="../../common/toast.js"></script>
|
||||
<script src="./script.js?v=20260611-invite-rank"></script>
|
||||
<script src="./script.js?v=20260630-invite-code"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -26,10 +26,15 @@
|
||||
inviterName: firstParam(SHARE_NAME_KEYS),
|
||||
inviterAvatar: firstParam(SHARE_AVATAR_KEYS),
|
||||
inviteLink: '',
|
||||
currentUser: null,
|
||||
pendingInviteCode: '',
|
||||
searchedInviter: null,
|
||||
inviteRewardStatus: null,
|
||||
rankRows: [],
|
||||
rankLoaded: false,
|
||||
rankLoading: false,
|
||||
searchingInviter: false,
|
||||
bindingInviter: false,
|
||||
claiming: {},
|
||||
};
|
||||
|
||||
@ -49,6 +54,10 @@
|
||||
return String(value || '').trim();
|
||||
}
|
||||
|
||||
function normalizeInviteCodeInput(value) {
|
||||
return textValue(value).toUpperCase();
|
||||
}
|
||||
|
||||
function readPath(source, path) {
|
||||
var value = source;
|
||||
for (var i = 0; i < path.length; i += 1) {
|
||||
@ -66,6 +75,25 @@
|
||||
return '';
|
||||
}
|
||||
|
||||
function currentUserPayload(data, profile) {
|
||||
var target = profile || data || {};
|
||||
return Boolean(
|
||||
target.user_id ||
|
||||
target.userId ||
|
||||
target.display_user_id ||
|
||||
target.displayUserId ||
|
||||
target.username ||
|
||||
target.nickname ||
|
||||
target.profile_completed !== undefined ||
|
||||
target.profileCompleted !== undefined
|
||||
);
|
||||
}
|
||||
|
||||
function mergeCurrentUser(profile) {
|
||||
if (!profile || typeof profile !== 'object') return;
|
||||
state.currentUser = Object.assign({}, state.currentUser || {}, profile);
|
||||
}
|
||||
|
||||
function currentLandingURL() {
|
||||
return new URL('../invite-landing/', window.location.href);
|
||||
}
|
||||
@ -112,6 +140,7 @@
|
||||
function applyCurrentUser(payload) {
|
||||
var data = readOverviewPayload(payload || {});
|
||||
var profile = data.profile || data;
|
||||
if (currentUserPayload(data, profile)) mergeCurrentUser(profile);
|
||||
var inviteCode = firstPath(data, [
|
||||
['invite', 'my_invite_code'],
|
||||
['invite', 'myInviteCode'],
|
||||
@ -171,6 +200,13 @@
|
||||
.then(applyCurrentUser)
|
||||
.catch(function () {});
|
||||
}
|
||||
function loadMeProfile() {
|
||||
if (!hasToken || !userAPI || !userAPI.me) return Promise.resolve();
|
||||
return userAPI
|
||||
.me()
|
||||
.then(applyCurrentUser)
|
||||
.catch(function () {});
|
||||
}
|
||||
|
||||
if (window.HyAppParams && window.HyAppParams.loadUser) {
|
||||
return userPromise
|
||||
@ -179,7 +215,8 @@
|
||||
})
|
||||
.then(function (current) {
|
||||
if (current && current.user) applyCurrentUser(current.user);
|
||||
});
|
||||
})
|
||||
.then(loadMeProfile);
|
||||
}
|
||||
if (userAPI) {
|
||||
if (userAPI.overview) {
|
||||
@ -187,17 +224,14 @@
|
||||
.then(function () {
|
||||
return userAPI.overview();
|
||||
})
|
||||
.then(applyCurrentUser);
|
||||
.then(applyCurrentUser)
|
||||
.then(loadMeProfile);
|
||||
}
|
||||
if (userAPI.me) {
|
||||
return userPromise
|
||||
.then(function () {
|
||||
return userAPI.me();
|
||||
})
|
||||
.then(applyCurrentUser);
|
||||
return userPromise.then(loadMeProfile);
|
||||
}
|
||||
}
|
||||
return userPromise;
|
||||
return userPromise.then(loadMeProfile);
|
||||
}
|
||||
|
||||
function toast(message) {
|
||||
@ -583,6 +617,20 @@
|
||||
state.inviteRewardStatus = normalizeInviteRewardStatus(status);
|
||||
var current = state.inviteRewardStatus || {};
|
||||
var progress = field(current, 'progress', 'progress') || {};
|
||||
var perInviteReward = numberValue(
|
||||
field(
|
||||
current,
|
||||
'per_invite_inviter_reward_coin_amount',
|
||||
'perInviteInviterRewardCoinAmount'
|
||||
)
|
||||
);
|
||||
|
||||
if (perInviteReward > 0) {
|
||||
setText(
|
||||
'#rewardInviteAmount',
|
||||
'+' + formatNumber(perInviteReward) + '(Max40,000)'
|
||||
);
|
||||
}
|
||||
|
||||
if (state.inviteRewardStatus) {
|
||||
setText(
|
||||
@ -766,6 +814,247 @@
|
||||
copyTextFrom('#inviteCode');
|
||||
}
|
||||
|
||||
function firstObjectValue(source, keys) {
|
||||
source = source || {};
|
||||
for (var i = 0; i < keys.length; i += 1) {
|
||||
var value = source[keys[i]];
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function openBindModal() {
|
||||
var api = window.HyAppAPI || {};
|
||||
if (!api.getAccessToken || !api.getAccessToken()) {
|
||||
toast(t('invite.loginRequired', 'Please log in first'));
|
||||
return;
|
||||
}
|
||||
state.pendingInviteCode = '';
|
||||
state.searchedInviter = null;
|
||||
state.searchingInviter = false;
|
||||
state.bindingInviter = false;
|
||||
var input = $('#bindInviteInput');
|
||||
if (input) input.value = '';
|
||||
showBindInput();
|
||||
$('#bindInviteModal').hidden = false;
|
||||
window.setTimeout(function () {
|
||||
if (input) input.focus();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function closeBindModal() {
|
||||
$('#bindInviteModal').hidden = true;
|
||||
state.searchingInviter = false;
|
||||
state.bindingInviter = false;
|
||||
renderBindActions();
|
||||
}
|
||||
|
||||
function showBindInput() {
|
||||
$('#bindInputCard').hidden = false;
|
||||
$('#bindResultCard').hidden = true;
|
||||
state.searchedInviter = null;
|
||||
renderBindActions();
|
||||
}
|
||||
|
||||
function showBindResult(inviter) {
|
||||
var avatar = $('#inviterAvatar');
|
||||
var name = $('#inviterName');
|
||||
var displayID = $('#inviterDisplayId');
|
||||
if (avatar) {
|
||||
avatar.src = inviter.avatar || './assets/rank-avatar.png';
|
||||
avatar.onerror = function () {
|
||||
avatar.onerror = null;
|
||||
avatar.src = './assets/rank-avatar.png';
|
||||
};
|
||||
}
|
||||
if (name) name.textContent = inviter.name || '--';
|
||||
if (displayID) displayID.textContent = inviter.displayUserID || '--';
|
||||
$('#bindInputCard').hidden = true;
|
||||
$('#bindResultCard').hidden = false;
|
||||
renderBindActions();
|
||||
}
|
||||
|
||||
function renderBindActions() {
|
||||
var cancel = $('#bindCancelButton');
|
||||
var confirm = $('#confirmBindButton');
|
||||
var input = $('#bindInviteInput');
|
||||
var busy = state.searchingInviter || state.bindingInviter;
|
||||
if (confirm) {
|
||||
confirm.disabled = busy;
|
||||
confirm.textContent = state.bindingInviter
|
||||
? t('invite.binding', 'Binding...')
|
||||
: state.searchingInviter
|
||||
? t('invite.searchingInviter', 'Searching...')
|
||||
: t('invite.confirm', 'Confirm');
|
||||
}
|
||||
if (cancel) cancel.disabled = busy;
|
||||
if (input) input.disabled = busy;
|
||||
}
|
||||
|
||||
function normalizeInviter(payload, fallbackDisplayUserID) {
|
||||
payload = payload || {};
|
||||
var wrapper = payload.inviter || payload.Inviter || payload;
|
||||
var identity = payload.identity || payload.Identity || payload;
|
||||
var profile =
|
||||
payload.profile ||
|
||||
payload.Profile ||
|
||||
wrapper.profile ||
|
||||
wrapper.Profile ||
|
||||
wrapper;
|
||||
var userID =
|
||||
textValue(firstObjectValue(profile, ['user_id', 'userId'])) ||
|
||||
textValue(firstObjectValue(identity, ['user_id', 'userId']));
|
||||
var displayUserID =
|
||||
textValue(
|
||||
firstObjectValue(profile, [
|
||||
'pretty_display_user_id',
|
||||
'prettyDisplayUserId',
|
||||
'display_user_id',
|
||||
'displayUserId',
|
||||
])
|
||||
) ||
|
||||
textValue(
|
||||
firstObjectValue(identity, [
|
||||
'pretty_display_user_id',
|
||||
'prettyDisplayUserId',
|
||||
'display_user_id',
|
||||
'displayUserId',
|
||||
])
|
||||
) ||
|
||||
fallbackDisplayUserID;
|
||||
var name =
|
||||
textValue(
|
||||
firstObjectValue(profile, ['username', 'nickname', 'name'])
|
||||
) || displayUserID;
|
||||
var avatar = textValue(
|
||||
firstObjectValue(profile, ['avatar', 'avatar_url', 'avatarUrl'])
|
||||
);
|
||||
if (!userID && !displayUserID) return null;
|
||||
return {
|
||||
userID: userID,
|
||||
displayUserID: displayUserID,
|
||||
name: name,
|
||||
avatar: avatar,
|
||||
};
|
||||
}
|
||||
|
||||
function isCurrentUser(inviter) {
|
||||
var current = state.currentUser || {};
|
||||
var currentUserID = textValue(
|
||||
firstObjectValue(current, ['user_id', 'userId'])
|
||||
);
|
||||
var currentDisplayID = textValue(
|
||||
firstObjectValue(current, [
|
||||
'pretty_display_user_id',
|
||||
'prettyDisplayUserId',
|
||||
'display_user_id',
|
||||
'displayUserId',
|
||||
])
|
||||
);
|
||||
return Boolean(
|
||||
(currentUserID && currentUserID === inviter.userID) ||
|
||||
(currentDisplayID && currentDisplayID === inviter.displayUserID)
|
||||
);
|
||||
}
|
||||
|
||||
function searchInviter() {
|
||||
if (state.searchingInviter) return;
|
||||
var input = $('#bindInviteInput');
|
||||
var inviteCode = normalizeInviteCodeInput(input && input.value);
|
||||
var api = window.HyAppAPI && window.HyAppAPI.user;
|
||||
if (input && input.value !== inviteCode) input.value = inviteCode;
|
||||
if (!inviteCode) {
|
||||
toast(
|
||||
t('invite.searchRequired', 'Please enter an invitation code')
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!api || !api.searchInviteReferrer) {
|
||||
toast(t('invite.bindFailed', 'Bind failed'));
|
||||
return;
|
||||
}
|
||||
state.searchingInviter = true;
|
||||
state.pendingInviteCode = inviteCode;
|
||||
renderBindActions();
|
||||
// 搜索入口只提交邀请码,由 server 解析归属并按当前用户国家过滤,前端不再用可被篡改的用户 ID 作为绑定入参。
|
||||
api.searchInviteReferrer(inviteCode)
|
||||
.then(function (payload) {
|
||||
var inviter = normalizeInviter(payload, '');
|
||||
state.searchingInviter = false;
|
||||
if (!inviter) {
|
||||
renderBindActions();
|
||||
toast(t('invite.inviterNotFound', 'Inviter not found'));
|
||||
return;
|
||||
}
|
||||
if (isCurrentUser(inviter)) {
|
||||
renderBindActions();
|
||||
toast(
|
||||
t(
|
||||
'invite.cannotBindSelf',
|
||||
'You cannot bind yourself as inviter'
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
inviter.inviteCode = inviteCode;
|
||||
state.searchedInviter = inviter;
|
||||
showBindResult(inviter);
|
||||
})
|
||||
.catch(function (error) {
|
||||
state.searchingInviter = false;
|
||||
renderBindActions();
|
||||
toast(
|
||||
(error && error.message) ||
|
||||
t('invite.inviterNotFound', 'Inviter not found')
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function confirmBindInviter() {
|
||||
if (state.bindingInviter) return;
|
||||
var api = window.HyAppAPI && window.HyAppAPI.user;
|
||||
var inviter = state.searchedInviter;
|
||||
if (!inviter) {
|
||||
searchInviter();
|
||||
return;
|
||||
}
|
||||
if (!api || !api.bindInviteReferrer) {
|
||||
toast(t('invite.bindFailed', 'Bind failed'));
|
||||
return;
|
||||
}
|
||||
state.bindingInviter = true;
|
||||
renderBindActions();
|
||||
api.bindInviteReferrer(inviter.inviteCode || state.pendingInviteCode)
|
||||
.then(function (response) {
|
||||
var invite = response && response.invite;
|
||||
state.bindingInviter = false;
|
||||
renderBindActions();
|
||||
if (invite && (invite.bound || invite.invite_code)) {
|
||||
toast(t('invite.bindSuccess', 'Bound successfully'));
|
||||
closeBindModal();
|
||||
loadCurrentUser().catch(function () {});
|
||||
loadInviteActivityReward();
|
||||
return;
|
||||
}
|
||||
toast(
|
||||
t(
|
||||
'invite.bindNoChange',
|
||||
'Invite referrer is already bound.'
|
||||
)
|
||||
);
|
||||
})
|
||||
.catch(function (error) {
|
||||
state.bindingInviter = false;
|
||||
renderBindActions();
|
||||
toast(
|
||||
(error && error.message) ||
|
||||
t('invite.bindFailed', 'Bind failed')
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function bindEvents() {
|
||||
document.querySelectorAll('.task-tab').forEach(function (button) {
|
||||
button.addEventListener('click', function () {
|
||||
@ -774,6 +1063,20 @@
|
||||
});
|
||||
$('#copyLinkButton').addEventListener('click', copyInviteLink);
|
||||
$('#copyCodeButton').addEventListener('click', copyInviteCode);
|
||||
$('#bindInviteButton').addEventListener('click', openBindModal);
|
||||
$('#bindCancelButton').addEventListener('click', closeBindModal);
|
||||
$('#confirmBindButton').addEventListener('click', confirmBindInviter);
|
||||
$('#bindInviteModal').addEventListener('click', function (event) {
|
||||
if (event.target === $('#bindInviteModal')) closeBindModal();
|
||||
});
|
||||
$('#bindInviteInput').addEventListener('keydown', function (event) {
|
||||
if (event.key === 'Enter') confirmBindInviter();
|
||||
});
|
||||
$('#bindInviteInput').addEventListener('input', function (event) {
|
||||
var nextValue = normalizeInviteCodeInput(event.target.value);
|
||||
if (event.target.value !== nextValue)
|
||||
event.target.value = nextValue;
|
||||
});
|
||||
document
|
||||
.querySelectorAll('.copy-task-button')
|
||||
.forEach(function (button) {
|
||||
@ -798,6 +1101,7 @@
|
||||
|
||||
window.addEventListener('hyapp:i18n-ready', function () {
|
||||
renderRank();
|
||||
renderBindActions();
|
||||
renderInviteActivityReward(state.inviteRewardStatus);
|
||||
});
|
||||
|
||||
|
||||
@ -171,18 +171,8 @@ button {
|
||||
width: calc(1016 * var(--u));
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
background-image:
|
||||
url('./assets/panel-top-a.png'), url('./assets/panel-bottom-a.png'),
|
||||
url('./assets/panel-middle-a.png');
|
||||
background-repeat: no-repeat, no-repeat, no-repeat;
|
||||
background-position:
|
||||
top center,
|
||||
bottom center,
|
||||
center center;
|
||||
background-size:
|
||||
100% auto,
|
||||
100% auto,
|
||||
100% 100%;
|
||||
background-position: center;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.ornate-panel > * {
|
||||
@ -211,9 +201,9 @@ p {
|
||||
}
|
||||
|
||||
.reward-panel {
|
||||
height: calc(790 * var(--u));
|
||||
height: calc(770 * var(--u));
|
||||
margin-top: calc(20 * var(--u));
|
||||
padding-top: calc(122 * var(--u));
|
||||
padding-top: calc(104 * var(--u));
|
||||
background-image: url('./assets/reward-panel-bg.png');
|
||||
background-position: center;
|
||||
background-size: 100% 100%;
|
||||
@ -232,73 +222,75 @@ p {
|
||||
.reward-grid {
|
||||
position: relative;
|
||||
width: calc(1016 * var(--u));
|
||||
height: calc(486 * var(--u));
|
||||
margin: calc(28 * var(--u)) auto 0;
|
||||
height: calc(450 * var(--u));
|
||||
margin: calc(34 * var(--u)) auto 0;
|
||||
}
|
||||
|
||||
.reward-item {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: calc(486 * var(--u));
|
||||
height: calc(486 * var(--u));
|
||||
color: var(--gold);
|
||||
width: calc(420 * var(--u));
|
||||
height: calc(450 * var(--u));
|
||||
color: #ffd133;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.reward-item:first-child {
|
||||
left: calc(8 * var(--u));
|
||||
.reward-item-success {
|
||||
left: calc(54 * var(--u));
|
||||
}
|
||||
|
||||
.reward-item:last-child {
|
||||
left: calc(522 * var(--u));
|
||||
.reward-item-topup {
|
||||
left: calc(560 * var(--u));
|
||||
}
|
||||
|
||||
.reward-orb {
|
||||
.reward-visual {
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
display: block;
|
||||
inset: 0;
|
||||
width: calc(486 * var(--u));
|
||||
height: calc(486 * var(--u));
|
||||
left: 50%;
|
||||
top: 0;
|
||||
width: calc(370 * var(--u));
|
||||
max-width: none;
|
||||
transform: translateX(-50%);
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.reward-gold {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: calc(178 * var(--u));
|
||||
transform: translate(-50%, -50%);
|
||||
.reward-item-topup .reward-visual {
|
||||
width: calc(382 * var(--u));
|
||||
}
|
||||
|
||||
.reward-item strong {
|
||||
position: absolute;
|
||||
top: calc(98 * var(--u));
|
||||
left: calc(290 * var(--u));
|
||||
font-size: calc(40 * var(--u));
|
||||
top: calc(338 * var(--u));
|
||||
left: 50%;
|
||||
display: block;
|
||||
width: calc(520 * var(--u));
|
||||
transform: translateX(-50%);
|
||||
font-size: calc(42 * var(--u));
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.reward-item span {
|
||||
position: absolute;
|
||||
top: calc(421 * var(--u));
|
||||
top: calc(404 * var(--u));
|
||||
left: 50%;
|
||||
display: block;
|
||||
width: calc(360 * var(--u));
|
||||
width: calc(430 * var(--u));
|
||||
transform: translateX(-50%);
|
||||
color: var(--gold);
|
||||
font-size: calc(30 * var(--u));
|
||||
color: var(--white);
|
||||
font-size: calc(34 * var(--u));
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.plus {
|
||||
position: absolute;
|
||||
top: calc(207 * var(--u));
|
||||
top: calc(142 * var(--u));
|
||||
left: calc(472 * var(--u));
|
||||
display: block;
|
||||
width: calc(71 * var(--u));
|
||||
height: calc(71 * var(--u));
|
||||
width: calc(78 * var(--u));
|
||||
height: calc(78 * var(--u));
|
||||
}
|
||||
|
||||
.invite-copy {
|
||||
@ -319,25 +311,35 @@ p {
|
||||
|
||||
.invite-fields {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) calc(286 * var(--u));
|
||||
gap: calc(24 * var(--u));
|
||||
width: calc(760 * var(--u));
|
||||
gap: calc(34 * var(--u));
|
||||
width: calc(1016 * var(--u));
|
||||
margin: calc(58 * var(--u)) auto 0;
|
||||
}
|
||||
|
||||
.invite-field {
|
||||
position: relative;
|
||||
height: calc(93 * var(--u));
|
||||
background: url('./assets/link-input.svg') center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.link-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
justify-content: flex-start;
|
||||
min-width: 0;
|
||||
height: calc(85 * var(--u));
|
||||
padding: 0 calc(28 * var(--u));
|
||||
height: 100%;
|
||||
padding: 0 calc(112 * var(--u)) 0 calc(52 * var(--u));
|
||||
overflow: hidden;
|
||||
color: var(--gold);
|
||||
font-size: calc(30 * var(--u));
|
||||
font-weight: 700;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
background: url('./assets/link-input.svg') center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.invite-field.is-code .link-box {
|
||||
justify-content: center;
|
||||
padding-left: calc(112 * var(--u));
|
||||
}
|
||||
|
||||
.invite-code {
|
||||
@ -345,13 +347,20 @@ p {
|
||||
letter-spacing: calc(1 * var(--u));
|
||||
}
|
||||
|
||||
.invite-actions {
|
||||
display: flex;
|
||||
width: calc(764 * var(--u));
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: calc(24 * var(--u));
|
||||
margin: calc(50 * var(--u)) auto 0;
|
||||
.copy-icon-button {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: calc(42 * var(--u));
|
||||
width: calc(52 * var(--u));
|
||||
height: calc(52 * var(--u));
|
||||
cursor: pointer;
|
||||
transform: translateY(-50%);
|
||||
background: url('./assets/generated/copy-icon.png') center / 100% 100%
|
||||
no-repeat;
|
||||
}
|
||||
|
||||
.copy-icon-button:active {
|
||||
transform: translateY(-50%) scale(0.96);
|
||||
}
|
||||
|
||||
.ornate-button {
|
||||
@ -374,19 +383,8 @@ p {
|
||||
transform: translateY(calc(2 * var(--u)));
|
||||
}
|
||||
|
||||
.invite-actions .ornate-button {
|
||||
flex: 0 0 calc(520 * var(--u));
|
||||
width: calc(520 * var(--u));
|
||||
height: calc(100 * var(--u));
|
||||
font-size: calc(42 * var(--u));
|
||||
}
|
||||
|
||||
.invite-actions .small-copy-button {
|
||||
flex: 0 0 calc(220 * var(--u));
|
||||
width: calc(220 * var(--u));
|
||||
height: calc(78 * var(--u));
|
||||
font-size: calc(30 * var(--u));
|
||||
background-image: url('./assets/claim-active.png');
|
||||
.bind-invite-button {
|
||||
margin-top: calc(68 * var(--u));
|
||||
}
|
||||
|
||||
.stats-panel {
|
||||
@ -397,6 +395,7 @@ p {
|
||||
height: calc(520 * var(--u));
|
||||
margin-top: calc(62 * var(--u));
|
||||
padding: calc(108 * var(--u)) calc(92 * var(--u)) calc(92 * var(--u));
|
||||
background-image: url('./assets/generated/panel-a-stats-bg.png');
|
||||
}
|
||||
|
||||
.stat {
|
||||
@ -428,10 +427,12 @@ p {
|
||||
margin-top: calc(34 * var(--u));
|
||||
margin-bottom: calc(32 * var(--u));
|
||||
padding: calc(126 * var(--u)) calc(78 * var(--u)) calc(70 * var(--u));
|
||||
background-image: url('./assets/generated/panel-a-monthly-bg.png');
|
||||
}
|
||||
|
||||
.monthly-panel.is-quota {
|
||||
min-height: calc(1375 * var(--u));
|
||||
background-image: url('./assets/generated/panel-a-monthly-quota-bg.png');
|
||||
}
|
||||
|
||||
.monthly-panel h2,
|
||||
@ -610,9 +611,7 @@ p {
|
||||
margin-top: calc(42 * var(--u));
|
||||
margin-bottom: calc(28 * var(--u));
|
||||
padding: calc(126 * var(--u)) calc(68 * var(--u)) calc(72 * var(--u));
|
||||
background-image:
|
||||
url('./assets/panel-top-b.png'), url('./assets/panel-bottom-b.png'),
|
||||
url('./assets/panel-middle-b.png');
|
||||
background-image: url('./assets/generated/panel-b-rank-bg.png');
|
||||
}
|
||||
|
||||
.rank-list {
|
||||
@ -687,6 +686,156 @@ p {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.invite-modal {
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: calc(28 * var(--u));
|
||||
background: rgba(0, 0, 0, 0.68);
|
||||
}
|
||||
|
||||
.bind-card {
|
||||
position: relative;
|
||||
width: min(calc(1016 * var(--u)), calc(100vw - 24px));
|
||||
min-height: calc(786 * var(--u));
|
||||
padding: calc(104 * var(--u)) calc(90 * var(--u)) calc(78 * var(--u));
|
||||
overflow: hidden;
|
||||
background: url('./assets/generated/modal-bg.png') center / 100% 100%
|
||||
no-repeat;
|
||||
}
|
||||
|
||||
.bind-card > * {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.bind-card h2 {
|
||||
color: var(--gold);
|
||||
font-size: calc(60 * var(--u));
|
||||
line-height: 1;
|
||||
font-weight: 800;
|
||||
text-align: center;
|
||||
text-shadow: 0 calc(2 * var(--u)) calc(4 * var(--u)) rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
.bind-input-state,
|
||||
.bind-result-state {
|
||||
width: calc(827 * var(--u));
|
||||
max-width: 100%;
|
||||
margin: calc(70 * var(--u)) auto 0;
|
||||
}
|
||||
|
||||
.bind-input-shell {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: calc(93 * var(--u));
|
||||
background: url('./assets/generated/invite-input-bg.png') center / 100% 100%
|
||||
no-repeat;
|
||||
}
|
||||
|
||||
.bind-input-shell input {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 calc(124 * var(--u)) 0 calc(36 * var(--u));
|
||||
border: 0;
|
||||
outline: 0;
|
||||
color: var(--gold);
|
||||
font:
|
||||
800 calc(30 * var(--u)) / 1 'Source Han Sans SC',
|
||||
'Noto Sans',
|
||||
'Helvetica Neue',
|
||||
Arial,
|
||||
sans-serif;
|
||||
text-align: left;
|
||||
background: url('./assets/generated/search-icon.png') right
|
||||
calc(44 * var(--u)) center / calc(52 * var(--u)) calc(49 * var(--u))
|
||||
no-repeat;
|
||||
}
|
||||
|
||||
.bind-input-shell input::placeholder {
|
||||
color: rgba(246, 224, 178, 0.55);
|
||||
}
|
||||
|
||||
.inviter-card {
|
||||
display: grid;
|
||||
grid-template-columns: calc(122 * var(--u)) minmax(0, 1fr);
|
||||
align-items: center;
|
||||
gap: calc(28 * var(--u));
|
||||
height: calc(152 * var(--u));
|
||||
padding: 0 calc(42 * var(--u));
|
||||
background: url('./assets/generated/inviter-card-bg.png') center / 100% 100%
|
||||
no-repeat;
|
||||
}
|
||||
|
||||
.inviter-card img {
|
||||
width: calc(104 * var(--u));
|
||||
height: calc(104 * var(--u));
|
||||
border: calc(2 * var(--u)) solid #ffebbb;
|
||||
border-radius: 999px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.inviter-card strong,
|
||||
.inviter-card span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.inviter-card strong {
|
||||
color: var(--white);
|
||||
font-size: calc(36 * var(--u));
|
||||
line-height: 1.1;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.inviter-card span {
|
||||
margin-top: calc(14 * var(--u));
|
||||
color: var(--gold);
|
||||
font-size: calc(28 * var(--u));
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.bind-actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, calc(441 * var(--u)));
|
||||
justify-content: center;
|
||||
gap: calc(38 * var(--u));
|
||||
margin-top: calc(152 * var(--u));
|
||||
}
|
||||
|
||||
.bind-action-button {
|
||||
width: 100%;
|
||||
height: calc(120 * var(--u));
|
||||
color: #6f2d12;
|
||||
font-size: calc(34 * var(--u));
|
||||
line-height: 1;
|
||||
font-weight: 900;
|
||||
text-align: center;
|
||||
text-shadow: 0 calc(1 * var(--u)) calc(1 * var(--u))
|
||||
rgba(255, 255, 255, 0.45);
|
||||
background: url('./assets/generated/modal-button-active.png') center / 100%
|
||||
100% no-repeat;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bind-cancel-button {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
text-shadow: 0 calc(2 * var(--u)) calc(2 * var(--u)) rgba(0, 0, 0, 0.28);
|
||||
background-image: url('./assets/generated/modal-button-inactive.png');
|
||||
}
|
||||
|
||||
.bind-action-button:disabled {
|
||||
cursor: default;
|
||||
filter: grayscale(0.25) brightness(0.86);
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@ -541,6 +541,12 @@ var default_api = 'https://api.global-interaction.com/';
|
||||
body: payload || {},
|
||||
});
|
||||
},
|
||||
completeOnboarding: function (payload) {
|
||||
return request('/api/v1/users/me/onboarding/complete', {
|
||||
method: 'POST',
|
||||
body: payload || {},
|
||||
});
|
||||
},
|
||||
resolveDisplayUserID: function (displayUserID) {
|
||||
return request(
|
||||
'/api/v1/users/by-display-user-id/' +
|
||||
@ -550,6 +556,18 @@ var default_api = 'https://api.global-interaction.com/';
|
||||
}
|
||||
);
|
||||
},
|
||||
searchInviteReferrer: function (inviteCode) {
|
||||
return request('/api/v1/users/me/invite-referrer/search', {
|
||||
method: 'GET',
|
||||
query: { invite_code: inviteCode || '' },
|
||||
});
|
||||
},
|
||||
bindInviteReferrer: function (inviteCode) {
|
||||
return request('/api/v1/users/me/invite-referrer/bind', {
|
||||
method: 'POST',
|
||||
body: { invite_code: String(inviteCode || '') },
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
var walletAPI = {
|
||||
|
||||
@ -133,6 +133,32 @@
|
||||
"invite.noRankData": "لا توجد بيانات ترتيب",
|
||||
"invite.copied": "تم النسخ",
|
||||
"invite.copyFailed": "فشل النسخ",
|
||||
"invite.successfulInvite": "دعوة ناجحة",
|
||||
"invite.friendTopUp": "شحن الصديق",
|
||||
"invite.copyInviteLink": "نسخ رابط الدعوة",
|
||||
"invite.copyInviteCode": "نسخ رمز الدعوة",
|
||||
"invite.linkInviter": "ربط الداعي",
|
||||
"invite.bindInviteTitle": "ربط الداعي",
|
||||
"invite.bindInviteHint": "أدخل رمز الدعوة ثم أكد الداعي قبل الربط.",
|
||||
"invite.bindInvitePlaceholder": "أدخل رمز الدعوة",
|
||||
"invite.searchInviter": "بحث",
|
||||
"invite.searchingInviter": "جار البحث...",
|
||||
"invite.inviterFoundTitle": "تأكيد الداعي",
|
||||
"invite.bindInviteConfirmHint": "يرجى التحقق من معلومات الداعي قبل الربط.",
|
||||
"invite.confirmBind": "ربط",
|
||||
"invite.cancel": "إلغاء",
|
||||
"invite.confirm": "تأكيد",
|
||||
"invite.binding": "جار الربط...",
|
||||
"invite.back": "رجوع",
|
||||
"invite.close": "إغلاق",
|
||||
"invite.inviterNotFound": "لم يتم العثور على الداعي",
|
||||
"invite.loginRequired": "يرجى تسجيل الدخول أولا",
|
||||
"invite.searchRequired": "أدخل رمز الدعوة",
|
||||
"invite.cannotBindSelf": "لا يمكنك ربط نفسك كداع",
|
||||
"invite.bindProfileRequired": "لا يمكن ربط هذا الحساب هنا.",
|
||||
"invite.bindSuccess": "تم الربط بنجاح",
|
||||
"invite.bindNoChange": "تم ربط الداعي بهذا الحساب بالفعل.",
|
||||
"invite.bindFailed": "فشل الربط",
|
||||
"host_center.title": "مركز المضيف",
|
||||
"host_center.back": "رجوع",
|
||||
"host_center.change_language": "تغيير اللغة",
|
||||
|
||||
@ -133,6 +133,32 @@
|
||||
"invite.noRankData": "No rank data",
|
||||
"invite.copied": "Copied",
|
||||
"invite.copyFailed": "Copy failed",
|
||||
"invite.successfulInvite": "Successful Invite",
|
||||
"invite.friendTopUp": "Friend's Top-Up",
|
||||
"invite.copyInviteLink": "Copy invitation link",
|
||||
"invite.copyInviteCode": "Copy invitation code",
|
||||
"invite.linkInviter": "Link Inviter",
|
||||
"invite.bindInviteTitle": "Bind Referrer",
|
||||
"invite.bindInviteHint": "Enter an invitation code and confirm the referrer before binding.",
|
||||
"invite.bindInvitePlaceholder": "Enter Invitation Code",
|
||||
"invite.searchInviter": "Search",
|
||||
"invite.searchingInviter": "Searching...",
|
||||
"invite.inviterFoundTitle": "Confirm inviter",
|
||||
"invite.bindInviteConfirmHint": "Please check the inviter information before binding.",
|
||||
"invite.confirmBind": "Bind",
|
||||
"invite.cancel": "Cancel",
|
||||
"invite.confirm": "Confirm",
|
||||
"invite.binding": "Binding...",
|
||||
"invite.back": "Back",
|
||||
"invite.close": "Close",
|
||||
"invite.inviterNotFound": "Inviter not found",
|
||||
"invite.loginRequired": "Please log in first",
|
||||
"invite.searchRequired": "Please enter an invitation code",
|
||||
"invite.cannotBindSelf": "You cannot bind yourself as inviter",
|
||||
"invite.bindProfileRequired": "Current account cannot bind here.",
|
||||
"invite.bindSuccess": "Bound successfully",
|
||||
"invite.bindNoChange": "Invite referrer is already bound.",
|
||||
"invite.bindFailed": "Bind failed",
|
||||
"host_center.title": "Host Center",
|
||||
"host_center.back": "Back",
|
||||
"host_center.change_language": "Change language",
|
||||
|
||||
@ -133,6 +133,32 @@
|
||||
"invite.noRankData": "No hay datos de ranking",
|
||||
"invite.copied": "Copiado",
|
||||
"invite.copyFailed": "Error al copiar",
|
||||
"invite.successfulInvite": "Invitación exitosa",
|
||||
"invite.friendTopUp": "Recarga del amigo",
|
||||
"invite.copyInviteLink": "Copiar enlace de invitación",
|
||||
"invite.copyInviteCode": "Copiar código de invitación",
|
||||
"invite.linkInviter": "Vincular invitador",
|
||||
"invite.bindInviteTitle": "Vincular invitador",
|
||||
"invite.bindInviteHint": "Ingresa el código de invitación y confirma el invitador antes de vincular.",
|
||||
"invite.bindInvitePlaceholder": "Ingresa el código de invitación",
|
||||
"invite.searchInviter": "Buscar",
|
||||
"invite.searchingInviter": "Buscando...",
|
||||
"invite.inviterFoundTitle": "Confirmar invitador",
|
||||
"invite.bindInviteConfirmHint": "Verifica la información del invitador antes de vincular.",
|
||||
"invite.confirmBind": "Vincular",
|
||||
"invite.cancel": "Cancelar",
|
||||
"invite.confirm": "Confirmar",
|
||||
"invite.binding": "Vinculando...",
|
||||
"invite.back": "Volver",
|
||||
"invite.close": "Cerrar",
|
||||
"invite.inviterNotFound": "Invitador no encontrado",
|
||||
"invite.loginRequired": "Inicia sesión primero",
|
||||
"invite.searchRequired": "Ingresa un código de invitación",
|
||||
"invite.cannotBindSelf": "No puedes vincularte como invitador",
|
||||
"invite.bindProfileRequired": "Esta cuenta no puede vincular aquí.",
|
||||
"invite.bindSuccess": "Vinculado correctamente",
|
||||
"invite.bindNoChange": "Esta cuenta ya tiene un invitador vinculado.",
|
||||
"invite.bindFailed": "Error al vincular",
|
||||
"host_center.title": "Centro de anfitrión",
|
||||
"host_center.back": "Volver",
|
||||
"host_center.change_language": "Cambiar idioma",
|
||||
|
||||
@ -100,6 +100,32 @@
|
||||
"invite.noRankData": "Belum ada data peringkat",
|
||||
"invite.copied": "Disalin",
|
||||
"invite.copyFailed": "Gagal menyalin",
|
||||
"invite.successfulInvite": "Undangan Berhasil",
|
||||
"invite.friendTopUp": "Top up teman",
|
||||
"invite.copyInviteLink": "Salin tautan undangan",
|
||||
"invite.copyInviteCode": "Salin kode undangan",
|
||||
"invite.linkInviter": "Tautkan pengundang",
|
||||
"invite.bindInviteTitle": "Tautkan pengundang",
|
||||
"invite.bindInviteHint": "Masukkan kode undangan, lalu konfirmasi pengundang sebelum menautkan.",
|
||||
"invite.bindInvitePlaceholder": "Masukkan kode undangan",
|
||||
"invite.searchInviter": "Cari",
|
||||
"invite.searchingInviter": "Mencari...",
|
||||
"invite.inviterFoundTitle": "Konfirmasi pengundang",
|
||||
"invite.bindInviteConfirmHint": "Periksa informasi pengundang sebelum menautkan.",
|
||||
"invite.confirmBind": "Tautkan",
|
||||
"invite.cancel": "Batal",
|
||||
"invite.confirm": "Konfirmasi",
|
||||
"invite.binding": "Menautkan...",
|
||||
"invite.back": "Kembali",
|
||||
"invite.close": "Tutup",
|
||||
"invite.inviterNotFound": "Pengundang tidak ditemukan",
|
||||
"invite.loginRequired": "Silakan masuk terlebih dahulu",
|
||||
"invite.searchRequired": "Masukkan kode undangan",
|
||||
"invite.cannotBindSelf": "Kamu tidak bisa menautkan dirimu sebagai pengundang",
|
||||
"invite.bindProfileRequired": "Akun ini tidak dapat ditautkan di sini.",
|
||||
"invite.bindSuccess": "Berhasil ditautkan",
|
||||
"invite.bindNoChange": "Akun ini sudah memiliki pengundang.",
|
||||
"invite.bindFailed": "Gagal menautkan",
|
||||
"host_center.title": "Pusat Host",
|
||||
"host_center.back": "Kembali",
|
||||
"host_center.change_language": "Ganti bahasa",
|
||||
|
||||
@ -100,6 +100,32 @@
|
||||
"invite.noRankData": "Sıralama verisi yok",
|
||||
"invite.copied": "Kopyalandı",
|
||||
"invite.copyFailed": "Kopyalama başarısız",
|
||||
"invite.successfulInvite": "Başarılı Davet",
|
||||
"invite.friendTopUp": "Arkadaş yüklemesi",
|
||||
"invite.copyInviteLink": "Davet bağlantısını kopyala",
|
||||
"invite.copyInviteCode": "Davet kodunu kopyala",
|
||||
"invite.linkInviter": "Davetçiyi bağla",
|
||||
"invite.bindInviteTitle": "Davetçiyi bağla",
|
||||
"invite.bindInviteHint": "Davet kodunu gir ve bağlamadan önce davetçiyi onayla.",
|
||||
"invite.bindInvitePlaceholder": "Davet kodu gir",
|
||||
"invite.searchInviter": "Ara",
|
||||
"invite.searchingInviter": "Aranıyor...",
|
||||
"invite.inviterFoundTitle": "Davetçiyi onayla",
|
||||
"invite.bindInviteConfirmHint": "Bağlamadan önce davetçi bilgisini kontrol et.",
|
||||
"invite.confirmBind": "Bağla",
|
||||
"invite.cancel": "İptal",
|
||||
"invite.confirm": "Onayla",
|
||||
"invite.binding": "Bağlanıyor...",
|
||||
"invite.back": "Geri",
|
||||
"invite.close": "Kapat",
|
||||
"invite.inviterNotFound": "Davetçi bulunamadı",
|
||||
"invite.loginRequired": "Önce giriş yap",
|
||||
"invite.searchRequired": "Davet kodu gir",
|
||||
"invite.cannotBindSelf": "Kendini davetçi olarak bağlayamazsın",
|
||||
"invite.bindProfileRequired": "Bu hesap burada bağlanamaz.",
|
||||
"invite.bindSuccess": "Başarıyla bağlandı",
|
||||
"invite.bindNoChange": "Bu hesap zaten bir davetçiye bağlı.",
|
||||
"invite.bindFailed": "Bağlama başarısız",
|
||||
"host_center.title": "Host Merkezi",
|
||||
"host_center.back": "Geri",
|
||||
"host_center.change_language": "Dili değiştir",
|
||||
|
||||
@ -100,6 +100,32 @@
|
||||
"invite.noRankData": "暂无排行榜数据",
|
||||
"invite.copied": "已复制",
|
||||
"invite.copyFailed": "复制失败",
|
||||
"invite.successfulInvite": "成功邀请",
|
||||
"invite.friendTopUp": "好友充值",
|
||||
"invite.copyInviteLink": "复制邀请链接",
|
||||
"invite.copyInviteCode": "复制邀请码",
|
||||
"invite.linkInviter": "绑定邀请人",
|
||||
"invite.bindInviteTitle": "绑定邀请人",
|
||||
"invite.bindInviteHint": "输入邀请码,确认邀请人后再绑定。",
|
||||
"invite.bindInvitePlaceholder": "输入邀请码",
|
||||
"invite.searchInviter": "搜索",
|
||||
"invite.searchingInviter": "搜索中...",
|
||||
"invite.inviterFoundTitle": "确认邀请人",
|
||||
"invite.bindInviteConfirmHint": "绑定前请确认邀请人信息。",
|
||||
"invite.confirmBind": "绑定",
|
||||
"invite.cancel": "取消",
|
||||
"invite.confirm": "确认",
|
||||
"invite.binding": "绑定中...",
|
||||
"invite.back": "返回",
|
||||
"invite.close": "关闭",
|
||||
"invite.inviterNotFound": "未找到邀请人",
|
||||
"invite.loginRequired": "请先登录",
|
||||
"invite.searchRequired": "请输入邀请码",
|
||||
"invite.cannotBindSelf": "不能绑定自己为邀请人",
|
||||
"invite.bindProfileRequired": "当前账号不能在这里绑定。",
|
||||
"invite.bindSuccess": "绑定成功",
|
||||
"invite.bindNoChange": "当前账号已绑定邀请人。",
|
||||
"invite.bindFailed": "绑定失败",
|
||||
"host_center.title": "主播中心",
|
||||
"host_center.back": "返回",
|
||||
"host_center.change_language": "切换语言",
|
||||
|
||||