fix(chat): redirect guests to auth before image paywall

This commit is contained in:
2026-06-24 18:41:59 +08:00
parent c288148c12
commit 5aa32a4256
4 changed files with 47 additions and 12 deletions
+23 -6
View File
@@ -17,10 +17,15 @@ import { Logger } from "@/utils";
const log = new Logger("AppAuthAuthScreen"); const log = new Logger("AppAuthAuthScreen");
export function AuthScreen() { export interface AuthScreenProps {
redirectTo?: string | null;
}
export function AuthScreen({ redirectTo = null }: AuthScreenProps) {
const state = useAuthState(); const state = useAuthState();
const authDispatch = useAuthDispatch(); const authDispatch = useAuthDispatch();
const router = useRouter(); const router = useRouter();
const safeRedirectTo = getSafeRedirectPath(redirectTo) ?? ROUTES.chat;
// 邮箱登录成功 → 跳转;User hydrate 由根级 <UserAuthSync /> 监听 loginStatus 变化处理。 // 邮箱登录成功 → 跳转;User hydrate 由根级 <UserAuthSync /> 监听 loginStatus 变化处理。
// 用 pendingRedirect flag(不是 useRef transition detection)—— // 用 pendingRedirect flag(不是 useRef transition detection)——
@@ -34,13 +39,19 @@ export function AuthScreen() {
}); });
if (state.pendingRedirect && state.loginStatus !== "notLoggedIn") { if (state.pendingRedirect && state.loginStatus !== "notLoggedIn") {
log.debug( log.debug("[auth-screen] useEffect → router.replace [via pendingRedirect flag]", {
"[auth-screen] useEffect → router.replace(/chat) [via pendingRedirect flag]", redirectTo: safeRedirectTo,
); });
authDispatch({ type: "AuthClearPendingRedirect" }); authDispatch({ type: "AuthClearPendingRedirect" });
router.replace(ROUTES.chat); router.replace(safeRedirectTo);
} }
}, [state.loginStatus, state.pendingRedirect, authDispatch, router]); }, [
state.loginStatus,
state.pendingRedirect,
authDispatch,
router,
safeRedirectTo,
]);
return ( return (
<MobileShell> <MobileShell>
@@ -53,3 +64,9 @@ export function AuthScreen() {
</MobileShell> </MobileShell>
); );
} }
function getSafeRedirectPath(redirectTo: string | null | undefined): string | null {
if (!redirectTo) return null;
if (!redirectTo.startsWith("/") || redirectTo.startsWith("//")) return null;
return redirectTo;
}
+13 -4
View File
@@ -1,7 +1,16 @@
"use client";
import { AuthScreen } from "@/app/auth/auth-screen"; import { AuthScreen } from "@/app/auth/auth-screen";
export default function AuthPage() { interface AuthPageProps {
return <AuthScreen />; searchParams: Promise<{
redirect?: string | string[];
}>;
}
export default async function AuthPage({ searchParams }: AuthPageProps) {
const params = await searchParams;
const redirectTo = Array.isArray(params.redirect)
? params.redirect[0]
: params.redirect;
return <AuthScreen redirectTo={redirectTo ?? null} />;
} }
+7 -2
View File
@@ -133,7 +133,12 @@ export function ChatScreen() {
} }
function handleUnlockImagePaywall(): void { function handleUnlockImagePaywall(): void {
router.push(`${ROUTES.subscription}?type=vip`); const subscriptionUrl = ROUTE_BUILDERS.subscription("vip");
if (isGuest) {
router.push(ROUTE_BUILDERS.authWithRedirect(subscriptionUrl));
return;
}
router.push(subscriptionUrl);
} }
function handleMessageLimitUnlock(): void { function handleMessageLimitUnlock(): void {
@@ -141,7 +146,7 @@ export function ChatScreen() {
router.push(ROUTES.auth); router.push(ROUTES.auth);
return; return;
} }
router.push(`${ROUTES.subscription}?type=vip`); router.push(ROUTE_BUILDERS.subscription("vip"));
} }
return ( return (
+4
View File
@@ -30,6 +30,10 @@ export type StaticRoute = (typeof ROUTES)[keyof typeof ROUTES];
export const ROUTE_BUILDERS = { export const ROUTE_BUILDERS = {
chatDeviceId: (deviceId: string): `/chat/deviceid/${string}` => chatDeviceId: (deviceId: string): `/chat/deviceid/${string}` =>
`/chat/deviceid/${encodeURIComponent(deviceId)}` as const, `/chat/deviceid/${encodeURIComponent(deviceId)}` as const,
subscription: (type: "vip" | "voice"): `/subscription?type=${string}` =>
`${ROUTES.subscription}?type=${encodeURIComponent(type)}` as const,
authWithRedirect: (redirectTo: string): `/auth?redirect=${string}` =>
`${ROUTES.auth}?redirect=${encodeURIComponent(redirectTo)}` as const,
} as const; } as const;
/** 仅未登录态可见的路由(命中后已登录用户应跳走) */ /** 仅未登录态可见的路由(命中后已登录用户应跳走) */