import { useMutation } from '@tanstack/react-query'; import { AxiosError } from 'axios'; import { List as ImmutableList, Map as ImmutableMap } from 'immutable'; import sumBy from 'lodash/sumBy'; import React, { useEffect, useState } from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { useHistory } from 'react-router-dom'; import { createSelector } from 'reselect'; import { openChat, launchChat, toggleMainWindow } from 'soapbox/actions/chats'; import { getSettings } from 'soapbox/actions/settings'; import snackbar from 'soapbox/actions/snackbar'; import AccountSearch from 'soapbox/components/account_search'; import { Avatar, Button, Counter, HStack, Icon, IconButton, Input, Spinner, Stack, Text } from 'soapbox/components/ui'; import VerificationBadge from 'soapbox/components/verification_badge'; import { ChatProvider, useChatContext } from 'soapbox/contexts/chat-context'; import AudioToggle from 'soapbox/features/chats/components/audio-toggle'; import PlaceholderAccount from 'soapbox/features/placeholder/components/placeholder_account'; import { useAppDispatch, useAppSelector, useDebounce, useSettings } from 'soapbox/hooks'; import { IChat, useChats } from 'soapbox/queries/chats'; import useAccountSearch from 'soapbox/queries/search'; import { RootState } from 'soapbox/store'; import { Chat } from 'soapbox/types/entities'; import ChatList from './chat-list'; import ChatPaneHeader from './chat-pane-header'; import ChatWindow from './chat-window'; import { Pane, WindowState } from './ui'; const messages = defineMessages({ searchPlaceholder: { id: 'chats.search_placeholder', defaultMessage: 'Type a name' }, }); const getChatsUnreadCount = (state: RootState) => { const chats = state.chats.items; return chats.reduce((acc, curr) => acc + Math.min(curr.get('unread', 0), 1), 0); }; // Filter out invalid chats const normalizePanes = (chats: ImmutableMap, panes = ImmutableList>()) => ( panes.filter(pane => chats.get(pane.get('chat_id'))) ); const makeNormalizeChatPanes = () => createSelector([ (state: RootState) => state.chats.items, (state: RootState) => getSettings(state).getIn(['chats', 'panes']) as any, ], normalizePanes); const normalizeChatPanes = makeNormalizeChatPanes(); const ChatPane = () => { const intl = useIntl(); const dispatch = useAppDispatch(); const debounce = useDebounce; const { chat, setChat } = useChatContext(); const [value, setValue] = useState(); const debouncedValue = debounce(value as string, 300); const { chatsQuery: { data: chats, isFetching }, getOrCreateChatByAccountId } = useChats(); const { data: accounts } = useAccountSearch(debouncedValue); const panes = useAppSelector((state) => normalizeChatPanes(state)); const mainWindowState = useSettings().getIn(['chats', 'mainWindow']) as WindowState; const unreadCount = sumBy(chats, (chat) => chat.unread); const open = mainWindowState === 'open'; const isSearching = accounts && accounts.length > 0; const hasSearchValue = value && value.length > 0; const handleClickOnSearchResult = useMutation((accountId: string) => { return getOrCreateChatByAccountId(accountId); }, { onError: (error: AxiosError) => { const data = error.response?.data as any; dispatch(snackbar.error(data?.error)); }, onSuccess: (response) => { setChat(response.data); }, }); const clearValue = () => { if (hasSearchValue) { setValue(''); } }; const handleMainWindowToggle = () => { if (mainWindowState === 'open') { setChat(null); } dispatch(toggleMainWindow()); }; const renderBody = () => { if (isFetching) { return (
); } else if (isSearching) { return ( {accounts.map((account: any) => ( ))} ); } else if (chats && chats.length > 0) { return ( {chats.map((chat) => ( ))} ); } else { return ( No messages yet You can start a conversation with anyone that follows you. ); } }; return (
{chat?.id ? ( setChat(null)} closePane={handleMainWindowToggle} /> ) : ( <> {open ? (
setValue(event.target.value)} isSearch append={ } />
{renderBody()}
) : null} )}
{/* {panes.map((pane, i) => ( ))} */}
); }; export default ChatPane;