Files
cozsweet-frontend-nextjs/src/stores/auth/machine/auth-context.tsx
T
admin 47591be41c refactor(auth): unify Facebook and Google login into AuthPlatform class
Replace the separate FacebookLogin and GoogleLogin classes with a single
AuthPlatform class that takes a provider name ("facebook" | "google") as a
constructor argument. This consolidates duplicate OAuth sign-in logic behind
one entry point while preserving the existing NextAuth flow.

- Add new src/lib/auth/auth_platform.ts exporting AuthPlatform and
  AuthProvider type
- Update auth-facebook-panel.tsx and splash-button.tsx to use the new API
- Rename initialContext → initialState in the auth machine for consistency
- Update inline docs and comments to reference AuthPlatform

No behavioral change for end users; both providers still route through
NextAuth's signIn() with the same callbacks and cookies.
2026-06-10 18:58:15 +08:00

87 lines
2.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
/**
* AuthContext:基于 XState v5 的 React Context Provider
*
* 业务事件(`Auth*Submitted`)通过 `useMachine(authMachine).send()` 派发。
* XState 自动处理异步副作用(invoke + fromPromise actors)。
*
* 兼容性:保持原 `useAuthState()` / `useAuthDispatch()` API
* 内部将 XState 状态机快照映射回原 `AuthState` 形状。
*/
import {
type Dispatch,
type ReactNode,
createContext,
useContext,
useMemo,
} from "react";
import { useMachine } from "@xstate/react";
import { authMachine } from "./auth-machine";
import type { AuthEvent, AuthState as MachineContext } from "./auth-machine";
/**
* 对外暴露的 State 形状(保持与原 AuthState 兼容)
*/
interface AuthState {
authPanelMode: MachineContext["authPanelMode"];
authMode: MachineContext["authMode"];
email: string;
password: string;
username: string;
confirmPassword: string;
isLoading: boolean;
errorMessage: string | null;
isSuccess: boolean;
loginType: MachineContext["loginType"];
}
const AuthStateCtx = createContext<AuthState | null>(null);
const AuthDispatchCtx = createContext<Dispatch<AuthEvent> | null>(null);
export interface AuthProviderProps {
children: ReactNode;
}
export function AuthProvider({ children }: AuthProviderProps) {
const [state, send] = useMachine(authMachine);
// 映射 XState 状态机快照 → 原 AuthState 形状
const authState = useMemo<AuthState>(
() => ({
authPanelMode: state.context.authPanelMode,
authMode: state.context.authMode,
email: state.context.email,
password: state.context.password,
username: state.context.username,
confirmPassword: state.context.confirmPassword,
// isLoading 仅来自邮箱登录 actor(社交登录改由 NextAuth 处理,UI 自行管 busy 状态)
isLoading: state.matches("loadingEmailLogin") ||
state.matches("loadingEmailRegister"),
errorMessage: state.context.errorMessage,
isSuccess: state.matches("success"),
loginType: state.context.loginType,
}),
[state],
);
return (
<AuthStateCtx.Provider value={authState}>
<AuthDispatchCtx.Provider value={send}>{children}</AuthDispatchCtx.Provider>
</AuthStateCtx.Provider>
);
}
export function useAuthState(): AuthState {
const ctx = useContext(AuthStateCtx);
if (!ctx) throw new Error("useAuthState must be used inside <AuthProvider>");
return ctx;
}
export function useAuthDispatch(): Dispatch<AuthEvent> {
const ctx = useContext(AuthDispatchCtx);
if (!ctx)
throw new Error("useAuthDispatch must be used inside <AuthProvider>");
return ctx;
}