fix:splash 界面重定向界面问题

This commit is contained in:
2026-06-11 17:00:04 +08:00
parent e3d549d660
commit 1151a9a61b
7 changed files with 144 additions and 94 deletions
+9 -12
View File
@@ -21,7 +21,7 @@ import { authMachine } from "./auth-machine";
import type { AuthEvent, AuthState as MachineContext } from "./auth-machine";
/**
* 对外暴露的 State 形状(保持与原 AuthState 兼容)
* 对外暴露的 State 形状
*/
interface AuthState {
authPanelMode: MachineContext["authPanelMode"];
@@ -32,16 +32,14 @@ interface AuthState {
confirmPassword: string;
isLoading: boolean;
errorMessage: string | null;
/**
* 字段名 `isSuccess` 保留(接口兼容),语义改为:
* true = 用户**已登录**loginStatus ∈ {email, google, facebook, apple, guest}
* false = 未登录(loginStatus === "notLoggedIn"
*
* 之前用 `state.matches("success")` 当信号 —— 但 status check 流也会误入
* success,触发 splash-button 误跳 /chat。现改用 `loginStatus` 判定。
*/
isSuccess: boolean;
/** 当前登录状态(未登录 / 游客 / OAuth / 邮箱) */
loginStatus: MachineContext["loginStatus"];
/**
* 一次性的"刚按了"信号 —— Skip / Facebook / 邮箱登录按钮派完业务事件后置 true,
* splash-screen / auth-screen 看到 `pendingRedirect && loginStatus !== "notLoggedIn"`
* 触发跳转 + 调 `AuthClearPendingRedirect` 置 false。
*/
pendingRedirect: boolean;
}
const AuthStateCtx = createContext<AuthState | null>(null);
@@ -70,9 +68,8 @@ export function AuthProvider({ children }: AuthProviderProps) {
state.matches("loadingOAuth") ||
state.matches("loadingGuestLogin"),
errorMessage: state.context.errorMessage,
// 改用 loginStatus 判断"已登录"(避开 success state 误触发)
isSuccess: state.context.loginStatus !== "notLoggedIn",
loginStatus: state.context.loginStatus,
pendingRedirect: state.context.pendingRedirect,
}),
[state],
);
+6 -1
View File
@@ -33,4 +33,9 @@ export type AuthEvent =
// OAuth 回调后:把 OAuth provider token 转交后端换业务 token
// 由 <OAuthSessionSync /> 监听 useSession() 派发
| { type: "AuthGoogleSyncSubmitted"; idToken: string }
| { type: "AuthFacebookSyncSubmitted"; accessToken: string };
| { type: "AuthFacebookSyncSubmitted"; accessToken: string }
// ──────────────────────────────────────────────────────────────────────
// splash / auth screen 跳完 /chat 后**清**"刚按了"信号(一次性):
// `pendingRedirect` 在 login onDone action 里**自动**置 true(不是按钮派的)
// —— 因此**只**需要 `AuthClearPendingRedirect` 一个事件
| { type: "AuthClearPendingRedirect" };
+25 -6
View File
@@ -154,7 +154,15 @@ const checkAuthStatusActor = fromPromise<LoginStatus, void>(async () => {
// 设计:所有登录/同步流跑完都回 `idle`(带正确 `loginStatus`)。
// **不**再设 `success` state —— 之前曾用 "success" 当"刚成功"信号,
// 但 status check 流也会误入 success,触发 splash-button 误跳 /chat。
// 现在改用 `loginStatus !== "notLoggedIn"` 作为"已登录"信号(见 auth-context.tsx)。
//
// `pendingRedirect: boolean`"用户**显式**触发了登录"信号)——
// **在登录成功的 onDone 里自动置 true**
// splash / auth screen 看到 `pendingRedirect && loginStatus !== "notLoggedIn"` 跳 /chat
// 跳完派 `AuthClearPendingRedirect` 置 false
// checkingAuthStatus **不**设 flag —— 被动查 token 不算"用户意图"。
//
// 注:onDone 用了**内联**assign(不是 helper function)—— XState v5 的 TypeScript
// 推断对 helper return type 不友好;内联能保留 `state.matches("loadingXxx")` 的类型。
// ============================================================
export const authMachine = setup({
types: {
@@ -217,6 +225,10 @@ export const authMachine = setup({
errorMessage: "Apple login not implemented",
}),
},
// splash / auth screen 跳完 /chat 后**清**flag
AuthClearPendingRedirect: {
actions: assign({ pendingRedirect: false }),
},
},
},
@@ -228,6 +240,7 @@ export const authMachine = setup({
target: "idle", // ← status check 完回 idle**不**再假冒 success
actions: assign({
loginStatus: ({ event }) => event.output,
// **不**置 pendingRedirect —— 状态查询是**被动**读 token,不算"用户意图"
errorMessage: null,
}),
},
@@ -246,9 +259,11 @@ export const authMachine = setup({
invoke: {
src: "guestLogin",
onDone: {
target: "idle", // ← 改自 "success"
target: "idle",
// 内联 assign —— XState v5 type inference 保留 loadingGuestLogin state 类型
actions: assign({
loginStatus: ({ event }) => event.output,
pendingRedirect: true, // ← 显式登录成功 → splash / auth 看到跳 /chat
errorMessage: null,
}),
},
@@ -271,9 +286,10 @@ export const authMachine = setup({
return { email: event.email, password: event.password };
},
onDone: {
target: "idle", // ← 改自 "success"
target: "idle",
actions: assign({
loginStatus: ({ event }) => event.output,
pendingRedirect: true, // ← 邮箱登录成功 → 跳
errorMessage: null,
}),
},
@@ -301,9 +317,10 @@ export const authMachine = setup({
};
},
onDone: {
target: "idle", // ← 改自 "success"
target: "idle",
actions: assign({
loginStatus: ({ event }) => event.output,
pendingRedirect: true, // ← 注册成功 → 跳
errorMessage: null,
}),
},
@@ -348,9 +365,10 @@ export const authMachine = setup({
return { idToken: event.idToken };
},
onDone: {
target: "idle", // ← 改自 "success"
target: "idle",
actions: assign({
loginStatus: ({ event }) => event.output,
pendingRedirect: true, // ← OAuth sync 成功 → 跳
errorMessage: null,
}),
},
@@ -373,9 +391,10 @@ export const authMachine = setup({
return { accessToken: event.accessToken };
},
onDone: {
target: "idle", // ← 改自 "success"
target: "idle",
actions: assign({
loginStatus: ({ event }) => event.output,
pendingRedirect: true, // ← OAuth sync 成功 → 跳
errorMessage: null,
}),
},
+10
View File
@@ -17,6 +17,15 @@ export interface AuthState {
errorMessage: string | null;
/** 当前登录状态(未登录 / 游客 / OAuth / 邮箱) */
loginStatus: LoginStatus;
/**
* **一次性的"刚按了"信号** —— Skip / Facebook / 邮箱登录按钮**刚**派事件 → 置 true
* → splash-screen / auth-screen 看到 `pendingRedirect && loginStatus !== "notLoggedIn"` 触发跳转
* → 跳完置 false
*
* 历史:之前用 useRef 做 transition detection**但** re-mount 时 ref 重置,bug 复发。
* 现**在 auth state 里持久**machine 不重置)—— re-mount 时也能区分"刚按"和"历史"。
*/
pendingRedirect: boolean;
}
export const initialState: AuthState = {
@@ -28,4 +37,5 @@ export const initialState: AuthState = {
confirmPassword: "",
errorMessage: null,
loginStatus: "notLoggedIn",
pendingRedirect: false,
};