2026-05-19 15:18:34 +08:00

995 lines
28 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover" />
<title>Room Reward Event</title>
<style>
@font-face {
font-family: "BalooDa2";
src: url("../../assets/BalooDa2-Bold-ChYvdM8z-1776148661447.ttf") format("truetype");
font-weight: 700;
font-style: normal;
font-display: swap;
}
:root {
--page-width: 430px;
--brown-980: #170600;
--brown-920: #240900;
--brown-850: #321000;
--brown-780: #431802;
--gold-100: #fff4cf;
--gold-200: #ffe3a2;
--gold-400: #f8ba55;
--gold-650: #a84e16;
--line: rgba(255, 230, 173, 0.9);
--hero-image: url("../../assets/room-turnover-reward/hero.png");
--coin-image: url("../../assets/coin-lz3Tp0nX-177614866144.png");
}
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
min-height: 100%;
background: #0b0300;
font-family:
-apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Arial,
sans-serif;
}
body {
color: #fff7df;
padding-bottom: env(safe-area-inset-bottom);
}
.page {
position: relative;
width: min(100%, var(--page-width));
min-height: 100vh;
margin: 0 auto;
overflow: hidden;
background:
radial-gradient(circle at 50% 0, rgba(249, 164, 53, 0.2) 0, rgba(249, 164, 53, 0) 36%),
linear-gradient(180deg, #2b0d02 0%, #1b0600 42%, #150500 100%);
padding-bottom: calc(142px + env(safe-area-inset-bottom));
}
.hero {
position: relative;
padding-top: env(safe-area-inset-top);
background: #3c1707;
}
.hero-visual {
position: relative;
aspect-ratio: 552 / 390;
background: center top / cover no-repeat var(--hero-image);
}
.hero-visual::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: -1px;
height: 38px;
background: linear-gradient(180deg, rgba(28, 7, 0, 0) 0%, #230800 82%);
}
.content {
position: relative;
z-index: 1;
margin-top: -6px;
padding: 0 14px;
}
.reward-meter {
position: relative;
min-height: 118px;
margin: 0 -2px 24px;
display: grid;
place-items: center;
border: 3px solid transparent;
border-image: linear-gradient(90deg, #ffe7b5, #c96a25 18%, #fff0bb 50%, #c96a25 82%, #ffe7b5) 1;
background:
linear-gradient(180deg, rgba(74, 24, 2, 0.58), rgba(35, 9, 0, 0.96)) padding-box,
linear-gradient(180deg, #fff7d2, #d8792e 24%, #fff0bc 50%, #9b3e0d 78%, #ffe7b3) border-box;
box-shadow:
0 8px 20px rgba(0, 0, 0, 0.34),
inset 0 0 0 1px rgba(80, 20, 3, 0.95),
inset 0 0 32px rgba(247, 137, 40, 0.14);
}
.reward-meter::before,
.reward-meter::after {
content: "";
position: absolute;
left: 50%;
width: 78px;
height: 38px;
transform: translateX(-50%);
background:
radial-gradient(circle at 50% 48%, #f75b7a 0 12px, #ffca71 13px 17px, rgba(255, 202, 113, 0) 18px),
linear-gradient(90deg, rgba(255, 223, 156, 0), #ffe3a5 25%, #b84816 50%, #ffe3a5 75%, rgba(255, 223, 156, 0));
clip-path: polygon(50% 0, 100% 48%, 50% 100%, 0 48%);
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.42));
}
.reward-meter::before {
top: -20px;
}
.reward-meter::after {
bottom: -20px;
}
.corner {
position: absolute;
width: 56px;
height: 56px;
pointer-events: none;
}
.corner::before,
.corner::after {
content: "";
position: absolute;
border-radius: 999px 999px 4px 999px;
background: linear-gradient(135deg, #fff6d4 0%, #f1a947 42%, #8d2f0b 100%);
box-shadow: inset 0 0 0 1px rgba(255, 244, 199, 0.78);
}
.corner::before {
width: 36px;
height: 18px;
left: 6px;
top: 18px;
transform: rotate(-26deg);
}
.corner::after {
width: 18px;
height: 36px;
left: 18px;
top: 6px;
transform: rotate(26deg);
}
.corner.tl {
left: -8px;
top: -9px;
}
.corner.tr {
right: -8px;
top: -9px;
transform: scaleX(-1);
}
.corner.bl {
left: -8px;
bottom: -9px;
transform: scaleY(-1);
}
.corner.br {
right: -8px;
bottom: -9px;
transform: scale(-1);
}
.meter-value {
position: relative;
z-index: 1;
display: inline-flex;
align-items: center;
gap: 9px;
min-width: 0;
max-width: calc(100% - 42px);
color: var(--gold-100);
font-family: "BalooDa2", -apple-system, BlinkMacSystemFont, Arial, sans-serif;
font-size: 42px;
line-height: 1;
font-weight: 700;
text-align: center;
text-shadow:
0 2px 0 #7c2f0b,
0 0 12px rgba(255, 190, 75, 0.38);
}
.coin {
display: inline-block;
flex: 0 0 auto;
width: 25px;
height: 25px;
background: center / contain no-repeat var(--coin-image);
filter: drop-shadow(0 1px 1px rgba(63, 19, 0, 0.54));
}
.rule-table {
position: relative;
overflow: hidden;
border: 3px solid #f3bf82;
background: #210800;
box-shadow:
0 0 0 1px #6d2609,
0 10px 22px rgba(0, 0, 0, 0.35),
inset 0 0 0 1px rgba(255, 249, 218, 0.32);
}
.rule-table::before {
content: "";
position: absolute;
inset: 3px;
border: 1px solid rgba(255, 242, 203, 0.5);
pointer-events: none;
}
.table-row {
position: relative;
z-index: 1;
display: grid;
grid-template-columns: 1fr 1fr;
min-height: 52px;
}
.table-row:nth-child(odd) {
background: #1b0600;
}
.table-row:nth-child(even) {
background: #321000;
}
.table-row.header {
min-height: 58px;
background: #1c0700;
color: #fff8ec;
font-size: 15px;
font-weight: 700;
}
.table-cell {
display: flex;
align-items: center;
justify-content: center;
min-width: 0;
padding: 8px 10px;
border-left: 1px solid rgba(255, 245, 216, 0.84);
color: #fff4df;
font-size: 15px;
line-height: 1.15;
font-weight: 700;
text-align: center;
white-space: nowrap;
}
.table-cell:first-child {
border-left: 0;
}
.reward-cell {
color: #ffdc8e;
gap: 5px;
}
.reward-cell .coin {
width: 13px;
height: 13px;
}
.dock {
position: fixed;
left: 50%;
bottom: 0;
z-index: 20;
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 8px;
align-items: center;
width: min(100%, var(--page-width));
min-height: 76px;
padding: 10px 14px calc(10px + env(safe-area-inset-bottom));
transform: translateX(-50%);
border-top: 1px solid rgba(255, 222, 160, 0.18);
background: rgba(20, 5, 0, 0.98);
box-shadow: 0 -8px 18px rgba(0, 0, 0, 0.42);
}
.profile {
display: grid;
grid-template-columns: 54px minmax(0, 1fr);
gap: 9px;
align-items: center;
min-width: 0;
}
.avatar {
width: 54px;
height: 54px;
overflow: hidden;
border: 2px solid #ffd995;
border-radius: 999px;
background: #3b1708;
box-shadow: 0 0 0 1px rgba(129, 54, 18, 0.9);
}
.avatar img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
.profile-copy {
min-width: 0;
}
.name {
overflow: hidden;
color: #fff3df;
font-size: 17px;
font-weight: 800;
line-height: 1.2;
text-overflow: ellipsis;
white-space: nowrap;
}
.id {
margin-top: 5px;
color: rgba(255, 239, 205, 0.78);
font-size: 11px;
line-height: 1.1;
}
.stats {
display: grid;
gap: 8px;
min-width: 160px;
}
.stat-row {
display: grid;
grid-template-columns: max-content 74px;
gap: 7px;
align-items: center;
justify-content: end;
color: #fff6e9;
font-size: 12px;
line-height: 1.1;
white-space: nowrap;
}
.stat-pill {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 4px;
min-width: 74px;
height: 27px;
padding: 0 10px;
border: 1px solid #c37019;
border-radius: 999px;
background: linear-gradient(180deg, #fff1bf 0%, #ffd685 44%, #ffe7ae 100%);
color: #c45a13;
font-family: "BalooDa2", -apple-system, BlinkMacSystemFont, Arial, sans-serif;
font-size: 14px;
font-weight: 700;
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.68),
0 1px 0 rgba(64, 15, 0, 0.52);
}
.stat-pill .coin {
width: 12px;
height: 12px;
}
.claim-button {
grid-column: 1 / -1;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
width: 100%;
min-height: 38px;
padding: 0 16px;
border: 1px solid #c37019;
border-radius: 999px;
appearance: none;
background: linear-gradient(180deg, #fff0bd 0%, #ffc35b 48%, #f3932c 100%);
color: #7d2b05;
font-size: 15px;
font-weight: 900;
line-height: 1.1;
text-align: center;
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.78),
0 2px 0 rgba(104, 36, 2, 0.86),
0 5px 12px rgba(0, 0, 0, 0.28);
}
.claim-button:not(:disabled):active {
transform: translateY(1px);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.78),
0 1px 0 rgba(104, 36, 2, 0.86),
0 3px 9px rgba(0, 0, 0, 0.26);
}
.claim-button:disabled {
background: linear-gradient(180deg, #6a3a18 0%, #47200b 100%);
color: rgba(255, 233, 196, 0.58);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.08),
0 1px 0 rgba(0, 0, 0, 0.36);
}
.claim-button .coin {
width: 15px;
height: 15px;
}
.claim-button .coin[hidden] {
display: none;
}
.toast {
position: fixed;
left: 50%;
bottom: calc(132px + env(safe-area-inset-bottom));
z-index: 30;
width: min(calc(100% - 44px), 330px);
min-height: 38px;
padding: 10px 14px;
transform: translateX(-50%);
border: 1px solid rgba(255, 221, 152, 0.44);
border-radius: 999px;
background: rgba(23, 6, 0, 0.94);
color: #fff4df;
font-size: 13px;
line-height: 1.2;
font-weight: 700;
text-align: center;
box-shadow: 0 8px 22px rgba(0, 0, 0, 0.38);
}
@media (max-width: 360px) {
.content {
padding-left: 10px;
padding-right: 10px;
}
.meter-value {
font-size: 37px;
}
.dock {
grid-template-columns: 1fr;
gap: 8px;
padding-left: 12px;
padding-right: 12px;
}
.stats {
min-width: 0;
}
.stat-row {
grid-template-columns: minmax(0, 1fr) 74px;
justify-content: stretch;
}
.stat-row span:first-child {
overflow: hidden;
text-overflow: ellipsis;
}
.page {
padding-bottom: calc(208px + env(safe-area-inset-bottom));
}
.toast {
bottom: calc(194px + env(safe-area-inset-bottom));
}
}
</style>
<script>
window.__H5_ROUTE_PATH__ = "/activity/room-turnover-reward";
</script>
<script src="../../assets/yumi-route-entry.js"></script>
</head>
<body>
<main class="page">
<section class="hero" aria-label="Room Reward Event">
<div class="hero-visual"></div>
</section>
<section class="content">
<div class="reward-meter" aria-label="Current reward">
<span class="corner tl"></span>
<span class="corner tr"></span>
<span class="corner bl"></span>
<span class="corner br"></span>
<div class="meter-value">
<span id="highlightReward">1000</span>
<span class="coin" aria-hidden="true"></span>
</div>
</div>
<div class="rule-table" aria-label="Room turnover reward levels">
<div class="table-row header">
<div class="table-cell">Room turnover</div>
<div class="table-cell">Receive a reward</div>
</div>
<div id="levelRows"></div>
</div>
</section>
<aside class="dock" aria-label="Room reward profile">
<div class="profile">
<div class="avatar">
<img id="profileAvatar" src="../../assets/defaultAvatar-CdxWBK1k.png" alt="Room avatar" />
</div>
<div class="profile-copy">
<div class="name" id="profileName">Namename...</div>
<div class="id">ID: <span id="profileId">123456789</span></div>
</div>
</div>
<div class="stats">
<div class="stat-row">
<span>This week's contribution:</span>
<span class="stat-pill">
<span id="currentTurnover">100</span>
<span class="coin" aria-hidden="true"></span>
</span>
</div>
<div class="stat-row">
<span>Next week's rewards:</span>
<span class="stat-pill">
<span id="currentReward">100</span>
<span class="coin" aria-hidden="true"></span>
</span>
</div>
</div>
<button class="claim-button" id="claimButton" type="button" disabled>
<span id="claimButtonText">Checking...</span>
<span class="coin" id="claimButtonCoin" aria-hidden="true" hidden></span>
</button>
</aside>
<div class="toast" id="pageToast" role="status" aria-live="polite" hidden></div>
</main>
<script>
const DEFAULT_API_BASE = "https://jvapi.haiyihy.com/";
const DEFAULT_API_PREFIX = "/go";
const DEFAULT_AVATAR = "../../assets/defaultAvatar-CdxWBK1k.png";
const query = buildPageQueryParams();
const resolvedAPIBase = resolveAPIBase();
const fallbackLevels = Array.from({ length: 7 }, (_, index) => ({
level: index + 1,
turnoverThreshold: 7000000,
rewardGold: 350000,
enabled: true,
}));
const state = {
apiBase: resolvedAPIBase,
apiPrefix: resolveAPIPrefix(resolvedAPIBase),
token: resolveToken(),
levels: fallbackLevels,
highlightReward: numberFromQuery(["highlightRewardGold", "highlightReward", "topRewardGold"], 1000),
currentTurnover: numberFromQuery(["turnover", "contribution", "amount"], 100),
currentReward: numberFromQuery(["weekReward", "reward", "currentReward"], 100),
profileName: textFromQuery(["roomName", "name", "nickname"], "Namename..."),
profileId: textFromQuery(["roomAccount", "account", "roomId", "id"], "123456789"),
profileAvatar: textFromQuery(["roomCover", "avatar", "userAvatar"], DEFAULT_AVATAR),
claimStatus: {
canClaim: false,
reason: "loading",
autoRewardEnabled: false,
record: null,
},
claimLoading: false,
toastTimer: 0,
};
const els = {
levelRows: document.getElementById("levelRows"),
highlightReward: document.getElementById("highlightReward"),
currentTurnover: document.getElementById("currentTurnover"),
currentReward: document.getElementById("currentReward"),
profileName: document.getElementById("profileName"),
profileId: document.getElementById("profileId"),
profileAvatar: document.getElementById("profileAvatar"),
claimButton: document.getElementById("claimButton"),
claimButtonText: document.getElementById("claimButtonText"),
claimButtonCoin: document.getElementById("claimButtonCoin"),
pageToast: document.getElementById("pageToast"),
};
function trimValue(value) {
return value == null ? "" : String(value).trim();
}
function buildPageQueryParams() {
const params = new URLSearchParams(window.location.search);
const hash = window.location.hash || "";
const queryIndex = hash.indexOf("?");
if (queryIndex >= 0) {
const hashParams = new URLSearchParams(hash.slice(queryIndex + 1));
hashParams.forEach((value, key) => {
if (!params.has(key)) {
params.append(key, value);
}
});
}
return params;
}
function textFromQuery(keys, fallback) {
for (const key of keys) {
const value = trimValue(query.get(key));
if (value) {
return value;
}
}
return fallback;
}
function resolveToken() {
const token = textFromQuery(["token", "accessToken", "authorization"], "");
if (token.toLowerCase().startsWith("bearer ")) {
return "Bearer " + token.slice(7).replace(/ /g, "+");
}
return token.replace(/ /g, "+");
}
function numberFromQuery(keys, fallback) {
for (const key of keys) {
const raw = trimValue(query.get(key));
if (!raw) {
continue;
}
const number = Number(raw.replace(/,/g, ""));
if (Number.isFinite(number)) {
return number;
}
}
return fallback;
}
function normalizeBaseURL(base) {
const value = trimValue(base) || DEFAULT_API_BASE;
return value.endsWith("/") ? value : value + "/";
}
function resolveAPIBase() {
const queryBase = trimValue(query.get("apiBase"));
if (queryBase) {
return normalizeBaseURL(queryBase);
}
if (typeof window.__ROOM_TURNOVER_REWARD_API_BASE__ === "string") {
return normalizeBaseURL(window.__ROOM_TURNOVER_REWARD_API_BASE__);
}
return normalizeBaseURL(DEFAULT_API_BASE);
}
function resolveAPIPrefix(apiBase) {
const queryPrefix = trimValue(query.get("apiPrefix"));
if (queryPrefix) {
return queryPrefix;
}
if (typeof window.__ROOM_TURNOVER_REWARD_API_PREFIX__ === "string") {
return trimValue(window.__ROOM_TURNOVER_REWARD_API_PREFIX__);
}
return isOnlineAPIBase(apiBase) ? DEFAULT_API_PREFIX : "";
}
function isOnlineAPIBase(base) {
try {
return new URL(base, window.location.href).origin === new URL(DEFAULT_API_BASE).origin;
} catch (_) {
return false;
}
}
function joinURLPath(...parts) {
return "/" + parts
.map((part) => trimValue(part).replace(/^\/+|\/+$/g, ""))
.filter(Boolean)
.join("/");
}
function buildAPIURL(path, searchParams = {}) {
const apiPath = joinURLPath(state.apiPrefix, path);
const url = new URL(apiPath.replace(/^\/+/, ""), state.apiBase);
Object.entries(searchParams).forEach(([key, value]) => {
const raw = trimValue(value);
if (raw) {
url.searchParams.set(key, raw);
}
});
return url;
}
async function requestJSON(path, options = {}) {
const url = buildAPIURL(path, options.searchParams || {});
const headers = { Accept: "application/json" };
if (options.auth && state.token) {
headers.Authorization = state.token.toLowerCase().startsWith("bearer ")
? state.token
: "Bearer " + state.token;
}
const fetchOptions = {
method: options.method || "GET",
headers,
};
if (options.body != null) {
headers["Content-Type"] = "application/json";
fetchOptions.body = JSON.stringify(options.body);
}
const response = await fetch(url.toString(), fetchOptions);
const contentType = response.headers.get("content-type") || "";
if (!contentType.includes("application/json")) {
if (!response.ok) {
throw new Error("Request failed: " + response.status);
}
return null;
}
const json = await response.json();
if (!response.ok) {
const message = json && (json.message || json.errorMsg || json.code);
throw new Error(message || "Request failed: " + response.status);
}
return json && (json.body || json.data || json);
}
function escapeHtml(value) {
return String(value).replace(/[&<>"']/g, (match) => {
const entityMap = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
'"': "&quot;",
"'": "&#39;",
};
return entityMap[match] || match;
});
}
function formatCompact(value) {
const number = Number(value || 0);
if (!Number.isFinite(number)) {
return "0";
}
const absolute = Math.abs(number);
if (absolute >= 1000000) {
return trimDecimal(number / 1000000) + "M";
}
if (absolute >= 1000) {
return trimDecimal(number / 1000) + "k";
}
return new Intl.NumberFormat("en-US").format(Math.trunc(number));
}
function trimDecimal(value) {
return Number(value.toFixed(1)).toString();
}
function formatMeterValue(value) {
const number = Number(value || 0);
if (!Number.isFinite(number)) {
return "0";
}
return String(Math.trunc(number));
}
function normalizeLevels(levels) {
const source = Array.isArray(levels) && levels.length ? levels : fallbackLevels;
return source
.filter((level) => level && level.turnoverThreshold > 0 && level.rewardGold > 0)
.sort((a, b) => Number(a.turnoverThreshold) - Number(b.turnoverThreshold));
}
function applyHomeData(body) {
if (!body || typeof body !== "object") {
return;
}
state.levels = normalizeLevels(body.levelConfigs);
state.highlightReward = Number(body.expectedRewardGold || body.highlightRewardGold || 0);
state.currentTurnover = Number(body.turnoverAmount || 0);
state.currentReward = Number(body.expectedRewardGold || 0);
state.profileName = trimValue(body.userNickname) || trimValue(body.roomName) || state.profileName;
state.profileId = trimValue(body.userAccount) || trimValue(body.roomAccount) || trimValue(body.roomId) || state.profileId;
state.profileAvatar = trimValue(body.userAvatar) || trimValue(body.roomCover) || state.profileAvatar;
}
function applyPublicPageData(body) {
if (!body || typeof body !== "object") {
return;
}
state.levels = normalizeLevels(body.levelConfigs);
const hasHighlightOverride =
query.has("highlightRewardGold") || query.has("highlightReward") || query.has("topRewardGold");
if (!hasHighlightOverride && body.highlightRewardGold > 0) {
state.highlightReward = Number(body.highlightRewardGold);
}
}
function applyClaimStatus(body) {
const source = body && typeof body === "object" ? body : {};
const canClaim = Boolean(source.canClaim);
state.claimStatus = {
canClaim,
reason: trimValue(source.reason) || (canClaim ? "available" : "no_claimable_reward"),
autoRewardEnabled: Boolean(source.autoRewardEnabled),
record: source.record || null,
};
}
function claimButtonText() {
const status = state.claimStatus || {};
if (state.claimLoading) {
return "Claiming...";
}
if (!state.token) {
return "Login required";
}
if (status.reason === "loading") {
return "Checking...";
}
if (status.canClaim) {
const rewardGold = Number(status.record && status.record.rewardGold ? status.record.rewardGold : 0);
return rewardGold > 0 ? "Claim " + formatCompact(rewardGold) : "Claim reward";
}
if (status.reason === "claimed") {
return "Claimed";
}
if (status.reason === "auto_reward_enabled") {
return "Auto issued";
}
if (status.reason === "status_unavailable") {
return "Retry later";
}
return "No reward";
}
function renderClaimButton() {
const status = state.claimStatus || {};
const rewardGold = Number(status.record && status.record.rewardGold ? status.record.rewardGold : 0);
const canClaim = Boolean(state.token && status.canClaim && !state.claimLoading);
els.claimButton.disabled = !canClaim;
els.claimButton.setAttribute("aria-busy", state.claimLoading ? "true" : "false");
els.claimButtonText.textContent = claimButtonText();
els.claimButtonCoin.hidden = !(status.canClaim && rewardGold > 0);
}
function showToast(message) {
const text = trimValue(message);
if (!text) {
return;
}
window.clearTimeout(state.toastTimer);
els.pageToast.textContent = text;
els.pageToast.hidden = false;
state.toastTimer = window.setTimeout(() => {
els.pageToast.hidden = true;
}, 2200);
}
function render() {
els.highlightReward.textContent = formatMeterValue(state.highlightReward);
els.currentTurnover.textContent = formatCompact(state.currentTurnover);
els.currentReward.textContent = formatCompact(state.currentReward);
els.profileName.textContent = state.profileName;
els.profileId.textContent = state.profileId;
els.profileAvatar.src = state.profileAvatar || DEFAULT_AVATAR;
els.levelRows.innerHTML = state.levels.map((level) => {
return `
<div class="table-row">
<div class="table-cell">${escapeHtml(formatCompact(level.turnoverThreshold))}</div>
<div class="table-cell reward-cell">
<span>${escapeHtml(formatCompact(level.rewardGold))}</span>
<span class="coin" aria-hidden="true"></span>
</div>
</div>`;
}).join("");
renderClaimButton();
}
async function fetchPageData() {
if (state.token) {
try {
const home = await requestJSON("/app/h5/room-turnover-reward/home", { auth: true });
applyHomeData(home);
} catch (_) {
} finally {
render();
}
await fetchClaimStatus();
return;
}
try {
const body = await requestJSON("/public/h5/room-turnover-reward/page", {
searchParams: { sysOrigin: query.get("sysOrigin") },
});
applyPublicPageData(body);
} catch (_) {
}
applyClaimStatus({ canClaim: false, reason: "login_required", autoRewardEnabled: false });
render();
}
async function fetchClaimStatus() {
if (!state.token) {
applyClaimStatus({ canClaim: false, reason: "login_required", autoRewardEnabled: false });
renderClaimButton();
return;
}
state.claimStatus = {
canClaim: false,
reason: "loading",
autoRewardEnabled: false,
record: null,
};
renderClaimButton();
try {
const body = await requestJSON("/app/h5/room-turnover-reward/reward/claim/status", { auth: true });
applyClaimStatus(body);
} catch (_) {
applyClaimStatus({ canClaim: false, reason: "status_unavailable", autoRewardEnabled: false });
}
renderClaimButton();
}
async function handleClaimClick() {
const status = state.claimStatus || {};
if (state.claimLoading || !state.token || !status.canClaim) {
return;
}
const record = status.record || {};
const payload = {};
const recordId = trimValue(record.id);
if (recordId) {
payload.recordId = recordId;
}
state.claimLoading = true;
renderClaimButton();
try {
const body = await requestJSON("/app/h5/room-turnover-reward/reward/claim", {
auth: true,
method: "POST",
body: payload,
});
applyClaimStatus({
canClaim: false,
reason: "claimed",
autoRewardEnabled: false,
record: body && body.record ? body.record : record,
});
showToast(body && body.claimed === false ? "Reward already claimed" : "Reward claimed");
} catch (error) {
showToast(error && error.message ? error.message : "Claim failed");
} finally {
state.claimLoading = false;
renderClaimButton();
}
fetchClaimStatus();
}
els.claimButton.addEventListener("click", handleClaimClick);
render();
fetchPageData();
</script>
</body>
</html>