import { create as batshitCreate, keyResolver } from "@yornaath/batshit"; import { create } from "zustand"; import { immer } from "zustand/middleware/immer"; import { getUser } from "~/lib/api/client/user"; import type { FullUser, PartialUser, UserId } from "~/lib/api/types"; type UsersStore = { users: Record; currentUserId: UserId | undefined; fetchUsersIfNotPresent: (userIds: UserId[]) => Promise; addUser: (user: PartialUser) => void; removeUser: (userId: UserId) => void; setCurrentUserId: (userId: UserId) => void; getCurrentUser: () => FullUser | undefined; }; const usersFetcher = batshitCreate({ fetcher: async (userIds: UserId[]) => { const users = []; for (const userId of userIds) { users.push(getUser(userId)); } return await Promise.all(users); }, resolver: keyResolver("id"), }); export const useUsersStore = create()( immer((set, get) => ({ users: {}, currentUserId: undefined, fetchUsersIfNotPresent: async (userIds) => { const userPromises: Promise[] = []; for (const userId of userIds) { const user = get().users[userId]; if (!user) { userPromises.push(usersFetcher.fetch(userId)); } } const users = await Promise.all(userPromises); const activeUsers = users.filter(Boolean); set((state) => { for (const user of activeUsers) { if (user?.id) state.users[user.id] = user; } }); }, addUser: (user) => set((state) => { if (user.id !== get().currentUserId) state.users[user.id] = user; else { const currentUser = get().users[user.id]; if (currentUser) state.users[user.id] = { ...currentUser, ...user }; else state.users[user.id] = user; } }), removeUser: (userId) => set((state) => { delete state.users[userId]; }), setCurrentUserId: (userId) => set((state) => { state.currentUserId = userId; }), getCurrentUser: () => (get().currentUserId ? (get().users[get().currentUserId!] as FullUser) : undefined), })), );