修复邀请
This commit is contained in:
parent
b6d8e6900d
commit
224808a3e3
@ -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=20260629-bind-invite" />
|
||||
<link rel="stylesheet" href="./style.css?v=20260630-invite-layout" />
|
||||
</head>
|
||||
<body>
|
||||
<main
|
||||
@ -135,6 +135,7 @@
|
||||
class="ornate-button bind-invite-button"
|
||||
id="bindInviteButton"
|
||||
type="button"
|
||||
hidden
|
||||
data-i18n="invite.linkInviter"
|
||||
>
|
||||
Bind User
|
||||
@ -315,6 +316,6 @@
|
||||
<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=20260630-invite-code"></script>
|
||||
<script src="./script.js?v=20260630-bind-window"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
'ios_url',
|
||||
'url',
|
||||
];
|
||||
var BIND_INVITE_VISIBLE_WINDOW_MS = 48 * 60 * 60 * 1000;
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
var state = {
|
||||
inviteCode: firstParam(INVITE_CODE_KEYS),
|
||||
@ -27,6 +28,9 @@
|
||||
inviterAvatar: firstParam(SHARE_AVATAR_KEYS),
|
||||
inviteLink: '',
|
||||
currentUser: null,
|
||||
currentUserCreatedAtMS: 0,
|
||||
currentUserTimingLoaded: false,
|
||||
serverTimeMS: 0,
|
||||
pendingInviteCode: '',
|
||||
searchedInviter: null,
|
||||
inviteRewardStatus: null,
|
||||
@ -58,12 +62,17 @@
|
||||
return textValue(value).toUpperCase();
|
||||
}
|
||||
|
||||
function readPath(source, path) {
|
||||
function readRawPath(source, path) {
|
||||
var value = source;
|
||||
for (var i = 0; i < path.length; i += 1) {
|
||||
if (!value || typeof value !== 'object') return '';
|
||||
value = value[path[i]];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function readPath(source, path) {
|
||||
var value = readRawPath(source, path);
|
||||
return textValue(value);
|
||||
}
|
||||
|
||||
@ -75,6 +84,25 @@
|
||||
return '';
|
||||
}
|
||||
|
||||
function normalizeTimestampMS(value) {
|
||||
if (value === undefined || value === null || value === '') return 0;
|
||||
if (typeof value === 'string' && !String(value).trim()) return 0;
|
||||
var number = Number(value);
|
||||
if (Number.isFinite(number) && number > 0) {
|
||||
return number < 100000000000 ? number * 1000 : number;
|
||||
}
|
||||
var parsed = Date.parse(value);
|
||||
return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
|
||||
}
|
||||
|
||||
function firstTimestampMS(source, paths) {
|
||||
for (var i = 0; i < paths.length; i += 1) {
|
||||
var value = normalizeTimestampMS(readRawPath(source, paths[i]));
|
||||
if (value) return value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function currentUserPayload(data, profile) {
|
||||
var target = profile || data || {};
|
||||
return Boolean(
|
||||
@ -84,6 +112,8 @@
|
||||
target.displayUserId ||
|
||||
target.username ||
|
||||
target.nickname ||
|
||||
target.created_at_ms !== undefined ||
|
||||
target.createdAtMs !== undefined ||
|
||||
target.profile_completed !== undefined ||
|
||||
target.profileCompleted !== undefined
|
||||
);
|
||||
@ -137,10 +167,97 @@
|
||||
return payload && payload.user ? payload.user : payload;
|
||||
}
|
||||
|
||||
function applyCurrentUserTiming(data, profile) {
|
||||
var serverTimeMS = firstTimestampMS(data, [
|
||||
['server_time_ms'],
|
||||
['serverTimeMS'],
|
||||
['serverTimeMs'],
|
||||
['server_time'],
|
||||
['serverTime'],
|
||||
]);
|
||||
var createdAtMS = firstTimestampMS(data, [
|
||||
['profile', 'created_at_ms'],
|
||||
['profile', 'createdAtMs'],
|
||||
['profile', 'created_at'],
|
||||
['profile', 'createdAt'],
|
||||
['profile', 'registered_at_ms'],
|
||||
['profile', 'registeredAtMs'],
|
||||
['profile', 'registered_at'],
|
||||
['profile', 'registeredAt'],
|
||||
['created_at_ms'],
|
||||
['createdAtMs'],
|
||||
['created_at'],
|
||||
['createdAt'],
|
||||
['registered_at_ms'],
|
||||
['registeredAtMs'],
|
||||
['registered_at'],
|
||||
['registeredAt'],
|
||||
]);
|
||||
if (!createdAtMS) {
|
||||
createdAtMS = firstTimestampMS(profile, [
|
||||
['created_at_ms'],
|
||||
['createdAtMs'],
|
||||
['created_at'],
|
||||
['createdAt'],
|
||||
['registered_at_ms'],
|
||||
['registeredAtMs'],
|
||||
['registered_at'],
|
||||
['registeredAt'],
|
||||
]);
|
||||
}
|
||||
if (serverTimeMS) state.serverTimeMS = serverTimeMS;
|
||||
if (createdAtMS) state.currentUserCreatedAtMS = createdAtMS;
|
||||
}
|
||||
|
||||
function bindInviteReferenceTimeMS() {
|
||||
return state.serverTimeMS || Date.now();
|
||||
}
|
||||
|
||||
function canShowBindInviteButton() {
|
||||
var api = window.HyAppAPI || {};
|
||||
var hasToken = api.getAccessToken && api.getAccessToken();
|
||||
if (hasToken && !state.currentUserTimingLoaded) return false;
|
||||
var current = state.currentUser || {};
|
||||
var createdAtMS =
|
||||
state.currentUserCreatedAtMS ||
|
||||
firstTimestampMS(current, [
|
||||
['created_at_ms'],
|
||||
['createdAtMs'],
|
||||
['created_at'],
|
||||
['createdAt'],
|
||||
['registered_at_ms'],
|
||||
['registeredAtMs'],
|
||||
['registered_at'],
|
||||
['registeredAt'],
|
||||
]);
|
||||
if (!createdAtMS) return true;
|
||||
// 48 小时窗口必须用服务端返回的当前时间优先判断;接口缺少时间时才退回本机时间,避免用户手动改系统时间影响显隐。
|
||||
return (
|
||||
bindInviteReferenceTimeMS() - createdAtMS <=
|
||||
BIND_INVITE_VISIBLE_WINDOW_MS
|
||||
);
|
||||
}
|
||||
|
||||
function renderBindInviteVisibility() {
|
||||
var button = $('#bindInviteButton');
|
||||
if (!button) return;
|
||||
var visible = canShowBindInviteButton();
|
||||
button.hidden = !visible;
|
||||
button.disabled = !visible;
|
||||
if (visible || !$('#bindInviteModal') || $('#bindInviteModal').hidden) {
|
||||
return;
|
||||
}
|
||||
closeBindModal();
|
||||
}
|
||||
|
||||
function applyCurrentUser(payload) {
|
||||
var data = readOverviewPayload(payload || {});
|
||||
var profile = data.profile || data;
|
||||
if (currentUserPayload(data, profile)) mergeCurrentUser(profile);
|
||||
applyCurrentUserTiming(data, profile);
|
||||
if (currentUserPayload(data, profile)) {
|
||||
state.currentUserTimingLoaded = true;
|
||||
mergeCurrentUser(profile);
|
||||
}
|
||||
var inviteCode = firstPath(data, [
|
||||
['invite', 'my_invite_code'],
|
||||
['invite', 'myInviteCode'],
|
||||
@ -186,6 +303,7 @@
|
||||
$('#statEligible').textContent = validInviteCount;
|
||||
}
|
||||
renderInviteShare();
|
||||
renderBindInviteVisibility();
|
||||
}
|
||||
|
||||
function loadCurrentUser() {
|
||||
@ -826,6 +944,10 @@
|
||||
}
|
||||
|
||||
function openBindModal() {
|
||||
if (!canShowBindInviteButton()) {
|
||||
renderBindInviteVisibility();
|
||||
return;
|
||||
}
|
||||
var api = window.HyAppAPI || {};
|
||||
if (!api.getAccessToken || !api.getAccessToken()) {
|
||||
toast(t('invite.loginRequired', 'Please log in first'));
|
||||
@ -1089,6 +1211,7 @@
|
||||
renderRank();
|
||||
updateCountdown();
|
||||
setInterval(updateCountdown, 1000);
|
||||
renderBindInviteVisibility();
|
||||
bindEvents();
|
||||
renderInviteActivityReward(null);
|
||||
Promise.all([
|
||||
|
||||
@ -318,16 +318,20 @@ p {
|
||||
|
||||
.invite-field {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
height: calc(93 * var(--u));
|
||||
overflow: hidden;
|
||||
background: url('./assets/link-input.svg') center / 100% 100% no-repeat;
|
||||
}
|
||||
|
||||
.link-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
line-height: calc(93 * var(--u));
|
||||
padding: 0 calc(112 * var(--u)) 0 calc(52 * var(--u));
|
||||
overflow: hidden;
|
||||
color: var(--gold);
|
||||
@ -335,11 +339,13 @@ p {
|
||||
font-weight: 700;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
direction: ltr;
|
||||
unicode-bidi: plaintext;
|
||||
}
|
||||
|
||||
.invite-field.is-code .link-box {
|
||||
justify-content: center;
|
||||
padding-left: calc(112 * var(--u));
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.invite-code {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user