Add error states
This commit is contained in:
parent
c48b4adc81
commit
1c179cd4a0
6 changed files with 93 additions and 39 deletions
|
@ -27,7 +27,7 @@ const ChatMessageListIntro = () => {
|
|||
};
|
||||
|
||||
const handleReportChat = () => {
|
||||
dispatch(initReport(chat?.account));
|
||||
dispatch(initReport(chat?.account as any));
|
||||
acceptChat.mutate();
|
||||
};
|
||||
|
||||
|
|
|
@ -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<IChatMessageList> = ({ 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<HTMLDivElement>(null);
|
||||
const messagesEnd = useRef<HTMLDivElement>(null);
|
||||
|
@ -89,16 +99,14 @@ const ChatMessageList: React.FC<IChatMessageList> = ({ 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<IChatMessageList> = ({ chat, autosize }) => {
|
|||
</div>
|
||||
|
||||
<div className={classNames({ 'order-1': !isMyMessage })}>
|
||||
<Avatar src={isMyMessage ? account?.avatar : chat.account.avatar} size={34} />
|
||||
<Avatar src={isMyMessage ? account?.avatar as string : chat.account.avatar as string} size={34} />
|
||||
</div>
|
||||
</HStack>
|
||||
</HStack>
|
||||
|
@ -383,6 +391,44 @@ const ChatMessageList: React.FC<IChatMessageList> = ({ chat, autosize }) => {
|
|||
);
|
||||
}
|
||||
|
||||
if (isBlocked) {
|
||||
return (
|
||||
<Stack alignItems='center' justifyContent='center' className='h-full flex-grow'>
|
||||
<Stack alignItems='center' space={2}>
|
||||
<Avatar src={chat.account.avatar_static} size={75} />
|
||||
<Text align='center'>
|
||||
<>
|
||||
<Text tag='span'>You are blocked by</Text>
|
||||
{' '}
|
||||
<Text tag='span' theme='primary'>@{chat.account.acct}</Text>
|
||||
</>
|
||||
</Text>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
if (isError) {
|
||||
return (
|
||||
<Stack alignItems='center' justifyContent='center' className='h-full flex-grow'>
|
||||
<Stack space={4}>
|
||||
<Stack space={1}>
|
||||
<Text size='lg' weight='bold' align='center'>Whoops!</Text>
|
||||
<Text theme='muted' align='center'>
|
||||
We encountered a network failure.
|
||||
</Text>
|
||||
</Stack>
|
||||
|
||||
<div className='mx-auto'>
|
||||
<Button theme='primary' onClick={() => refetch()}>
|
||||
Try again
|
||||
</Button>
|
||||
</div>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='h-full flex flex-col px-4 flex-grow overflow-y-scroll space-y-6' onScroll={handleScroll} ref={node}> {/* style={{ height: autosize ? 'calc(100vh - 16rem)' : undefined }} */}
|
||||
{!isLoading ? (
|
||||
|
|
|
@ -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) {
|
||||
|
|
24
app/soapbox/queries/accounts.ts
Normal file
24
app/soapbox/queries/accounts.ts
Normal file
|
@ -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
|
||||
}
|
|
@ -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<IChat[]>('/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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue