diff --git a/app/soapbox/features/chats/components/chat-message-list-intro.tsx b/app/soapbox/features/chats/components/chat-message-list-intro.tsx index 6818fa739..dd5f4a479 100644 --- a/app/soapbox/features/chats/components/chat-message-list-intro.tsx +++ b/app/soapbox/features/chats/components/chat-message-list-intro.tsx @@ -27,7 +27,7 @@ const ChatMessageListIntro = () => { }; const handleReportChat = () => { - dispatch(initReport(chat?.account)); + dispatch(initReport(chat?.account as any)); acceptChat.mutate(); }; diff --git a/app/soapbox/features/chats/components/chat-message-list.tsx b/app/soapbox/features/chats/components/chat-message-list.tsx index dc20c9467..447e9aeec 100644 --- a/app/soapbox/features/chats/components/chat-message-list.tsx +++ b/app/soapbox/features/chats/components/chat-message-list.tsx @@ -7,8 +7,7 @@ import React, { useState, useEffect, useRef, useLayoutEffect } from 'react'; import { useIntl, defineMessages } from 'react-intl'; import { openModal } from 'soapbox/actions/modals'; -import { initReportById } from 'soapbox/actions/reports'; -import { Avatar, Divider, HStack, Spinner, Stack, Text } from 'soapbox/components/ui'; +import { Avatar, Button, Divider, HStack, Spinner, Stack, Text } from 'soapbox/components/ui'; import DropdownMenuContainer from 'soapbox/containers/dropdown_menu_container'; // import emojify from 'soapbox/features/emoji/emoji'; import PlaceholderChatMessage from 'soapbox/features/placeholder/components/placeholder-chat-message'; @@ -68,10 +67,21 @@ const ChatMessageList: React.FC = ({ chat, autosize }) => { const [scrollPosition, setScrollPosition] = useState(0); const { deleteChatMessage, markChatAsRead } = useChat(chat.id); - const { data: chatMessages, isLoading, isFetching, isFetched, fetchNextPage, isFetchingNextPage, isPlaceholderData } = useChatMessages(chat.id); + const { + data: chatMessages, + fetchNextPage, + isError, + isFetched, + isFetching, + isFetchingNextPage, + isLoading, + isPlaceholderData, + refetch, + } = useChatMessages(chat.id); const formattedChatMessages = chatMessages || []; - const me = useAppSelector(state => state.me); + const me = useAppSelector((state) => state.me); + const isBlocked = useAppSelector((state) => state.getIn(['relationships', chat.account, 'blocked_by'])); const node = useRef(null); const messagesEnd = useRef(null); @@ -89,16 +99,14 @@ const ChatMessageList: React.FC = ({ chat, autosize }) => { }; const getFormattedTimestamp = (chatMessage: ChatMessageEntity) => { - return intl.formatDate( - new Date(chatMessage.created_at), { + return intl.formatDate(new Date(chatMessage.created_at), { hour12: false, year: 'numeric', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit', - }, - ); + }); }; const setBubbleRef = (c: HTMLDivElement) => { @@ -295,7 +303,7 @@ const ChatMessageList: React.FC = ({ chat, autosize }) => {
- +
@@ -383,6 +391,44 @@ const ChatMessageList: React.FC = ({ chat, autosize }) => { ); } + if (isBlocked) { + return ( + + + + + <> + You are blocked by + {' '} + @{chat.account.acct} + + + + + ); + } + + if (isError) { + return ( + + + + Whoops! + + We encountered a network failure. + + + +
+ +
+
+
+ ); + } + return (
{/* style={{ height: autosize ? 'calc(100vh - 16rem)' : undefined }} */} {!isLoading ? ( diff --git a/app/soapbox/features/chats/components/chat-settings.tsx b/app/soapbox/features/chats/components/chat-settings.tsx index bd7dda913..02c0b9dfe 100644 --- a/app/soapbox/features/chats/components/chat-settings.tsx +++ b/app/soapbox/features/chats/components/chat-settings.tsx @@ -31,7 +31,7 @@ const ChatSettings = () => { message: 'Blocking will prevent this profile from direct messaging you and viewing your content. You can unblock later.', confirm: 'Block', confirmationTheme: 'primary', - onConfirm: () => dispatch(blockAccount(chat?.account.id)), + onConfirm: () => dispatch(blockAccount(chat?.account.id as string)), })); }; @@ -48,7 +48,7 @@ const ChatSettings = () => { }; const handleReportChat = () => { - dispatch(initReport(chat?.account)); + dispatch(initReport(chat?.account as any)); }; if (!chat) { diff --git a/app/soapbox/queries/accounts.ts b/app/soapbox/queries/accounts.ts new file mode 100644 index 000000000..7c1e1b106 --- /dev/null +++ b/app/soapbox/queries/accounts.ts @@ -0,0 +1,24 @@ +export type IAccount = { + acct: string + avatar: string + avatar_static: string + bot: boolean + created_at: string + discoverable: boolean + display_name: string + followers_count: number + following_count: number + group: boolean + header: string + header_static: string + id: string + last_status_at: string + location: string + locked: boolean + note: string + statuses_count: number + url: string + username: string + verified: boolean + website: string +} \ No newline at end of file diff --git a/app/soapbox/queries/chats.ts b/app/soapbox/queries/chats.ts index 8c7e214b6..f8b187b30 100644 --- a/app/soapbox/queries/chats.ts +++ b/app/soapbox/queries/chats.ts @@ -1,12 +1,15 @@ import { useInfiniteQuery, useMutation } from '@tanstack/react-query'; import { useEffect, useState } from 'react'; +import { fetchRelationships } from 'soapbox/actions/accounts'; import snackbar from 'soapbox/actions/snackbar'; import { useChatContext } from 'soapbox/contexts/chat-context'; import { useApi, useAppDispatch } from 'soapbox/hooks'; import { queryClient } from './client'; +import type { IAccount } from './accounts'; + export interface IChat { id: string unread: number @@ -24,7 +27,7 @@ export interface IChat { updated_at: Date accepted: boolean discarded_at: null | string - account: any + account: IAccount } export interface IChatMessage { @@ -88,9 +91,10 @@ const useChatMessages = (chatId: string) => { const useChats = () => { const api = useApi(); + const dispatch = useAppDispatch(); const getChats = async(pageParam?: any): Promise<{ result: IChat[], maxId: string, hasMore: boolean }> => { - const { data, headers } = await api.get('/api/v1/pleroma/chats', { + const { data, headers } = await api.get('/api/v1/pleroma/chats', { params: { max_id: pageParam?.maxId, }, @@ -99,6 +103,9 @@ const useChats = () => { const hasMore = !!headers.link; const nextMaxId = data[data.length - 1]?.id; + // Set the relationships to these users in the redux store. + dispatch(fetchRelationships(data.map((item) => item.account.id))); + return { result: data, maxId: nextMaxId, diff --git a/app/soapbox/queries/suggestions.ts b/app/soapbox/queries/suggestions.ts index d5ddf07bf..b89603b13 100644 --- a/app/soapbox/queries/suggestions.ts +++ b/app/soapbox/queries/suggestions.ts @@ -5,34 +5,11 @@ import { importFetchedAccounts } from 'soapbox/actions/importer'; import { getLinks } from 'soapbox/api'; import { useApi, useAppDispatch } from 'soapbox/hooks'; -type Account = { - acct: string - avatar: string - avatar_static: string - bot: boolean - created_at: string - discoverable: boolean - display_name: string - followers_count: number - following_count: number - group: boolean - header: string - header_static: string - id: string - last_status_at: string - location: string - locked: boolean - note: string - statuses_count: number - url: string - username: string - verified: boolean - website: string -} +import type { IAccount } from './accounts'; type Suggestion = { source: 'staff' - account: Account + account: IAccount }