mirror of https://github.com/buster-so/buster.git
start moving chats to react query
This commit is contained in:
parent
912d0e855d
commit
c69030fcc6
|
@ -55,3 +55,16 @@ export const updateOrganizationUser = async ({
|
||||||
.put<OrganizationUser>(`/users/${userId}`, params)
|
.put<OrganizationUser>(`/users/${userId}`, params)
|
||||||
.then((response) => response.data);
|
.then((response) => response.data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const inviteUser = async ({
|
||||||
|
emails,
|
||||||
|
team_ids
|
||||||
|
}: {
|
||||||
|
emails: string[];
|
||||||
|
team_ids?: string[];
|
||||||
|
}) => {
|
||||||
|
return mainApi.post(`/users/invite`, {
|
||||||
|
emails,
|
||||||
|
team_ids
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
@ -61,11 +61,6 @@ export type UserRequestUserList = BusterSocketRequestBase<
|
||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export type UserInvite = BusterSocketRequestBase<
|
|
||||||
'/users/invite',
|
|
||||||
{ emails: string[]; team_ids?: null | string[] }
|
|
||||||
>;
|
|
||||||
|
|
||||||
export type UserEmits =
|
export type UserEmits =
|
||||||
| UserColorsList
|
| UserColorsList
|
||||||
| UserColorsCreate
|
| UserColorsCreate
|
||||||
|
@ -75,5 +70,4 @@ export type UserEmits =
|
||||||
| UsersFavoriteList
|
| UsersFavoriteList
|
||||||
| UserFavoriteDelete
|
| UserFavoriteDelete
|
||||||
| UserUpdateFavorites
|
| UserUpdateFavorites
|
||||||
| UserRequestUserList
|
| UserRequestUserList;
|
||||||
| UserInvite;
|
|
||||||
|
|
|
@ -60,20 +60,3 @@ export function useSocketQueryEmitAndOnce<
|
||||||
...options
|
...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;
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
|
|
|
@ -79,24 +79,3 @@ const defaultCallback = <TData, TRoute extends BusterSocketResponseRoute>(
|
||||||
currentData: TData | null,
|
currentData: TData | null,
|
||||||
d: InferBusterSocketResponseData<TRoute>
|
d: InferBusterSocketResponseData<TRoute>
|
||||||
) => d as TData;
|
) => 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 [];
|
|
||||||
// });
|
|
||||||
// };
|
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
import { queryOptions } from '@tanstack/react-query';
|
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 type { GetChatListParams } from '@/api/request_interfaces/chats';
|
||||||
|
import { IBusterChat, IBusterChatMessage } from '@/context/Chats';
|
||||||
|
|
||||||
const chatsGetChat = (chatId: string) =>
|
const chatsGetChat = (chatId: string) =>
|
||||||
queryOptions<BusterChat>({
|
queryOptions<IBusterChat>({
|
||||||
queryKey: ['chats', 'get', chatId] as const,
|
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) =>
|
const chatsGetList = (filters?: GetChatListParams) =>
|
||||||
|
@ -15,27 +22,7 @@ const chatsGetList = (filters?: GetChatListParams) =>
|
||||||
});
|
});
|
||||||
|
|
||||||
export const chatQueryKeys = {
|
export const chatQueryKeys = {
|
||||||
'/chats/get:getChat': chatsGetChat,
|
chatsGetChat,
|
||||||
'/chats/list:getChatsList': chatsGetList
|
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);
|
|
||||||
|
|
||||||
// //
|
|
||||||
// };
|
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ChatProvider } from './ChatProvider';
|
import { ChatProvider } from './ChatProvider';
|
||||||
import { BusterNewChatProvider } from './NewChatProvider';
|
import { BusterNewChatProvider } from './NewChatProvider';
|
||||||
import { BusterChatListProvider } from './ChatListProvider';
|
|
||||||
|
|
||||||
export const BusterChatProvider = React.memo(({ children }: { children: React.ReactNode }) => {
|
export const BusterChatProvider = React.memo(({ children }: { children: React.ReactNode }) => {
|
||||||
return (
|
return (
|
||||||
<ChatProvider>
|
<ChatProvider>
|
||||||
<BusterChatListProvider>
|
<BusterNewChatProvider>{children}</BusterNewChatProvider>
|
||||||
<BusterNewChatProvider>{children}</BusterNewChatProvider>
|
|
||||||
</BusterChatListProvider>
|
|
||||||
</ChatProvider>
|
</ChatProvider>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
|
||||||
};
|
|
|
@ -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;
|
|
||||||
}, {});
|
|
||||||
};
|
|
|
@ -1 +1 @@
|
||||||
export * from './ChatListProvider';
|
export * from './useBusterChatListByFilter';
|
||||||
|
|
|
@ -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
|
||||||
|
};
|
||||||
|
};
|
|
@ -2,7 +2,7 @@ import { useMemoizedFn } from 'ahooks';
|
||||||
import { useSocketQueryMutation } from '@/api/buster_socket_query';
|
import { useSocketQueryMutation } from '@/api/buster_socket_query';
|
||||||
import { queryKeys } from '@/api/query_keys';
|
import { queryKeys } from '@/api/query_keys';
|
||||||
|
|
||||||
const getChatsListOptions = queryKeys['/chats/list:getChatsList']();
|
const getChatsListOptions = queryKeys['chatsGetList']();
|
||||||
|
|
||||||
export const useChatAssosciations = () => {
|
export const useChatAssosciations = () => {
|
||||||
const { mutate: deleteChat } = useSocketQueryMutation(
|
const { mutate: deleteChat } = useSocketQueryMutation(
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
import { useBusterNewChatContextSelector } from './NewChatProvider';
|
import { useBusterNewChatContextSelector } from './NewChatProvider';
|
||||||
import { useBusterChatContextSelector } from './ChatProvider';
|
import { useBusterChatContextSelector } from './ChatProvider';
|
||||||
import { useBusterChatListContextSelector } from './ChatListProvider';
|
import { useBusterChatListByFilter } from './ChatListProvider';
|
||||||
|
|
||||||
export * from './BusterChatProvider';
|
export * from './BusterChatProvider';
|
||||||
|
|
||||||
export {
|
export { useBusterNewChatContextSelector, useBusterChatContextSelector, useBusterChatListByFilter };
|
||||||
useBusterNewChatContextSelector,
|
|
||||||
useBusterChatContextSelector,
|
|
||||||
useBusterChatListContextSelector
|
|
||||||
};
|
|
||||||
export * from './interfaces';
|
export * from './interfaces';
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export * from './DashboardListProvider';
|
export * from './useBusterDashboardListByFilter';
|
||||||
export * from './interfaces';
|
export * from './interfaces';
|
||||||
|
|
|
@ -1,18 +1,14 @@
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { useBusterWebSocket } from '../BusterWebSocket';
|
|
||||||
import { timeout } from '@/utils';
|
import { timeout } from '@/utils';
|
||||||
import { useBusterNotifications } from '../BusterNotifications';
|
import { useBusterNotifications } from '../BusterNotifications';
|
||||||
|
import { inviteUser as inviteUserRest } from '@/api/buster_rest';
|
||||||
|
|
||||||
export const useInviteUser = () => {
|
export const useInviteUser = () => {
|
||||||
const busterSocket = useBusterWebSocket();
|
|
||||||
const { openSuccessMessage } = useBusterNotifications();
|
const { openSuccessMessage } = useBusterNotifications();
|
||||||
|
|
||||||
const inviteUsers = useMemoizedFn(async (emails: string[], team_ids?: string[]) => {
|
const inviteUsers = useMemoizedFn(async (emails: string[], team_ids?: string[]) => {
|
||||||
busterSocket.emit({
|
await inviteUserRest({ emails, team_ids });
|
||||||
route: '/users/invite',
|
await timeout(100);
|
||||||
payload: { emails, team_ids }
|
|
||||||
});
|
|
||||||
await timeout(350);
|
|
||||||
openSuccessMessage('Invites sent');
|
openSuccessMessage('Invites sent');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue