start moving chats to react query

This commit is contained in:
Nate Kelley 2025-02-17 15:03:41 -07:00
parent 912d0e855d
commit c69030fcc6
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
15 changed files with 54 additions and 248 deletions

View File

@ -55,3 +55,16 @@ export const updateOrganizationUser = async ({
.put<OrganizationUser>(`/users/${userId}`, params)
.then((response) => response.data);
};
export const inviteUser = async ({
emails,
team_ids
}: {
emails: string[];
team_ids?: string[];
}) => {
return mainApi.post(`/users/invite`, {
emails,
team_ids
});
};

View File

@ -61,11 +61,6 @@ export type UserRequestUserList = BusterSocketRequestBase<
}
>;
export type UserInvite = BusterSocketRequestBase<
'/users/invite',
{ emails: string[]; team_ids?: null | string[] }
>;
export type UserEmits =
| UserColorsList
| UserColorsCreate
@ -75,5 +70,4 @@ export type UserEmits =
| UsersFavoriteList
| UserFavoriteDelete
| UserUpdateFavorites
| UserRequestUserList
| UserInvite;
| UserRequestUserList;

View File

@ -60,20 +60,3 @@ export function useSocketQueryEmitAndOnce<
...options
});
}
// const ExampleComponent = () => {
// const options = queryOptionsConfig['/chats/get:getChat']('123');
// const deleteChatInitialData = {
// id: '123'
// } as unknown as BusterChat;
// const { data } = useSocketQueryEmitAndOnce(
// { route: '/chats/get', payload: { id: '123' } },
// '/chats/get:getChat',
// options,
// (d, x) => {
// return deleteChatInitialData;
// }
// );
// };

View File

@ -79,24 +79,3 @@ const defaultCallback = <TData, TRoute extends BusterSocketResponseRoute>(
currentData: TData | null,
d: InferBusterSocketResponseData<TRoute>
) => d as TData;
// const _ExampleComponent = () => {
// const options = queryKeys['/chats/get:getChat']('123');
// const { data } = useSocketQueryOn('/chats/get:getChat', options);
// const options2 = queryKeys['/chats/list:getChatsList']();
// const { data: data2 } = useSocketQueryOn('/chats/list:getChatsList', options2);
// const options3 = queryKeys['/chats/delete:deleteChat']('123');
// // Create fresh options for delete chat that match the expected BusterChat type
// const deleteChatInitialData = {
// id: '123'
// } as unknown as BusterChat;
// const { data: data3 } = useSocketQueryOn('/chats/delete:deleteChat', options3, (d, x) => {
// d?.[0].is_favorited;
// x[0].id;
// return [];
// });
// };

View File

@ -1,11 +1,18 @@
import { queryOptions } from '@tanstack/react-query';
import type { BusterChat, BusterChatListItem } from '@/api/asset_interfaces';
import type { BusterChatListItem } from '@/api/asset_interfaces';
import type { GetChatListParams } from '@/api/request_interfaces/chats';
import { IBusterChat, IBusterChatMessage } from '@/context/Chats';
const chatsGetChat = (chatId: string) =>
queryOptions<BusterChat>({
queryOptions<IBusterChat>({
queryKey: ['chats', 'get', chatId] as const,
staleTime: 10 * 1000
staleTime: 60 * 1000 // 1 minute
});
const chatsMessages = (messageId: string) =>
queryOptions<IBusterChatMessage>({
queryKey: ['chats', 'messages', messageId] as const,
staleTime: Infinity
});
const chatsGetList = (filters?: GetChatListParams) =>
@ -15,27 +22,7 @@ const chatsGetList = (filters?: GetChatListParams) =>
});
export const chatQueryKeys = {
'/chats/get:getChat': chatsGetChat,
'/chats/list:getChatsList': chatsGetList
chatsGetChat,
chatsGetList,
chatsMessages
};
// const ExampleComponent = () => {
// const queryClient = useQueryClient();
// const options = chatQueryKeys['/chats/get:getChat']!('123');
// const queryKey = options.queryKey;
// const data = queryClient.getQueryData(queryKey);
// const { data: data2 } = useQuery(options);
// queryClient.setQueryData(queryKey, (d) => {
// return d;
// });
// const options2 = chatQueryKeys['/chats/list:getChatsList']!();
// const queryKey2 = options2.queryKey;
// const data3 = queryClient.getQueryData(queryKey2);
// //
// };

