import { create } from "zustand"; import { authServiceClient, userServiceClient, userSettingServiceClient } from "@/grpcweb"; import { User } from "@/types/proto/api/v1/user_service"; import { UserSetting } from "@/types/proto/api/v1/user_setting_service"; interface UserState { userMapById: Record; userSettingMapById: Record; currentUserId?: number; // User related actions. fetchUserList: () => Promise; fetchCurrentUser: () => Promise; getOrFetchUserById: (id: number) => Promise; getUserById: (id: number) => User; getCurrentUser: () => User; setCurrentUserId: (id: number) => void; createUser: (create: Partial) => Promise; patchUser: (userPatch: Partial) => Promise; deleteUser: (id: number) => Promise; // User setting related actions. fetchUserSetting: (userId: number) => Promise; updateUserSetting: (userSetting: UserSetting, updateMask: string[]) => Promise; getCurrentUserSetting: () => UserSetting; } const useUserStore = create()((set, get) => ({ userMapById: {}, userSettingMapById: {}, fetchUserList: async () => { const { users } = await userServiceClient.listUsers({}); const userMap = get().userMapById; users.forEach((user) => { userMap[user.id] = user; }); set(userMap); return users; }, fetchCurrentUser: async () => { const { user } = await authServiceClient.getAuthStatus({}); if (!user) { throw new Error("User not found"); } const userMap = get().userMapById; userMap[user.id] = user; set({ userMapById: userMap, currentUserId: user.id }); return user; }, getOrFetchUserById: async (id: number) => { const userMap = get().userMapById; if (userMap[id]) { return userMap[id] as User; } const { user } = await userServiceClient.getUser({ id: id, }); if (!user) { throw new Error("User not found"); } userMap[id] = user; set(userMap); return user; }, createUser: async (userCreate: Partial) => { const { user } = await userServiceClient.createUser({ user: userCreate, }); if (!user) { throw new Error("User not found"); } const userMap = get().userMapById; userMap[user.id] = user; set(userMap); return user; }, patchUser: async (userPatch: Partial) => { const { user } = await userServiceClient.updateUser({ user: userPatch, updateMask: ["email", "nickname"], }); if (!user) { throw new Error("User not found"); } const userMap = get().userMapById; userMap[user.id] = user; set(userMap); }, deleteUser: async (userId: number) => { await userServiceClient.deleteUser({ id: userId, }); const userMap = get().userMapById; delete userMap[userId]; set(userMap); }, getUserById: (id: number) => { const userMap = get().userMapById; return userMap[id] || unknownUser; }, getCurrentUser: () => { const userMap = get().userMapById; const currentUserId = get().currentUserId; return userMap[currentUserId as number]; }, setCurrentUserId: (id: number) => { set({ currentUserId: id, }); }, fetchUserSetting: async (userId: number) => { const userSetting = ( await userSettingServiceClient.getUserSetting({ id: userId, }) ).userSetting as UserSetting; const userSettingMap = get().userSettingMapById; userSettingMap[userId] = userSetting; set(userSettingMap); return userSetting; }, updateUserSetting: async (userSetting: UserSetting, updateMask: string[]) => { const userId = userSetting.id; const updatedUserSetting = ( await userSettingServiceClient.updateUserSetting({ id: userId, userSetting, updateMask, }) ).userSetting as UserSetting; const userSettingMap = get().userSettingMapById; userSettingMap[userId] = updatedUserSetting; set(userSettingMap); return updatedUserSetting; }, getCurrentUserSetting: () => { const userSettingMap = get().userSettingMapById; const currentUserId = get().currentUserId; return userSettingMap[currentUserId as number]; }, })); const unknownUser: User = User.fromPartial({ id: -1, email: "Unknown", nickname: "Unknown", }); export default useUserStore;