refactor(auth): migrate social login to next-auth
This commit is contained in:
@@ -3,11 +3,8 @@
|
||||
*
|
||||
* 原始 Dart: lib/ui/auth/bloc/auth_bloc.dart + auth_state.dart + auth_event.dart
|
||||
*
|
||||
* 设计要点:
|
||||
* - 使用 XState v5 `setup({...}).createMachine({...})` 声明式 API
|
||||
* - 异步副作用用 `fromPromise` actor 包装(自动取消、错误捕获)
|
||||
* - 表单字段值放在 `context`,UI 通过事件更新
|
||||
* - 保持事件类型名与原 Dart 一致,便于业务层迁移对照
|
||||
* 本轮迁移:社交登录改由 NextAuth 处理(`@/lib/auth/nextauth`),状态机仅保留
|
||||
* 邮箱注册/登录 + 通用 reset 事件。社交登录直接 `await nextauth.googleLogin()` 即可。
|
||||
*/
|
||||
import { setup, fromPromise, assign } from "xstate";
|
||||
|
||||
@@ -16,10 +13,6 @@ import type { AuthPanelMode } from "@/models/auth/auth-panel-mode";
|
||||
import type { LoginType } from "@/models/auth/login-type";
|
||||
import { authRepository } from "@/data/repositories/auth_repository";
|
||||
import { AuthStorage } from "@/data/storage/auth/auth_storage";
|
||||
import {
|
||||
loginWithFacebook,
|
||||
getFacebookUserData,
|
||||
} from "@/integrations/facebook-sdk";
|
||||
import { Result } from "@/utils/result";
|
||||
|
||||
// ============================================================
|
||||
@@ -67,18 +60,14 @@ export type AuthEvent =
|
||||
username: string;
|
||||
confirmPassword: string;
|
||||
}
|
||||
// 社交登录(已迁移到 NextAuth)— 业务层直接 await nextauth.googleLogin() 即可
|
||||
| { type: "AuthGoogleLoginSubmitted" }
|
||||
| { type: "AuthFacebookLoginSubmitted" }
|
||||
| { type: "AuthAppleLoginSubmitted" }
|
||||
| { type: "AuthWebGoogleLoginSuccess"; idToken: string; email: string };
|
||||
| { type: "AuthAppleLoginSubmitted" };
|
||||
|
||||
// ============================================================
|
||||
// Helpers
|
||||
// ============================================================
|
||||
/**
|
||||
* 从存储读取 guestId,失败或缺失返回 undefined
|
||||
* 用 if 语句避免 TS 联合类型 narrowing 问题
|
||||
*/
|
||||
async function readGuestId(): Promise<string | undefined> {
|
||||
const r = await AuthStorage.getInstance().getDeviceId();
|
||||
if (r.success && r.data != null) {
|
||||
@@ -118,37 +107,6 @@ const emailRegisterThenLoginActor = fromPromise<
|
||||
return "email" as LoginType;
|
||||
});
|
||||
|
||||
const googleLoginActor = fromPromise<LoginType, { idToken: string }>(async ({ input }) => {
|
||||
const guestId = await readGuestId();
|
||||
const result = await authRepository.googleLogin({ idToken: input.idToken, guestId });
|
||||
if (Result.isErr(result)) throw result.error;
|
||||
return "google" as LoginType;
|
||||
});
|
||||
|
||||
const facebookLoginActor = fromPromise<LoginType, Record<string, never>>(
|
||||
async () => {
|
||||
const guestId = await readGuestId();
|
||||
|
||||
const fbResult = await loginWithFacebook();
|
||||
if (Result.isErr(fbResult)) throw fbResult.error;
|
||||
|
||||
const authResult = await authRepository.facebookLogin({
|
||||
accessToken: fbResult.data.accessToken,
|
||||
guestId,
|
||||
});
|
||||
if (Result.isErr(authResult)) throw authResult.error;
|
||||
|
||||
// best-effort:异步上传 Facebook 头像
|
||||
void (async () => {
|
||||
const userData = await getFacebookUserData();
|
||||
if (Result.isOk(userData) && userData.data.pictureUrl) {
|
||||
// TODO: 调用 userStorage.setAvatarUrl
|
||||
}
|
||||
})();
|
||||
return "facebook" as LoginType;
|
||||
},
|
||||
);
|
||||
|
||||
// ============================================================
|
||||
// Machine
|
||||
// ============================================================
|
||||
@@ -160,8 +118,6 @@ export const authMachine = setup({
|
||||
actors: {
|
||||
emailLogin: emailLoginActor,
|
||||
emailRegisterThenLogin: emailRegisterThenLoginActor,
|
||||
googleLogin: googleLoginActor,
|
||||
facebookLogin: facebookLoginActor,
|
||||
},
|
||||
}).createMachine({
|
||||
id: "auth",
|
||||
@@ -196,18 +152,15 @@ export const authMachine = setup({
|
||||
},
|
||||
AuthEmailLoginSubmitted: "loadingEmailLogin",
|
||||
AuthEmailRegisterSubmitted: "loadingEmailRegister",
|
||||
AuthGoogleLoginSubmitted: {
|
||||
actions: assign({
|
||||
errorMessage: "Use the Google button to sign in on web",
|
||||
}),
|
||||
},
|
||||
AuthFacebookLoginSubmitted: "loadingFacebookLogin",
|
||||
// 社交登录已迁移到 NextAuth,业务层直接 await nextauth.googleLogin() / nextauth.facebookLogin()
|
||||
// 状态机保留事件以兼容旧调用方(实际不再触发)
|
||||
AuthGoogleLoginSubmitted: {},
|
||||
AuthFacebookLoginSubmitted: {},
|
||||
AuthAppleLoginSubmitted: {
|
||||
actions: assign({
|
||||
errorMessage: "Apple login not implemented",
|
||||
}),
|
||||
},
|
||||
AuthWebGoogleLoginSuccess: "loadingWebGoogleLogin",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -266,55 +219,8 @@ export const authMachine = setup({
|
||||
},
|
||||
},
|
||||
|
||||
loadingFacebookLogin: {
|
||||
invoke: {
|
||||
src: "facebookLogin",
|
||||
input: () => ({}),
|
||||
onDone: {
|
||||
target: "success",
|
||||
actions: assign({
|
||||
loginType: ({ event }) => event.output,
|
||||
errorMessage: null,
|
||||
}),
|
||||
},
|
||||
onError: {
|
||||
target: "idle",
|
||||
actions: assign({
|
||||
errorMessage: ({ event }) =>
|
||||
event.error instanceof Error ? event.error.message : String(event.error),
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
loadingWebGoogleLogin: {
|
||||
invoke: {
|
||||
src: "googleLogin",
|
||||
input: ({ event }) => {
|
||||
if (event.type !== "AuthWebGoogleLoginSuccess")
|
||||
return { idToken: "" };
|
||||
return { idToken: event.idToken };
|
||||
},
|
||||
onDone: {
|
||||
target: "success",
|
||||
actions: assign({
|
||||
loginType: ({ event }) => event.output,
|
||||
errorMessage: null,
|
||||
}),
|
||||
},
|
||||
onError: {
|
||||
target: "idle",
|
||||
actions: assign({
|
||||
errorMessage: ({ event }) =>
|
||||
event.error instanceof Error ? event.error.message : String(event.error),
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
success: {
|
||||
// 终态:业务层通过 state.matches("success") 判断
|
||||
// isSuccess 由 context 推算(loginType !== "none")
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user