bigbuffet-rw/app/soapbox/queries/chats.ts

262 lines
7 KiB
TypeScript
Raw Normal View History

2022-09-16 05:57:09 -07:00
import { useInfiniteQuery, useMutation, useQuery } from '@tanstack/react-query';
import { useState } from 'react';
2022-08-10 05:38:49 -07:00
2022-09-08 09:47:19 -07:00
import { fetchRelationships } from 'soapbox/actions/accounts';
2022-08-25 09:32:59 -07:00
import snackbar from 'soapbox/actions/snackbar';
2022-09-15 07:49:09 -07:00
import { getNextLink } from 'soapbox/api';
import compareId from 'soapbox/compare_id';
2022-08-16 10:38:17 -07:00
import { useChatContext } from 'soapbox/contexts/chat-context';
2022-09-22 14:04:52 -07:00
import { useApi, useAppDispatch, useFeatures } from 'soapbox/hooks';
import { normalizeChatMessage } from 'soapbox/normalizers';
import { flattenPages, updatePageItem } from 'soapbox/utils/queries';
2022-08-10 05:38:49 -07:00
2022-08-16 10:38:17 -07:00
import { queryClient } from './client';
2022-09-08 09:47:19 -07:00
import type { IAccount } from './accounts';
2022-08-10 05:38:49 -07:00
export interface IChat {
id: string
unread: number
2022-08-16 10:38:17 -07:00
created_by_account: string
2022-08-26 09:41:25 -07:00
last_message: null | {
account_id: string
chat_id: string
content: string
created_at: string
discarded_at: string | null
id: string
unread: boolean
}
2022-08-10 05:38:49 -07:00
created_at: Date
updated_at: Date
accepted: boolean
discarded_at: null | string
2022-09-08 09:47:19 -07:00
account: IAccount
2022-08-10 05:38:49 -07:00
}
export interface IChatMessage {
account_id: string
chat_id: string
content: string
created_at: Date
id: string
unread: boolean
2022-08-31 10:20:37 -07:00
pending?: boolean
2022-08-10 05:38:49 -07:00
}
2022-09-16 05:57:09 -07:00
export interface IChatSilence {
id: number
account_id: number
target_account_id: number
}
export interface PaginatedResult<T> {
result: T[],
hasMore: boolean,
link?: string,
}
const reverseOrder = (a: IChat, b: IChat): number => compareId(a.id, b.id);
2022-08-10 05:38:49 -07:00
const useChatMessages = (chatId: string) => {
const api = useApi();
const getChatMessages = async(chatId: string, pageParam?: any): Promise<PaginatedResult<IChatMessage>> => {
2022-09-15 07:49:09 -07:00
const nextPageLink = pageParam?.link;
const uri = nextPageLink || `/api/v1/pleroma/chats/${chatId}/messages`;
const response = await api.get(uri);
const { data } = response;
2022-08-10 05:38:49 -07:00
2022-09-15 07:49:09 -07:00
const link = getNextLink(response);
const hasMore = !!link;
const result = data.sort(reverseOrder).map(normalizeChatMessage);
2022-08-10 05:38:49 -07:00
return {
result,
2022-09-15 07:49:09 -07:00
link,
2022-08-10 05:38:49 -07:00
hasMore,
};
};
const queryInfo = useInfiniteQuery(['chats', 'messages', chatId], ({ pageParam }) => getChatMessages(chatId, pageParam), {
keepPreviousData: true,
getNextPageParam: (config) => {
if (config.hasMore) {
2022-09-15 07:49:09 -07:00
return { link: config.link };
2022-08-10 05:38:49 -07:00
}
return undefined;
},
});
2022-09-22 14:28:05 -07:00
const data = flattenPages(queryInfo);
2022-08-10 05:38:49 -07:00
return {
...queryInfo,
data,
};
};
2022-08-26 09:41:25 -07:00
2022-09-09 07:24:25 -07:00
const useChats = (search?: string) => {
2022-08-10 05:38:49 -07:00
const api = useApi();
2022-09-08 09:47:19 -07:00
const dispatch = useAppDispatch();
2022-09-22 14:04:52 -07:00
const features = useFeatures();
2022-08-10 05:38:49 -07:00
const getChats = async(pageParam?: any): Promise<PaginatedResult<IChat>> => {
2022-09-22 14:04:52 -07:00
const endpoint = features.chatsV2 ? '/api/v2/pleroma/chats' : '/api/v1/pleroma/chats';
2022-09-15 07:49:09 -07:00
const nextPageLink = pageParam?.link;
2022-09-22 14:04:52 -07:00
const uri = nextPageLink || endpoint;
2022-09-15 07:49:09 -07:00
const response = await api.get<IChat[]>(uri, {
2022-08-26 09:41:25 -07:00
params: {
2022-09-09 07:24:25 -07:00
search,
2022-08-26 09:41:25 -07:00
},
});
2022-09-15 07:49:09 -07:00
const { data } = response;
2022-08-26 09:41:25 -07:00
2022-09-15 07:49:09 -07:00
const link = getNextLink(response);
const hasMore = !!link;
2022-08-26 09:41:25 -07:00
2022-09-08 09:47:19 -07:00
// Set the relationships to these users in the redux store.
dispatch(fetchRelationships(data.map((item) => item.account.id)));
2022-08-26 09:41:25 -07:00
return {
result: data,
hasMore,
2022-09-15 07:49:09 -07:00
link,
2022-08-26 09:41:25 -07:00
};
2022-08-10 05:38:49 -07:00
};
const queryInfo = useInfiniteQuery(['chats', 'search', search], ({ pageParam }) => getChats(pageParam), {
2022-08-26 09:41:25 -07:00
keepPreviousData: true,
getNextPageParam: (config) => {
if (config.hasMore) {
2022-09-15 07:49:09 -07:00
return { link: config.link };
2022-08-26 09:41:25 -07:00
}
return undefined;
},
2022-08-10 05:38:49 -07:00
});
2022-09-22 14:28:05 -07:00
const data = flattenPages(queryInfo);
2022-08-26 09:41:25 -07:00
const chatsQuery = {
...queryInfo,
data,
};
2022-08-10 05:38:49 -07:00
const getOrCreateChatByAccountId = (accountId: string) => api.post<IChat>(`/api/v1/pleroma/chats/by-account-id/${accountId}`);
return { chatsQuery, getOrCreateChatByAccountId };
};
const useChat = (chatId: string) => {
const api = useApi();
2022-08-17 12:48:04 -07:00
const { setChat, setEditing } = useChatContext();
2022-08-10 05:38:49 -07:00
2022-08-30 07:10:31 -07:00
const markChatAsRead = (lastReadId: string) => {
api.post<IChat>(`/api/v1/pleroma/chats/${chatId}/read`, { last_read_id: lastReadId })
.then(({ data }) => updatePageItem(['chats', 'search'], data, (o, n) => o.id === n.id))
2022-08-30 07:10:31 -07:00
.catch(() => null);
};
2022-08-10 05:38:49 -07:00
const createChatMessage = (chatId: string, content: string) => {
return api.post<IChat>(`/api/v1/pleroma/chats/${chatId}/messages`, { content });
};
2022-08-16 05:39:58 -07:00
const deleteChatMessage = (chatMessageId: string) => api.delete<IChat>(`/api/v1/pleroma/chats/${chatId}/messages/${chatMessageId}`);
2022-08-16 10:38:17 -07:00
const acceptChat = useMutation(() => api.post<IChat>(`/api/v1/pleroma/chats/${chatId}/accept`), {
onSuccess(response) {
setChat(response.data);
queryClient.invalidateQueries(['chats', 'messages', chatId]);
queryClient.invalidateQueries(['chats', 'search']);
2022-08-16 10:38:17 -07:00
},
});
2022-08-16 10:54:36 -07:00
const deleteChat = useMutation(() => api.delete<IChat>(`/api/v1/pleroma/chats/${chatId}`), {
onSuccess(response) {
setChat(null);
2022-08-17 12:48:04 -07:00
setEditing(false);
2022-08-16 10:54:36 -07:00
queryClient.invalidateQueries(['chats', 'messages', chatId]);
queryClient.invalidateQueries(['chats', 'search']);
2022-08-16 10:54:36 -07:00
},
});
return { createChatMessage, markChatAsRead, deleteChatMessage, acceptChat, deleteChat };
2022-08-10 05:38:49 -07:00
};
2022-08-29 12:05:16 -07:00
const useChatSilences = () => {
2022-08-25 09:32:59 -07:00
const api = useApi();
2022-09-16 05:57:09 -07:00
const getChatSilences = async() => {
const { data } = await api.get<IChatSilence[]>('/api/v1/pleroma/chats/silences');
return data;
};
return useQuery<IChatSilence[]>(['chatSilences'], getChatSilences, {
placeholderData: [],
});
};
const useChatSilence = (chat: IChat | null) => {
const api = useApi();
2022-08-25 09:32:59 -07:00
const dispatch = useAppDispatch();
2022-08-29 12:05:16 -07:00
const [isSilenced, setSilenced] = useState<boolean>(false);
2022-08-25 09:32:59 -07:00
2022-08-29 12:05:16 -07:00
const getChatSilences = async() => {
const { data } = await api.get(`api/v1/pleroma/chats/silence?account_id=${chat?.account.id}`);
2022-08-25 09:32:59 -07:00
return data;
};
2022-08-29 12:05:16 -07:00
const fetchChatSilence = async() => {
const data = await getChatSilences();
2022-08-25 09:32:59 -07:00
if (data) {
2022-08-29 12:05:16 -07:00
setSilenced(true);
2022-09-13 13:24:19 -07:00
} else {
setSilenced(false);
2022-08-25 09:32:59 -07:00
}
};
2022-08-29 12:05:16 -07:00
const handleSilence = () => {
if (isSilenced) {
deleteSilence();
2022-08-25 09:32:59 -07:00
} else {
2022-08-29 12:05:16 -07:00
createSilence();
2022-08-25 09:32:59 -07:00
}
};
2022-08-29 12:05:16 -07:00
const createSilence = () => {
setSilenced(true);
2022-08-25 09:32:59 -07:00
2022-08-29 12:05:16 -07:00
api.post(`api/v1/pleroma/chats/silence?account_id=${chat?.account.id}`)
2022-08-25 09:32:59 -07:00
.then(() => {
2022-08-29 12:05:16 -07:00
dispatch(snackbar.success('Successfully silenced this chat.'));
2022-09-23 06:04:01 -07:00
queryClient.invalidateQueries(['chatSilences']);
2022-08-25 09:32:59 -07:00
})
.catch(() => {
2022-08-29 12:05:16 -07:00
dispatch(snackbar.error('Something went wrong trying to silence this chat. Please try again.'));
setSilenced(false);
2022-08-25 09:32:59 -07:00
});
};
2022-08-29 12:05:16 -07:00
const deleteSilence = () => {
setSilenced(false);
2022-08-25 09:32:59 -07:00
2022-08-29 12:05:16 -07:00
api.delete(`api/v1/pleroma/chats/silence?account_id=${chat?.account.id}`)
2022-08-25 09:32:59 -07:00
.then(() => {
2022-08-29 12:05:16 -07:00
dispatch(snackbar.success('Successfully unsilenced this chat.'));
2022-09-23 06:04:01 -07:00
queryClient.invalidateQueries(['chatSilences']);
2022-08-25 09:32:59 -07:00
})
.catch(() => {
2022-08-29 12:05:16 -07:00
dispatch(snackbar.error('Something went wrong trying to unsilence this chat. Please try again.'));
setSilenced(true);
2022-08-25 09:32:59 -07:00
});
};
return { isSilenced, handleSilence, fetchChatSilence };
2022-08-25 09:32:59 -07:00
};
2022-09-16 05:57:09 -07:00
export { useChat, useChats, useChatMessages, useChatSilences, useChatSilence };