feat: 重构和优化多个组件,增强性能和可维护性
Some checks failed
lotteryfront CI / build (push) Has been cancelled

This commit is contained in:
2026-06-30 11:42:05 +08:00
parent 7bfc713b14
commit ce1aca8905
15 changed files with 269 additions and 92 deletions

View File

@@ -1,19 +1,39 @@
"use client";
import { createContext, useContext, useEffect, useState, type ReactNode } from "react";
import {
createContext,
useContext,
useSyncExternalStore,
type ReactNode,
} from "react";
import { syncPreferredLanguage } from "@/i18n";
const I18nHydrationContext = createContext(false);
function subscribeI18nHydration(onStoreChange: () => void): () => void {
queueMicrotask(() => {
syncPreferredLanguage();
onStoreChange();
});
return () => {};
}
function getI18nHydratedSnapshot(): boolean {
return true;
}
function getI18nHydratedServerSnapshot(): boolean {
return false;
}
/** hydration 完成前保持 DEFAULT_LANGUAGE与 SSR 一致;完成后再同步用户偏好语言。 */
export function I18nHydrationProvider({ children }: { children: ReactNode }) {
const [hydrated, setHydrated] = useState(false);
useEffect(() => {
syncPreferredLanguage();
setHydrated(true);
}, []);
const hydrated = useSyncExternalStore(
subscribeI18nHydration,
getI18nHydratedSnapshot,
getI18nHydratedServerSnapshot,
);
return (
<I18nHydrationContext.Provider value={hydrated}>{children}</I18nHydrationContext.Provider>

View File

@@ -10,6 +10,33 @@ import {
resolvePostMessageTargetOrigin,
} from "@/lib/iframe-origins";
function sanitizeUrlForParent(href: string): string {
try {
const url = new URL(href);
url.searchParams.delete("token");
return `${url.pathname}${url.search}${url.hash}`;
} catch {
return href;
}
}
function resolveSafeInAppPath(path: string): string | null {
if (!path.startsWith("/") || path.startsWith("//")) {
return null;
}
try {
const url = new URL(path, window.location.origin);
if (url.origin !== window.location.origin) {
return null;
}
return `${url.pathname}${url.search}${url.hash}`;
} catch {
return null;
}
}
/**
* iframe 通信桥接组件
*
@@ -49,7 +76,7 @@ export function IframeBridge({ children }: { children: ReactNode }): ReactNode {
*/
const notifyReady = useCallback((): void => {
sendToParent("READY", {
url: window.location.href,
url: sanitizeUrlForParent(window.location.href),
userAgent: navigator.userAgent,
});
}, [sendToParent]);
@@ -147,7 +174,10 @@ export function IframeBridge({ children }: { children: ReactNode }): ReactNode {
// 主站导航请求
case "MAIN_NAVIGATE":
if (data.path && typeof data.path === "string") {
window.history.pushState({}, "", data.path);
const nextPath = resolveSafeInAppPath(data.path);
if (nextPath) {
window.history.pushState({}, "", nextPath);
}
}
break;