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.
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
/**
|
||||
* Auth 状态机:Context 形状 + 初始值
|
||||
* Auth 状态机:State 形状 + 初始值
|
||||
*/
|
||||
import type { AuthMode } from "@/models/auth/auth-mode";
|
||||
import type { AuthPanelMode } from "@/models/auth/auth-panel-mode";
|
||||
import type { LoginType } from "@/models/auth/login-type";
|
||||
|
||||
export interface AuthContext {
|
||||
export interface AuthState {
|
||||
/** 当前面板模式(Facebook / Email) */
|
||||
authPanelMode: AuthPanelMode;
|
||||
/** 内部登录模式(login / register) */
|
||||
@@ -18,7 +18,7 @@ export interface AuthContext {
|
||||
loginType: LoginType;
|
||||
}
|
||||
|
||||
export const initialContext: AuthContext = {
|
||||
export const initialState: AuthState = {
|
||||
authPanelMode: "facebook",
|
||||
authMode: "login",
|
||||
email: "",
|
||||
@@ -7,4 +7,4 @@
|
||||
* - Context 形状与初始值由 `auth-context.ts` 导出
|
||||
* - `AuthState` 由 `auth-context.tsx` 导出(保持原 API 兼容)
|
||||
*/
|
||||
export type { AuthEvent } from "./auth-events";
|
||||
export type { AuthEvent } from "./machine/auth-events";
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
* - 事件联合位于 auth-events.ts
|
||||
* - machine / 类型 / React 入口分别由对应文件导出
|
||||
*/
|
||||
export * from "./auth-state";
|
||||
export * from "./auth-context";
|
||||
export * from "./auth-events";
|
||||
export * from "./auth-machine";
|
||||
export * from "./machine/auth-events";
|
||||
export * from "./machine/auth-machine";
|
||||
export * from "./auth-types";
|
||||
|
||||
@@ -18,12 +18,12 @@ import {
|
||||
import { useMachine } from "@xstate/react";
|
||||
|
||||
import { authMachine } from "./auth-machine";
|
||||
import type { AuthEvent, AuthContext as MachineContext } from "./auth-machine";
|
||||
import type { AuthEvent, AuthState as MachineContext } from "./auth-machine";
|
||||
|
||||
/**
|
||||
* 对外暴露的 State 形状(保持与原 AuthState 兼容)
|
||||
*/
|
||||
export interface AuthState {
|
||||
interface AuthState {
|
||||
authPanelMode: MachineContext["authPanelMode"];
|
||||
authMode: MachineContext["authMode"];
|
||||
email: string;
|
||||
@@ -4,8 +4,8 @@
|
||||
* 原始 Dart: lib/ui/auth/bloc/auth_bloc.dart + auth_state.dart + auth_event.dart
|
||||
*
|
||||
* 本轮迁移:社交登录改由 NextAuth 处理(`@/lib/auth/nextauth`),状态机仅保留
|
||||
* 邮箱注册/登录 + 通用 reset 事件。社交登录走 `new GoogleLogin().signIn()` /
|
||||
* `new FacebookLogin().signIn()`。
|
||||
* 邮箱注册/登录 + 通用 reset 事件。社交登录走 `new AuthPlatform("google").signIn()` /
|
||||
* `new AuthPlatform("facebook").signIn()`。
|
||||
*/
|
||||
import { setup, fromPromise, assign } from "xstate";
|
||||
|
||||
@@ -14,12 +14,12 @@ import { authRepository } from "@/data/repositories/auth_repository";
|
||||
import { AuthStorage } from "@/data/storage/auth/auth_storage";
|
||||
import { Result } from "@/utils/result";
|
||||
|
||||
import { AuthContext, initialContext } from "./auth-context";
|
||||
import { AuthState, initialState } from "../auth-state";
|
||||
import type { AuthEvent } from "./auth-events";
|
||||
|
||||
// 重新导出 Context / Event 类型,保持 machine 文件的公共 API 不变
|
||||
export type { AuthContext } from "./auth-context";
|
||||
export { initialContext } from "./auth-context";
|
||||
// 重新导出 State / Event 类型,保持 machine 文件的公共 API 不变
|
||||
export type { AuthState } from "../auth-state";
|
||||
export { initialState } from "../auth-state";
|
||||
export type { AuthEvent } from "./auth-events";
|
||||
|
||||
// ============================================================
|
||||
@@ -73,7 +73,7 @@ const emailRegisterThenLoginActor = fromPromise<
|
||||
// ============================================================
|
||||
export const authMachine = setup({
|
||||
types: {
|
||||
context: {} as AuthContext,
|
||||
context: {} as AuthState,
|
||||
events: {} as AuthEvent,
|
||||
},
|
||||
actors: {
|
||||
@@ -83,7 +83,7 @@ export const authMachine = setup({
|
||||
}).createMachine({
|
||||
id: "auth",
|
||||
initial: "idle",
|
||||
context: initialContext,
|
||||
context: initialState,
|
||||
states: {
|
||||
idle: {
|
||||
on: {
|
||||
@@ -109,11 +109,11 @@ export const authMachine = setup({
|
||||
}),
|
||||
},
|
||||
AuthReset: {
|
||||
actions: assign(() => initialContext),
|
||||
actions: assign(() => initialState),
|
||||
},
|
||||
AuthEmailLoginSubmitted: "loadingEmailLogin",
|
||||
AuthEmailRegisterSubmitted: "loadingEmailRegister",
|
||||
// 社交登录已迁移到 NextAuth + GoogleLogin / FacebookLogin 类
|
||||
// 社交登录已迁移到 NextAuth + AuthPlatform 类
|
||||
// 状态机保留事件以兼容旧调用方(实际不再触发)
|
||||
AuthGoogleLoginSubmitted: {},
|
||||
AuthFacebookLoginSubmitted: {},
|
||||
@@ -20,13 +20,13 @@ import {
|
||||
} from "react";
|
||||
import { useMachine } from "@xstate/react";
|
||||
|
||||
import { chatMachine } from "./chat-machine";
|
||||
import type { ChatEvent, ChatContext as MachineContext } from "./chat-machine";
|
||||
import { chatMachine } from "./machine/chat-machine";
|
||||
import type { ChatEvent, ChatState as MachineContext } from "./machine/chat-machine";
|
||||
|
||||
/**
|
||||
* 对外暴露的 State 形状(保持与原 ChatState 兼容)
|
||||
*/
|
||||
export interface ChatState {
|
||||
interface ChatState {
|
||||
messages: MachineContext["messages"];
|
||||
isReplyingAI: boolean;
|
||||
isGuest: boolean;
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
* - `ChatState` 由 `chat-context.tsx` 导出(保持原 API 兼容)
|
||||
* - `GuestChatQuota` 仍由 `chat-machine.ts` 导出(业务常量,与上下文配对紧密)
|
||||
*/
|
||||
export type { ChatEvent } from "./chat-events";
|
||||
export type { ChatEvent } from "./machine/chat-events";
|
||||
export { GuestChatQuota } from "./chat-machine";
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
* 注:chat-side-effects.ts 暂未删除(其中 WebSocket 长生命周期逻辑
|
||||
* 待下一轮迁移到 fromCallback actor)。
|
||||
*/
|
||||
export * from "./machine/chat-state";
|
||||
export * from "./chat-context";
|
||||
export * from "./chat-events";
|
||||
export * from "./machine/chat-events";
|
||||
export * from "./chat-types";
|
||||
export { chatMachine } from "./chat-machine";
|
||||
|
||||
@@ -23,8 +23,8 @@ import { AuthStorage } from "@/data/storage/auth/auth_storage";
|
||||
import { formatDate } from "@/utils/date";
|
||||
import { Result } from "@/utils/result";
|
||||
|
||||
import { ChatContext, initialContext } from "./chat-context";
|
||||
import type { ChatEvent } from "./chat-events";
|
||||
import { ChatState, initialState } from "./chat-state";
|
||||
import type { ChatEvent } from "./machine/chat-events";
|
||||
|
||||
/** 游客配额阈值(与 Dart `GuestChatQuota` 保持一致) */
|
||||
export const GuestChatQuota = {
|
||||
@@ -32,10 +32,10 @@ export const GuestChatQuota = {
|
||||
quotaExhausted: 0,
|
||||
} as const;
|
||||
|
||||
// 重新导出 Context / Event 类型,保持 machine 文件的公共 API 不变
|
||||
export type { ChatContext } from "./chat-context";
|
||||
export { initialContext } from "./chat-context";
|
||||
export type { ChatEvent } from "./chat-events";
|
||||
// 重新导出 State / Event 类型,保持 machine 文件的公共 API 不变
|
||||
export type { ChatState } from "./chat-state";
|
||||
export { initialState } from "./chat-state";
|
||||
export type { ChatEvent } from "./machine/chat-events";
|
||||
|
||||
// ============================================================
|
||||
// Helpers
|
||||
@@ -146,7 +146,7 @@ const loadMoreHistoryActor = fromPromise<
|
||||
// ============================================================
|
||||
export const chatMachine = setup({
|
||||
types: {
|
||||
context: {} as ChatContext,
|
||||
context: {} as ChatState,
|
||||
events: {} as ChatEvent,
|
||||
},
|
||||
actors: {
|
||||
@@ -230,7 +230,7 @@ export const chatMachine = setup({
|
||||
}).createMachine({
|
||||
id: "chat",
|
||||
initial: "idle",
|
||||
context: initialContext,
|
||||
context: initialState,
|
||||
states: {
|
||||
idle: {
|
||||
on: {
|
||||
@@ -1,11 +1,11 @@
|
||||
/**
|
||||
* Chat 状态机:Context 形状 + 初始值
|
||||
* Chat 状态机:State 形状 + 初始值
|
||||
*
|
||||
* 注:GuestChatQuota 仍位于 chat-machine.ts(属于业务常量,与上下文配对紧密)。
|
||||
*/
|
||||
import type { UiMessage } from "@/models/chat/ui-message";
|
||||
|
||||
export interface ChatContext {
|
||||
export interface ChatState {
|
||||
messages: UiMessage[];
|
||||
isReplyingAI: boolean;
|
||||
isGuest: boolean;
|
||||
@@ -17,7 +17,7 @@ export interface ChatContext {
|
||||
historyOffset: number;
|
||||
}
|
||||
|
||||
export const initialContext: ChatContext = {
|
||||
export const initialState: ChatState = {
|
||||
messages: [],
|
||||
isReplyingAI: false,
|
||||
isGuest: true,
|
||||
@@ -8,7 +8,8 @@
|
||||
* - Context 形状与初始值位于 sidebar-context.ts
|
||||
* - 事件联合位于 sidebar-events.ts
|
||||
*/
|
||||
export * from "./sidebar-state";
|
||||
export * from "./sidebar-context";
|
||||
export * from "./sidebar-events";
|
||||
export * from "./sidebar-types";
|
||||
export { sidebarMachine } from "./sidebar-machine";
|
||||
export { sidebarMachine } from "./machine/sidebar-machine";
|
||||
|
||||
+6
-6
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
import { setup, assign } from "xstate";
|
||||
|
||||
import { SidebarContext, initialContext } from "./sidebar-context";
|
||||
import { SidebarState, initialState } from "../sidebar-state";
|
||||
import type { SidebarEvent } from "./sidebar-events";
|
||||
|
||||
/**
|
||||
@@ -36,9 +36,9 @@ export const BottomNavItem = {
|
||||
|
||||
export type BottomNavItem = (typeof BottomNavItem)[keyof typeof BottomNavItem];
|
||||
|
||||
// 重新导出 Context / Event 类型,保持 machine 文件的公共 API 不变
|
||||
export type { SidebarContext } from "./sidebar-context";
|
||||
export { initialContext } from "./sidebar-context";
|
||||
// 重新导出 State / Event 类型,保持 machine 文件的公共 API 不变
|
||||
export type { SidebarState } from "../sidebar-state";
|
||||
export { initialState } from "../sidebar-state";
|
||||
export type { SidebarEvent } from "./sidebar-events";
|
||||
|
||||
// ============================================================
|
||||
@@ -46,7 +46,7 @@ export type { SidebarEvent } from "./sidebar-events";
|
||||
// ============================================================
|
||||
export const sidebarMachine = setup({
|
||||
types: {
|
||||
context: {} as SidebarContext,
|
||||
context: {} as SidebarState,
|
||||
events: {} as SidebarEvent,
|
||||
},
|
||||
actions: {
|
||||
@@ -73,7 +73,7 @@ export const sidebarMachine = setup({
|
||||
}).createMachine({
|
||||
id: "sidebar",
|
||||
initial: "idle",
|
||||
context: initialContext,
|
||||
context: initialState,
|
||||
states: {
|
||||
/**
|
||||
* Sidebar 是纯数据状态(无异步副作用),仅用 idle 状态
|
||||
@@ -1,18 +1,18 @@
|
||||
/**
|
||||
* Sidebar 状态机:Context 形状 + 初始值
|
||||
* Sidebar 状态机:State 形状 + 初始值
|
||||
*
|
||||
* SidebarPage / BottomNavItem 仍由 sidebar-machine.ts 导出(事件/上下文均需引用)。
|
||||
*/
|
||||
import { SidebarPage, BottomNavItem } from "./sidebar-machine";
|
||||
import { SidebarPage, BottomNavItem } from "./machine/sidebar-machine";
|
||||
|
||||
export interface SidebarContext {
|
||||
export interface SidebarState {
|
||||
currentPage: SidebarPage;
|
||||
selectedBottomNavItem: BottomNavItem;
|
||||
characterName: string;
|
||||
characterProgress: number;
|
||||
}
|
||||
|
||||
export const initialContext: SidebarContext = {
|
||||
export const initialState: SidebarState = {
|
||||
currentPage: SidebarPage.DefaultView,
|
||||
selectedBottomNavItem: BottomNavItem.None,
|
||||
characterName: "Luna",
|
||||
@@ -17,16 +17,16 @@ import {
|
||||
} from "react";
|
||||
import { useMachine } from "@xstate/react";
|
||||
|
||||
import { sidebarMachine } from "./sidebar-machine";
|
||||
import { sidebarMachine } from "./machine/sidebar-machine";
|
||||
import type {
|
||||
SidebarContext as MachineContext,
|
||||
SidebarState as MachineContext,
|
||||
SidebarEvent,
|
||||
} from "./sidebar-machine";
|
||||
} from "./machine/sidebar-machine";
|
||||
|
||||
/**
|
||||
* 对外暴露的 State 形状(保持与原 SidebarState 兼容)
|
||||
*/
|
||||
export interface SidebarState {
|
||||
interface SidebarState {
|
||||
currentPage: MachineContext["currentPage"];
|
||||
selectedBottomNavItem: MachineContext["selectedBottomNavItem"];
|
||||
characterName: string;
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
* - Context 形状由 `sidebar-context.ts` 导出
|
||||
* - SidebarState 由 `sidebar-context.tsx` 导出(保持原 API 兼容)
|
||||
*/
|
||||
export { SidebarPage, BottomNavItem } from "./sidebar-machine";
|
||||
export { SidebarPage, BottomNavItem } from "./machine/sidebar-machine";
|
||||
export type { SidebarEvent } from "./sidebar-events";
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
* - Context 形状与初始值位于 user-context.ts
|
||||
* - 事件联合位于 user-events.ts
|
||||
*/
|
||||
export * from "./machine/user-state";
|
||||
export * from "./user-context";
|
||||
export * from "./user-events";
|
||||
export * from "./machine/user-events";
|
||||
export * from "./user-types";
|
||||
export { userMachine } from "./user-machine";
|
||||
|
||||
@@ -17,13 +17,13 @@ import { authRepository } from "@/data/repositories/auth_repository";
|
||||
import { UserStorage } from "@/data/storage/user/user_storage";
|
||||
import { Result } from "@/utils/result";
|
||||
|
||||
import { UserContext, initialContext } from "./user-context";
|
||||
import type { UserEvent } from "./user-events";
|
||||
import { UserState, initialState } from "./machine/user-state";
|
||||
import type { UserEvent } from "./machine/user-events";
|
||||
|
||||
// 重新导出 Context / Event 类型,保持 machine 文件的公共 API 不变
|
||||
export type { UserContext } from "./user-context";
|
||||
export { initialContext } from "./user-context";
|
||||
export type { UserEvent } from "./user-events";
|
||||
// 重新导出 State / Event 类型,保持 machine 文件的公共 API 不变
|
||||
export type { UserState } from "./machine/user-state";
|
||||
export { initialState } from "./machine/user-state";
|
||||
export type { UserEvent } from "./machine/user-events";
|
||||
|
||||
// ============================================================
|
||||
// Helpers
|
||||
@@ -102,7 +102,7 @@ const userLogoutActor = fromPromise<void>(async () => {
|
||||
// ============================================================
|
||||
export const userMachine = setup({
|
||||
types: {
|
||||
context: {} as UserContext,
|
||||
context: {} as UserState,
|
||||
events: {} as UserEvent,
|
||||
},
|
||||
actors: {
|
||||
@@ -136,7 +136,7 @@ export const userMachine = setup({
|
||||
}).createMachine({
|
||||
id: "user",
|
||||
initial: "idle",
|
||||
context: initialContext,
|
||||
context: initialState,
|
||||
states: {
|
||||
idle: {
|
||||
on: {
|
||||
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* User 状态机:Context 形状 + 初始值
|
||||
* User 状态机:State 形状 + 初始值
|
||||
*/
|
||||
import type { UserView } from "@/models/user/user";
|
||||
|
||||
export interface UserContext {
|
||||
export interface UserState {
|
||||
currentUser: UserView | null;
|
||||
pronouns: string;
|
||||
coinBalance: number;
|
||||
@@ -11,7 +11,7 @@ export interface UserContext {
|
||||
avatarUrl: string | null;
|
||||
}
|
||||
|
||||
export const initialContext: UserContext = {
|
||||
export const initialState: UserState = {
|
||||
currentUser: null,
|
||||
pronouns: "He",
|
||||
coinBalance: 45,
|
||||
@@ -18,12 +18,12 @@ import {
|
||||
import { useMachine } from "@xstate/react";
|
||||
|
||||
import { userMachine } from "./user-machine";
|
||||
import type { UserContext as MachineContext, UserEvent } from "./user-machine";
|
||||
import type { UserState as MachineContext, UserEvent } from "./user-machine";
|
||||
|
||||
/**
|
||||
* 对外暴露的 State 形状(保持与原 UserState 兼容)
|
||||
*/
|
||||
export interface UserState {
|
||||
interface UserState {
|
||||
currentUser: MachineContext["currentUser"];
|
||||
pronouns: string;
|
||||
coinBalance: number;
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
* - Context 形状与初始值由 `user-context.ts` 导出
|
||||
* - `UserState` 由 `user-context.tsx` 导出(保持原 API 兼容)
|
||||
*/
|
||||
export type { UserEvent } from "./user-events";
|
||||
export type { UserEvent } from "./machine/user-events";
|
||||
|
||||
Reference in New Issue
Block a user