refactor(splash): handle Skip redirect in splash screen, decouple SplashButton
Previously, the Skip button (guest login entry) relied on the auth state machine's `pendingRedirect` flag to trigger the navigation to /chat after guest login completed. That introduced a non-obvious coupling: the button dispatched an event, the machine ran an actor, the auth screen (or splash useEffect) saw the flag and redirected. This refactor moves the redirect into the splash screen itself: - `SplashButton` now takes an `onSkip` prop and no longer knows about auth dispatch. Pure presentation component. - `SplashScreen` provides `handleSkip` that dispatches the `AuthGuestLoginSubmitted` event AND immediately calls `router.replace(/chat)` for snappier perceived navigation. - `auth-machine.ts`: `loadingGuestLogin.onDone` no longer sets `pendingRedirect: true` (splash already navigated). Sets it to `false` explicitly so other screens (auth, sidebar) that also react to `pendingRedirect` don't double-navigate if the user triggers guest login from a non-splash surface in the future. No behavior change for the happy path: Skip → /chat works the same. The refactor is purely about responsibility allocation and component decoupling.
This commit is contained in:
@@ -6,16 +6,15 @@ import { useAuthDispatch, useAuthState } from "@/stores/auth/auth-context";
|
||||
import { LoadingIndicator } from "@/app/_components/core/loading-indicator";
|
||||
import styles from "./splash-button.module.css";
|
||||
|
||||
export function SplashButton() {
|
||||
export interface SplashButtonProps {
|
||||
onSkip: () => void;
|
||||
}
|
||||
|
||||
export function SplashButton({ onSkip }: SplashButtonProps) {
|
||||
const state = useAuthState();
|
||||
const authDispatch = useAuthDispatch();
|
||||
const isLoading = state.isLoading;
|
||||
|
||||
// Skip = 显式游客登录入口("以游客身份继续")
|
||||
const handleSkip = () => {
|
||||
authDispatch({ type: "AuthGuestLoginSubmitted" });
|
||||
};
|
||||
|
||||
const handleFacebookLogin = () => {
|
||||
authDispatch({
|
||||
type: "AuthFacebookLoginSubmitted",
|
||||
@@ -25,10 +24,10 @@ export function SplashButton() {
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
{/* Skip 按钮 = 显式游客登录入口(派发 AuthGuestLoginSubmitted,不做路由跳转) */}
|
||||
{/* Skip 按钮 = 显式游客登录入口(派发事件 + 立即跳 /chat) */}
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleSkip}
|
||||
onClick={onSkip}
|
||||
disabled={isLoading}
|
||||
className={styles.skip}
|
||||
>
|
||||
|
||||
@@ -21,6 +21,11 @@ export function SplashScreen() {
|
||||
const authDispatch = useAuthDispatch();
|
||||
const userDispatch = useUserDispatch();
|
||||
|
||||
const handleSkip = () => {
|
||||
authDispatch({ type: "AuthGuestLoginSubmitted" });
|
||||
router.replace(ROUTES.chat);
|
||||
};
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// useEffect ① 启动时检查 localStorage 里的 loginToken:
|
||||
// - loginToken(OAuth/email sync 写下的)→ 视为"已登录"跳 /chat
|
||||
@@ -86,7 +91,7 @@ export function SplashScreen() {
|
||||
<div className={styles.spacer} />
|
||||
<SplashContent />
|
||||
<div className={styles.buttonArea}>
|
||||
<SplashButton />
|
||||
<SplashButton onSkip={handleSkip} />
|
||||
</div>
|
||||
{/*
|
||||
* 登录错误提示 —— auth state machine 的 onError 会设 errorMessage
|
||||
|
||||
@@ -134,7 +134,8 @@ export const authMachine = setup({
|
||||
// 内联 assign —— XState v5 type inference 保留 loadingGuestLogin state 类型
|
||||
actions: assign({
|
||||
loginStatus: ({ event }) => event.output,
|
||||
pendingRedirect: true, // ← 显式登录成功 → splash / auth 看到跳 /chat
|
||||
// Skip 点击后已在 splash 里立即跳 /chat;guest login 不再依赖 pendingRedirect。
|
||||
pendingRedirect: false,
|
||||
errorMessage: null,
|
||||
}),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user