修复邀请
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"
|
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
|
||||||
/>
|
/>
|
||||||
<title>Invite Friends</title>
|
<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>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main
|
<main
|
||||||
@ -135,6 +135,7 @@
|
|||||||
class="ornate-button bind-invite-button"
|
class="ornate-button bind-invite-button"
|
||||||
id="bindInviteButton"
|
id="bindInviteButton"
|
||||||
type="button"
|
type="button"
|
||||||
|
hidden
|
||||||
data-i18n="invite.linkInviter"
|
data-i18n="invite.linkInviter"
|
||||||
>
|
>
|
||||||
Bind User
|
Bind User
|
||||||
@ -315,6 +316,6 @@
|
|||||||
<script src="../../common/api.js?v=20260630-invite-code"></script>
|
<script src="../../common/api.js?v=20260630-invite-code"></script>
|
||||||
<script src="../../common/params.js?v=20260611-invite-referrer"></script>
|
<script src="../../common/params.js?v=20260611-invite-referrer"></script>
|
||||||
<script src="../../common/toast.js"></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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
'ios_url',
|
'ios_url',
|
||||||
'url',
|
'url',
|
||||||
];
|
];
|
||||||
|
var BIND_INVITE_VISIBLE_WINDOW_MS = 48 * 60 * 60 * 1000;
|
||||||
var params = new URLSearchParams(window.location.search);
|
var params = new URLSearchParams(window.location.search);
|
||||||
var state = {
|
var state = {
|
||||||
inviteCode: firstParam(INVITE_CODE_KEYS),
|
inviteCode: firstParam(INVITE_CODE_KEYS),
|
||||||
@ -27,6 +28,9 @@
|
|||||||
inviterAvatar: firstParam(SHARE_AVATAR_KEYS),
|
inviterAvatar: firstParam(SHARE_AVATAR_KEYS),
|
||||||
inviteLink: '',
|
inviteLink: '',
|
||||||
currentUser: null,
|
currentUser: null,
|
||||||
|
currentUserCreatedAtMS: 0,
|
||||||
|
currentUserTimingLoaded: false,
|
||||||
|
serverTimeMS: 0,
|
||||||
pendingInviteCode: '',
|
pendingInviteCode: '',
|
||||||
searchedInviter: null,
|
searchedInviter: null,
|
||||||
inviteRewardStatus: null,
|
inviteRewardStatus: null,
|
||||||
@ -58,12 +62,17 @@
|
|||||||
return textValue(value).toUpperCase();
|
return textValue(value).toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
function readPath(source, path) {
|
function readRawPath(source, path) {
|
||||||
var value = source;
|
var value = source;
|
||||||
for (var i = 0; i < path.length; i += 1) {
|
for (var i = 0; i < path.length; i += 1) {
|
||||||
if (!value || typeof value !== 'object') return '';
|
if (!value || typeof value !== 'object') return '';
|
||||||
value = value[path[i]];
|
value = value[path[i]];
|
||||||
}
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readPath(source, path) {
|
||||||
|
var value = readRawPath(source, path);
|
||||||
return textValue(value);
|
return textValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,6 +84,25 @@
|
|||||||
return '';
|
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) {
|
function currentUserPayload(data, profile) {
|
||||||
var target = profile || data || {};
|
var target = profile || data || {};
|
||||||
return Boolean(
|
return Boolean(
|
||||||
@ -84,6 +112,8 @@
|
|||||||
target.displayUserId ||
|
target.displayUserId ||
|
||||||
target.username ||
|
target.username ||
|
||||||
target.nickname ||
|
target.nickname ||
|
||||||
|
target.created_at_ms !== undefined ||
|
||||||
|
target.createdAtMs !== undefined ||
|
||||||
target.profile_completed !== undefined ||
|
target.profile_completed !== undefined ||
|
||||||
target.profileCompleted !== undefined
|
target.profileCompleted !== undefined
|
||||||
);
|
);
|
||||||
@ -137,10 +167,97 @@
|
|||||||
return payload && payload.user ? payload.user : payload;
|
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) {
|
function applyCurrentUser(payload) {
|
||||||
var data = readOverviewPayload(payload || {});
|
var data = readOverviewPayload(payload || {});
|
||||||
var profile = data.profile || data;
|
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, [
|
var inviteCode = firstPath(data, [
|
||||||
['invite', 'my_invite_code'],
|
['invite', 'my_invite_code'],
|
||||||
['invite', 'myInviteCode'],
|
['invite', 'myInviteCode'],
|
||||||
@ -186,6 +303,7 @@
|
|||||||
$('#statEligible').textContent = validInviteCount;
|
$('#statEligible').textContent = validInviteCount;
|
||||||
}
|
}
|
||||||
renderInviteShare();
|
renderInviteShare();
|
||||||
|
renderBindInviteVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadCurrentUser() {
|
function loadCurrentUser() {
|
||||||
@ -826,6 +944,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openBindModal() {
|
function openBindModal() {
|
||||||
|
if (!canShowBindInviteButton()) {
|
||||||
|
renderBindInviteVisibility();
|
||||||
|
return;
|
||||||
|
}
|
||||||
var api = window.HyAppAPI || {};
|
var api = window.HyAppAPI || {};
|
||||||
if (!api.getAccessToken || !api.getAccessToken()) {
|
if (!api.getAccessToken || !api.getAccessToken()) {
|
||||||
toast(t('invite.loginRequired', 'Please log in first'));
|
toast(t('invite.loginRequired', 'Please log in first'));
|
||||||
@ -1089,6 +1211,7 @@
|
|||||||
renderRank();
|
renderRank();
|
||||||
updateCountdown();
|
updateCountdown();
|
||||||
setInterval(updateCountdown, 1000);
|
setInterval(updateCountdown, 1000);
|
||||||
|
renderBindInviteVisibility();
|
||||||
bindEvents();
|
bindEvents();
|
||||||
renderInviteActivityReward(null);
|
renderInviteActivityReward(null);
|
||||||
Promise.all([
|
Promise.all([
|
||||||
|
|||||||
@ -318,16 +318,20 @@ p {
|
|||||||
|
|
||||||
.invite-field {
|
.invite-field {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 0;
|
||||||
height: calc(93 * var(--u));
|
height: calc(93 * var(--u));
|
||||||
|
overflow: hidden;
|
||||||
background: url('./assets/link-input.svg') center / 100% 100% no-repeat;
|
background: url('./assets/link-input.svg') center / 100% 100% no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link-box {
|
.link-box {
|
||||||
display: flex;
|
display: block;
|
||||||
align-items: center;
|
width: 100%;
|
||||||
justify-content: flex-start;
|
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
max-width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
line-height: calc(93 * var(--u));
|
||||||
padding: 0 calc(112 * var(--u)) 0 calc(52 * var(--u));
|
padding: 0 calc(112 * var(--u)) 0 calc(52 * var(--u));
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
color: var(--gold);
|
color: var(--gold);
|
||||||
@ -335,11 +339,13 @@ p {
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
direction: ltr;
|
||||||
|
unicode-bidi: plaintext;
|
||||||
}
|
}
|
||||||
|
|
||||||
.invite-field.is-code .link-box {
|
.invite-field.is-code .link-box {
|
||||||
justify-content: center;
|
|
||||||
padding-left: calc(112 * var(--u));
|
padding-left: calc(112 * var(--u));
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.invite-code {
|
.invite-code {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user