View File

@ -1,14 +1,11 @@
import React from 'react';
import { ChatProvider } from './ChatProvider';
import { BusterNewChatProvider } from './NewChatProvider';
import { BusterChatListProvider } from './ChatListProvider';
export const BusterChatProvider = React.memo(({ children }: { children: React.ReactNode }) => {
return (
<ChatProvider>
<BusterChatListProvider>
<BusterNewChatProvider>{children}</BusterNewChatProvider>
</BusterChatListProvider>
<BusterNewChatProvider>{children}</BusterNewChatProvider>
</ChatProvider>
);
});

View File

@ -1,144 +0,0 @@
import React, { PropsWithChildren, useEffect, useRef, useState } from 'react';
import {
createContext,
ContextSelector,
useContextSelector
} from '@fluentui/react-context-selector';
import { useBusterWebSocket } from '../../BusterWebSocket';
import { BusterChatListItem } from '@/api/asset_interfaces';
import { useMemoizedFn, useThrottleFn } from 'ahooks';
import { chatsArrayToRecord, createFilterRecord } from './helpers';
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
import { BusterRoutes } from '@/routes';
interface IChatList {
fetching: boolean;
fetched: boolean;
fetchedAt: number;
chatListIds: string[];
}
export const useBusterChatList = () => {
const busterSocket = useBusterWebSocket();
const [chatList, setChatList] = useState<Record<string, BusterChatListItem>>({});
const [chatListIds, setChatListIds] = useState<Record<string, IChatList>>({});
//STATE UPDATES
const onUpdateChatListItem = useMemoizedFn(
(newChat: Partial<BusterChatListItem> & { id: string }) => {
setChatList((prevChats) => {
return {
...prevChats,
[newChat.id]: {
...prevChats[newChat.id],
...newChat
}
};
});
}
);
const removeItemFromChatList = useMemoizedFn(({ chatId }: { chatId: string }) => {
setChatListIds((prevChatListIds) => {
const newChatListIds = { ...prevChatListIds };
Object.keys(newChatListIds).forEach((key) => {
newChatListIds[key] = {
...newChatListIds[key],
chatListIds: newChatListIds[key].chatListIds.filter((id) => id !== chatId)
};
});
return newChatListIds;
});
});
//LISTENERS
const _onInitializeListChats = useMemoizedFn(
(chats: BusterChatListItem[], admin_view: boolean) => {
const newChats = chatsArrayToRecord(chats);
const filterKey = createFilterRecord({ admin_view });
setChatList((prev) => ({
...prev,
...newChats
}));
setChatListIds((prev) => ({
...prev,
[filterKey]: {
fetching: false,
fetched: true,
fetchedAt: Date.now(),
chatListIds: Object.keys(newChats)
}
}));
}
);
const _getChatsList = useMemoizedFn(({ admin_view }: { admin_view: boolean }) => {
const recordKey = createFilterRecord({ admin_view });
if (chatListIds[recordKey]?.fetching) {
return;
}
setChatListIds((prev) => {
const foundRecord = prev[recordKey];
return {
...prev,
[recordKey]: {
fetching: true,
chatListIds: foundRecord?.chatListIds || [],
fetched: foundRecord?.fetched || false,
fetchedAt: foundRecord?.fetchedAt || 0
}
};
});
return busterSocket.emitAndOnce({
emitEvent: {
route: '/chats/list',
payload: {
page_token: 0,
page_size: 3000, //TODO: make a pagination
admin_view
}
},
responseEvent: {
route: '/chats/list:getChatsList',
callback: (v) => _onInitializeListChats(v, admin_view)
}
});
});
//ACTIONS
const { run: getChatsList } = useThrottleFn(_getChatsList, { wait: 350, leading: true });
return {
getChatsList,
chatList,
chatListIds,
onUpdateChatListItem,
removeItemFromChatList
};
};
const BusterChatList = createContext<ReturnType<typeof useBusterChatList>>(
{} as ReturnType<typeof useBusterChatList>
);
export const BusterChatListProvider: React.FC<PropsWithChildren> = React.memo(({ children }) => {
const chatListContext = useBusterChatList();
return <BusterChatList.Provider value={chatListContext}>{children}</BusterChatList.Provider>;
});
BusterChatListProvider.displayName = 'BusterChatListProvider';
export const useBusterChatListContextSelector = <T,>(
selector: ContextSelector<ReturnType<typeof useBusterChatList>, T>
) => {
return useContextSelector(BusterChatList, selector);
};

