From ca3a1db770e23ec39f57aab942ddafe09018629f Mon Sep 17 00:00:00 2001 From: kang Date: Mon, 25 May 2026 15:35:50 +0800 Subject: [PATCH] feat: enhance player panel and draw status handling - Refactored PlayerPanel layout for improved title positioning and responsiveness. - Added new function to check if betting is blocked based on hall status. - Updated HallDrawPanel to utilize the new betting status check and display appropriate messages. - Enhanced i18n support with new notices for review and non-bettable states across multiple languages. --- src/components/layout/player-panel.tsx | 26 ++++++++------------------ src/features/draw/draw-status-meta.ts | 5 +++++ src/features/hall/hall-draw-panel.tsx | 19 +++++++++++++------ src/i18n/index.ts | 17 ++--------------- src/i18n/locales/en/player.json | 2 ++ src/i18n/locales/ne/player.json | 2 ++ src/i18n/locales/zh/player.json | 2 ++ src/lib/player-spacing.ts | 4 ++-- src/stores/error-store.ts | 4 ++-- 9 files changed, 38 insertions(+), 43 deletions(-) diff --git a/src/components/layout/player-panel.tsx b/src/components/layout/player-panel.tsx index f78eb6e..40c0666 100644 --- a/src/components/layout/player-panel.tsx +++ b/src/components/layout/player-panel.tsx @@ -6,7 +6,6 @@ import type { ReactNode } from "react"; import { Bell, ChevronLeft } from "lucide-react"; import { useTranslation } from "react-i18next"; -import { CurrencySwitcher } from "@/components/currency-switcher"; import { LanguageSwitcher } from "@/components/language-switcher"; import { playerHeaderControl, @@ -48,10 +47,10 @@ export function PlayerPanel({
-
+
-
-

- {title} -

-
+

+ {title} +

-
- +
- {formatSecondsClock(seconds)} + {hud.countdownKind === "none" ? "--:--" : formatSecondsClock(seconds)} {label} @@ -127,6 +129,7 @@ export function HallDrawPanel({ drawLive }: { drawLive: HallDrawLiveSnapshot }) const hud = drawStatusHud(display.status); const sealedUi = isHallSealedCountdownUi(display.status); + const blockedUi = isHallBlockedForBetting(display.status); return (
- {sealedUi ? ( + {blockedUi ? (
- - {t("draw.sealedNotice")} + + {display.status === "review" + ? t("draw.reviewNotice") + : sealedUi + ? t("draw.sealedNotice") + : t("draw.notBettableNotice")}
) : (
diff --git a/src/i18n/index.ts b/src/i18n/index.ts index 23f06f5..d9f1ed9 100644 --- a/src/i18n/index.ts +++ b/src/i18n/index.ts @@ -53,17 +53,6 @@ const resources = { Record<(typeof namespaces)[number], Record> >; -function resolveInitialLanguage(): AppLanguage { - // SSR 始终使用默认语言,避免首屏渲染依赖浏览器状态 - if (typeof window === "undefined") { - return DEFAULT_LANGUAGE; - } - - const stored = window.localStorage.getItem("i18nextLng"); - const preferred = normalizeLanguage(stored ?? window.navigator.language); - return preferred; -} - export function syncDocumentLanguage(lang: AppLanguage): void { if (typeof document === "undefined") return; @@ -83,17 +72,15 @@ export function syncPreferredLanguage(): void { } if (!i18n.isInitialized) { - const initialLng = resolveInitialLanguage(); - void i18n.use(initReactI18next).init({ resources, fallbackLng: DEFAULT_LANGUAGE, supportedLngs: ["en", "ne", "zh"], defaultNS: "common", ns: [...namespaces], - /** 始终先用默认语言完成 SSR / 首次 hydration,避免首屏文本不一致 */ + /** 与 SSR 一致:首屏固定默认语言,hydration 后再由 syncPreferredLanguage 切换 */ load: "languageOnly", - lng: initialLng, + lng: DEFAULT_LANGUAGE, interpolation: { escapeValue: false, diff --git a/src/i18n/locales/en/player.json b/src/i18n/locales/en/player.json index 7425f27..31f21cd 100644 --- a/src/i18n/locales/en/player.json +++ b/src/i18n/locales/en/player.json @@ -81,6 +81,8 @@ "hall": "Betting Hall", "noIssue": "No available issue. Please try again later.", "sealedNotice": "Closed. Please wait for the next issue.", + "reviewNotice": "Draw results are pending admin review. The next issue opens after publish.", + "notBettableNotice": "Betting is not available right now. Please try again later.", "status": { "pending": "Not started", "open": "Open", diff --git a/src/i18n/locales/ne/player.json b/src/i18n/locales/ne/player.json index 4d18d2d..261d677 100644 --- a/src/i18n/locales/ne/player.json +++ b/src/i18n/locales/ne/player.json @@ -81,6 +81,8 @@ "hall": "बेटिङ हल", "noIssue": "उपलब्ध इश्यू छैन। कृपया पछि प्रयास गर्नुहोस्।", "sealedNotice": "बन्द भयो। कृपया अर्को इश्यू पर्खनुहोस्।", + "reviewNotice": "नतिजा प्रशासक समीक्षामा छ। प्रकाशन पछि अर्को इश्यू खुल्छ।", + "notBettableNotice": "अहिले बाजी लगाउन मिल्दैन। कृपया पछि प्रयास गर्नुहोस्।", "status": { "pending": "सुरु भएको छैन", "open": "खुला", diff --git a/src/i18n/locales/zh/player.json b/src/i18n/locales/zh/player.json index a9ca43a..8e2ca2b 100644 --- a/src/i18n/locales/zh/player.json +++ b/src/i18n/locales/zh/player.json @@ -81,6 +81,8 @@ "hall": "下注大厅", "noIssue": "暂无可用期号,请稍后再试", "sealedNotice": "已封盘,请等待下一期。", + "reviewNotice": "开奖结果待后台审核发布,审核通过后将开启下一期。", + "notBettableNotice": "当前不可下注,请稍后再试。", "status": { "pending": "未开始", "open": "可下注", diff --git a/src/lib/player-spacing.ts b/src/lib/player-spacing.ts index 48a9604..15a4cc3 100644 --- a/src/lib/player-spacing.ts +++ b/src/lib/player-spacing.ts @@ -1,8 +1,8 @@ /** 玩家端统一紧凑间距(页面壳、区块堆叠、区块间距) */ export const playerPageInset = "px-3 pb-6 pt-2"; -/** 顶栏:左右等宽列 + 居中标题,避免返回键与标题高低不齐 */ +/** 顶栏:左右分列 + 标题绝对居中,避免右侧控件挤压/遮挡标题 */ export const playerPageHeader = - "mb-2 grid min-h-9 grid-cols-[1fr_auto_1fr] items-center gap-x-2"; + "relative mb-2 flex min-h-9 items-center justify-between gap-2"; /** 顶栏左右控件统一高度 */ export const playerHeaderControl = "inline-flex h-8 shrink-0 items-center justify-center"; diff --git a/src/stores/error-store.ts b/src/stores/error-store.ts index 65854d5..fab27dc 100644 --- a/src/stores/error-store.ts +++ b/src/stores/error-store.ts @@ -28,8 +28,8 @@ interface ErrorState { } export const useErrorStore = create((set, get) => ({ - // 初始状态 - isOffline: typeof window !== "undefined" ? !navigator.onLine : false, + // 首屏与 SSR 一致为 false;真实离线状态由 useNetworkStatus 在 mount 后同步 + isOffline: false, isServerError: false, serverErrorMessage: "服务器暂时不可用,请稍后重试", currentErrorType: null,