♻️ refactor: refactor to get user info from api (#7444)

* support get user info from api

* fix

* Update client.ts
This commit is contained in:
Arvin Xu
2025-04-16 23:21:55 +08:00
committed by GitHub
parent 4006721bff
commit 4c1fb4a084
6 changed files with 60 additions and 19 deletions
+13 -1
View File
@@ -62,10 +62,15 @@ export class UserModel {
getUserState = async (decryptor: DecryptUserKeyVaults) => {
const result = await this.db
.select({
avatar: users.avatar,
email: users.email,
firstName: users.firstName,
fullName: users.fullName,
isOnboarded: users.isOnboarded,
lastName: users.lastName,
preference: users.preference,
settingsDefaultAgent: userSettings.defaultAgent,
settingsGeneral: userSettings.general,
settingsHotkey: userSettings.hotkey,
settingsKeyVaults: userSettings.keyVaults,
@@ -73,6 +78,7 @@ export class UserModel {
settingsSystemAgent: userSettings.systemAgent,
settingsTTS: userSettings.tts,
settingsTool: userSettings.tool,
username: users.username,
})
.from(users)
.where(eq(users.id, this.userId))
@@ -105,10 +111,16 @@ export class UserModel {
};
return {
avatar: state.avatar || undefined,
email: state.email || undefined,
firstName: state.firstName || undefined,
fullName: state.fullName || undefined,
isOnboarded: state.isOnboarded,
lastName: state.lastName || undefined,
preference: state.preference as UserPreference,
settings,
userId: this.userId,
username: state.username || undefined,
};
};
@@ -1,7 +1,7 @@
'use client';
import { useSession } from 'next-auth/react';
import { memo } from 'react';
import { memo, useEffect } from 'react';
import { createStoreUpdater } from 'zustand-utils';
import { useUserStore } from '@/store/user';
@@ -17,20 +17,27 @@ const UserUpdater = memo(() => {
const nextUser = session?.user;
const useStoreUpdater = createStoreUpdater(useUserStore);
const lobeUser = {
avatar: nextUser?.image,
email: nextUser?.email,
fullName: nextUser?.name,
id: nextUser?.id,
} as LobeUser;
useStoreUpdater('isLoaded', isLoaded);
useStoreUpdater('user', lobeUser);
useStoreUpdater('isSignedIn', isSignedIn);
useStoreUpdater('nextSession', session);
useStoreUpdater('nextUser', nextUser);
// 使用 useEffect 处理需要保持同步的用户数据
useEffect(() => {
if (nextUser) {
const userAvatar = useUserStore.getState().user?.avatar;
const lobeUser = {
// 头像使用设置的,而不是从 next-auth 中获取
avatar: userAvatar || '',
email: nextUser.email,
fullName: nextUser.name,
id: nextUser.id,
} as LobeUser;
// 更新用户相关数据
useUserStore.setState({ nextUser: nextUser, user: lobeUser });
}
}, [nextUser]);
return null;
});
+9 -2
View File
@@ -85,17 +85,24 @@ export const userRouter = router({
const hasExtraSession = await sessionModel.hasMoreThanN(1);
return {
avatar: state.avatar,
canEnablePWAGuide: hasMoreThan4Messages,
canEnableTrace: hasMoreThan4Messages,
email: state.email,
firstName: state.firstName,
fullName: state.fullName,
// 有消息,或者创建过助手,则认为有 conversation
hasConversation: hasAnyMessages || hasExtraSession,
// always return true for community version
isOnboard: state.isOnboarded || true,
lastName: state.lastName,
preference: state.preference as UserPreference,
settings: state.settings,
userId: ctx.userId,
};
username: state.username,
} satisfies UserInitializationState;
}),
makeUserOnboarded: userProcedure.mutation(async ({ ctx }) => {
+5 -2
View File
@@ -39,18 +39,21 @@ export class ClientService extends BaseClientService implements IUserService {
encryptKeyVaultsStr ? JSON.parse(encryptKeyVaultsStr) : {},
);
const user = await UserModel.findById(clientDB as any, this.userId);
const messageCount = await this.messageModel.count();
const sessionCount = await this.sessionModel.count();
return {
...state,
avatar: user?.avatar as string,
avatar: state.avatar ?? '',
canEnablePWAGuide: messageCount >= 4,
canEnableTrace: messageCount >= 4,
firstName: state.firstName,
fullName: state.fullName,
hasConversation: messageCount > 0 || sessionCount > 0,
isOnboard: true,
lastName: state.lastName,
preference: await this.preferenceStorage.getFromLocalStorage(),
username: state.username,
};
};
+9 -2
View File
@@ -7,7 +7,7 @@ import { useOnlyFetchOnceSWR } from '@/libs/swr';
import { userService } from '@/services/user';
import type { UserStore } from '@/store/user';
import type { GlobalServerConfig } from '@/types/serverConfig';
import { UserInitializationState } from '@/types/user';
import { LobeUser, UserInitializationState } from '@/types/user';
import type { UserSettings } from '@/types/user/settings';
import { merge } from '@/utils/merge';
import { setNamespace } from '@/utils/storeDebug';
@@ -91,7 +91,14 @@ export const createCommonSlice: StateCreator<
// if there is avatar or userId (from client DB), update it into user
const user =
data.avatar || data.userId
? merge(get().user, { avatar: data.avatar, id: data.userId })
? merge(get().user, {
avatar: data.avatar,
firstName: data.firstName,
fullName: data.fullName,
id: data.userId,
latestName: data.lastName,
username: data.username,
} as LobeUser)
: get().user;
set(
+6 -1
View File
@@ -48,14 +48,19 @@ export interface UserInitializationState {
avatar?: string;
canEnablePWAGuide?: boolean;
canEnableTrace?: boolean;
email?: string;
firstName?: string;
fullName?: string;
hasConversation?: boolean;
isOnboard?: boolean;
lastName?: string;
preference: UserPreference;
settings: DeepPartial<UserSettings>;
userId?: string;
username?: string;
}
export const NextAuthAccountSchame = z.object({
provider: z.string(),
providerAccountId: z.string(),
});
});