View File

@ -1,13 +0,0 @@
import { BusterChatListItem } from '@/api/asset_interfaces';
export const createFilterRecord = ({ admin_view }: { admin_view: boolean }): string => {
const adminViewString = admin_view ? 'admin_view' : 'non_admin_view';
return adminViewString;
};
export const chatsArrayToRecord = (chats: BusterChatListItem[]) => {
return chats.reduce<Record<string, BusterChatListItem>>((acc, chat) => {
acc[chat.id] = chat;
return acc;
}, {});
};

View File

@ -1 +1 @@
export * from './ChatListProvider';
export * from './useBusterChatListByFilter';

View File

@ -0,0 +1,18 @@
import { useSocketQueryEmitOn } from '@/api/buster_socket_query';
import { queryKeys } from '@/api/query_keys';
import { GetChatListParams } from '@/api/request_interfaces/chats';
export const useBusterChatListByFilter = (filters: GetChatListParams) => {
const { data: chatsList, isFetched: isFetchedChatsList } = useSocketQueryEmitOn(
{ route: '/chats/list', payload: { page_token: 0, page_size: 3000, admin_view: false } },
'/chats/list:getChatsList',
queryKeys['chatsGetList'](filters)
);
//ACTIONS
return {
list: chatsList,
isFetched: isFetchedChatsList
};
};

View File

@ -2,7 +2,7 @@ import { useMemoizedFn } from 'ahooks';
import { useSocketQueryMutation } from '@/api/buster_socket_query';
import { queryKeys } from '@/api/query_keys';
const getChatsListOptions = queryKeys['/chats/list:getChatsList']();
const getChatsListOptions = queryKeys['chatsGetList']();
export const useChatAssosciations = () => {
const { mutate: deleteChat } = useSocketQueryMutation(

View File

@ -1,12 +1,8 @@
import { useBusterNewChatContextSelector } from './NewChatProvider';
import { useBusterChatContextSelector } from './ChatProvider';
import { useBusterChatListContextSelector } from './ChatListProvider';
import { useBusterChatListByFilter } from './ChatListProvider';
export * from './BusterChatProvider';
export {
useBusterNewChatContextSelector,
useBusterChatContextSelector,
useBusterChatListContextSelector
};
export { useBusterNewChatContextSelector, useBusterChatContextSelector, useBusterChatListByFilter };
export * from './interfaces';

View File

@ -1,2 +1,2 @@
export * from './DashboardListProvider';
export * from './useBusterDashboardListByFilter';
export * from './interfaces';

View File

@ -1,18 +1,14 @@
import { useMemoizedFn } from 'ahooks';
import { useBusterWebSocket } from '../BusterWebSocket';
import { timeout } from '@/utils';
import { useBusterNotifications } from '../BusterNotifications';
import { inviteUser as inviteUserRest } from '@/api/buster_rest';
export const useInviteUser = () => {
const busterSocket = useBusterWebSocket();
const { openSuccessMessage } = useBusterNotifications();
const inviteUsers = useMemoizedFn(async (emails: string[], team_ids?: string[]) => {
busterSocket.emit({
route: '/users/invite',
payload: { emails, team_ids }
});
await timeout(350);
await inviteUserRest({ emails, team_ids });
await timeout(100);
openSuccessMessage('Invites sent');
});