From a2e2d60fc7aaafa1fe587f301a072e1e66cb4a80 Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 17 Aug 2022 15:48:04 -0400 Subject: [PATCH] Add Message List Intro component --- .../components/ui/button/useButtonStyles.ts | 2 +- app/soapbox/contexts/chat-context.tsx | 21 +++- .../features/chats/components/chat-box.tsx | 72 +----------- .../components/chat-message-list-intro.tsx | 109 ++++++++++++++++++ .../chats/components/chat-message-list.tsx | 19 ++- .../features/chats/components/chat-window.tsx | 12 +- app/soapbox/queries/chats.ts | 3 +- 7 files changed, 157 insertions(+), 81 deletions(-) create mode 100644 app/soapbox/features/chats/components/chat-message-list-intro.tsx diff --git a/app/soapbox/components/ui/button/useButtonStyles.ts b/app/soapbox/components/ui/button/useButtonStyles.ts index 286a7751f..ecec3de1f 100644 --- a/app/soapbox/components/ui/button/useButtonStyles.ts +++ b/app/soapbox/components/ui/button/useButtonStyles.ts @@ -25,7 +25,7 @@ const useButtonStyles = ({ tertiary: 'bg-transparent border-gray-400 dark:border-gray-800 hover:border-primary-300 dark:hover:border-primary-700 focus:border-primary-500 text-gray-900 dark:text-gray-100 focus:ring-primary-500', accent: 'border-transparent bg-secondary-500 hover:bg-secondary-400 focus:bg-secondary-500 text-gray-100 focus:ring-secondary-300', - danger: 'border-transparent bg-danger-600 text-gray-100 hover:bg-danger-500 dark:hover:bg-danger-700 focus:bg-danger-600 dark:focus:bg-danger-600', + danger: 'border-transparent bg-danger-100 dark:bg-danger-900 text-danger-600 dark:text-danger-200 hover:bg-danger-600 hover:text-gray-100 dark:hover:text-gray-100 dark:hover:bg-danger-500 focus:bg-danger-800 dark:focus:bg-danger-600', transparent: 'border-transparent text-gray-800 backdrop-blur-sm bg-white/75 hover:bg-white/80', outline: 'border-gray-100 border-2 bg-transparent text-gray-100 hover:bg-white/10', }; diff --git a/app/soapbox/contexts/chat-context.tsx b/app/soapbox/contexts/chat-context.tsx index 82d3106ab..6d8fbc4d4 100644 --- a/app/soapbox/contexts/chat-context.tsx +++ b/app/soapbox/contexts/chat-context.tsx @@ -1,8 +1,8 @@ -import React, { createContext, useContext, useState } from 'react'; +import React, { createContext, useContext, useMemo, useState } from 'react'; import { useDispatch } from 'react-redux'; import { toggleMainWindow } from 'soapbox/actions/chats'; -import { useSettings } from 'soapbox/hooks'; +import { useOwnAccount, useSettings } from 'soapbox/hooks'; import type { IChat } from 'soapbox/queries/chats'; @@ -12,23 +12,35 @@ const ChatContext = createContext({ chat: null, isOpen: false, isEditing: false, + needsAcceptance: false, }); const ChatProvider: React.FC = ({ children }) => { const dispatch = useDispatch(); const settings = useSettings(); + const account = useOwnAccount(); const [chat, setChat] = useState(null); const [isEditing, setEditing] = useState(false); const mainWindowState = settings.getIn(['chats', 'mainWindow']) as WindowState; - + const needsAcceptance = !chat?.accepted && chat?.created_by_account !== account?.id; const isOpen = mainWindowState === 'open'; const toggleChatPane = () => dispatch(toggleMainWindow()); + const value = useMemo(() => ({ + chat, + setChat, + needsAcceptance, + isOpen, + isEditing, + setEditing, + toggleChatPane, + }), [chat, needsAcceptance, isOpen, isEditing]); + return ( - + {children} ); @@ -38,6 +50,7 @@ interface IChatContext { chat: IChat | null isOpen: boolean isEditing: boolean + needsAcceptance: boolean setChat: React.Dispatch> setEditing: React.Dispatch> toggleChatPane(): void diff --git a/app/soapbox/features/chats/components/chat-box.tsx b/app/soapbox/features/chats/components/chat-box.tsx index 5f86c36bd..080e8df01 100644 --- a/app/soapbox/features/chats/components/chat-box.tsx +++ b/app/soapbox/features/chats/components/chat-box.tsx @@ -44,7 +44,7 @@ const ChatBox: React.FC = ({ chat, onSetInputRef, autosize, inputRef } const chatMessageIds = useAppSelector(state => state.chat_message_lists.get(chat.id, ImmutableOrderedSet())); const account = useOwnAccount(); - const { createChatMessage, markChatAsRead, acceptChat, deleteChat } = useChat(chat.id); + const { createChatMessage, markChatAsRead, acceptChat } = useChat(chat.id); const [content, setContent] = useState(''); const [attachment, setAttachment] = useState(undefined); @@ -54,8 +54,6 @@ const ChatBox: React.FC = ({ chat, onSetInputRef, autosize, inputRef } const inputElem = useRef(null); - const needsAcceptance = !chat.accepted && chat.created_by_account !== account?.id; - const isSubmitDisabled = content.length === 0 && !attachment; // TODO: needs last_read_id param @@ -188,23 +186,6 @@ const ChatBox: React.FC = ({ chat, onSetInputRef, autosize, inputRef } }); }; - const handleLeaveChat = () => { - dispatch(openModal('CONFIRM', { - heading: 'Leave Chat', - message: 'Are you sure you want to leave this chat? This conversation will be removed from your inbox.', - confirm: 'Leave Chat', - confirmationTheme: 'primary', - onConfirm: () => { - deleteChat.mutate(); - }, - })); - }; - - const handleReportChat = () => { - dispatch(initReport(chat.account)); - acceptChat.mutate(); - }; - const renderAttachment = () => { if (!attachment) return null; @@ -240,53 +221,8 @@ const ChatBox: React.FC = ({ chat, onSetInputRef, autosize, inputRef } return (
- {needsAcceptance ? ( - - - - - @{chat.account.acct} - {' '} - wants to start a chat with you - - - - - - - - - - - - - - ) : ( - - )} -
+ +
@@ -312,7 +248,7 @@ const ChatBox: React.FC = ({ chat, onSetInputRef, autosize, inputRef } />
-
+ // {renderAttachment()} // {isUploading && ( // diff --git a/app/soapbox/features/chats/components/chat-message-list-intro.tsx b/app/soapbox/features/chats/components/chat-message-list-intro.tsx new file mode 100644 index 000000000..1fa912111 --- /dev/null +++ b/app/soapbox/features/chats/components/chat-message-list-intro.tsx @@ -0,0 +1,109 @@ +import classNames from 'classnames'; +import React from 'react'; + +import { openModal } from 'soapbox/actions/modals'; +import { initReport } from 'soapbox/actions/reports'; +import { Avatar, Button, HStack, Icon, Stack, Text } from 'soapbox/components/ui'; +import { useChatContext } from 'soapbox/contexts/chat-context'; +import { useAppDispatch } from 'soapbox/hooks'; +import { useChat } from 'soapbox/queries/chats'; + +const ChatMessageListIntro = () => { + const dispatch = useAppDispatch(); + + const { chat, needsAcceptance } = useChatContext(); + const { acceptChat, deleteChat } = useChat(chat?.id as string); + + const handleLeaveChat = () => { + dispatch(openModal('CONFIRM', { + heading: 'Leave Chat', + message: 'Are you sure you want to leave this chat? This conversation will be removed from your inbox.', + confirm: 'Leave Chat', + confirmationTheme: 'primary', + onConfirm: () => { + deleteChat.mutate(); + }, + })); + }; + + const handleReportChat = () => { + dispatch(initReport(chat?.account)); + acceptChat.mutate(); + }; + + if (!chat) { + return null; + } + + return ( + + + + + {needsAcceptance ? ( + <> + @{chat.account.acct} + {' '} + wants to start a chat with you + + ) : ( + @{chat.account.acct} + )} + + + + {needsAcceptance ? ( + + + + + + + + + + ) : ( + + + + Messages older than 15 days are deleted. + + + )} + + ); +}; + +export default ChatMessageListIntro; diff --git a/app/soapbox/features/chats/components/chat-message-list.tsx b/app/soapbox/features/chats/components/chat-message-list.tsx index 0ee6bbff8..4c112ba92 100644 --- a/app/soapbox/features/chats/components/chat-message-list.tsx +++ b/app/soapbox/features/chats/components/chat-message-list.tsx @@ -13,9 +13,10 @@ import { createSelector } from 'reselect'; import { fetchChatMessages, deleteChatMessage } from 'soapbox/actions/chats'; import { openModal } from 'soapbox/actions/modals'; -import { initReportById } from 'soapbox/actions/reports'; -import { Avatar, HStack, IconButton, Spinner, Stack, Text } from 'soapbox/components/ui'; +import { initReport, initReportById } from 'soapbox/actions/reports'; +import { Avatar, Button, HStack, IconButton, Spinner, Stack, Text } from 'soapbox/components/ui'; import DropdownMenuContainer from 'soapbox/containers/dropdown_menu_container'; +import { useChatContext } from 'soapbox/contexts/chat-context'; import emojify from 'soapbox/features/emoji/emoji'; import PlaceholderChat from 'soapbox/features/placeholder/components/placeholder_chat'; import Bundle from 'soapbox/features/ui/components/bundle'; @@ -25,6 +26,8 @@ import { IChat, IChatMessage, useChat, useChatMessages } from 'soapbox/queries/c import { queryClient } from 'soapbox/queries/client'; import { onlyEmoji } from 'soapbox/utils/rich_content'; +import ChatMessageListIntro from './chat-message-list-intro'; + import type { Menu } from 'soapbox/components/dropdown_menu'; import type { ChatMessage as ChatMessageEntity } from 'soapbox/types/entities'; @@ -83,13 +86,14 @@ const ChatMessageList: React.FC = ({ chat, chatMessageIds, aut const [initialLoad, setInitialLoad] = useState(true); const [scrollPosition, setScrollPosition] = useState(0); - const { deleteChatMessage } = useChat(chat.id); + const { needsAcceptance } = useChatContext(); + + const { deleteChatMessage, acceptChat, deleteChat } = useChat(chat.id); const { data: chatMessages, isLoading, isFetching, isFetched, fetchNextPage, isFetchingNextPage, isPlaceholderData } = useChatMessages(chat.id); const formattedChatMessages = chatMessages || []; const me = useAppSelector(state => state.me); - const node = useRef(null); const messagesEnd = useRef(null); const lastComputedScroll = useRef(undefined); @@ -97,6 +101,7 @@ const ChatMessageList: React.FC = ({ chat, chatMessageIds, aut const initialCount = useMemo(() => formattedChatMessages.length, []); + const handleDeleteMessage = useMutation((chatMessageId: string) => deleteChatMessage(chatMessageId), { onSettled: () => { queryClient.invalidateQueries(['chats', 'messages', chat.id]); @@ -399,7 +404,11 @@ const ChatMessageList: React.FC = ({ chat, chatMessageIds, aut } return ( -
{/* style={{ height: autosize ? 'calc(100vh - 16rem)' : undefined }} */} +
{/* style={{ height: autosize ? 'calc(100vh - 16rem)' : undefined }} */} + {!isLoading ? ( + + ) : null} +
{isLoading ? ( <> diff --git a/app/soapbox/features/chats/components/chat-window.tsx b/app/soapbox/features/chats/components/chat-window.tsx index df9dc02a4..21311d37e 100644 --- a/app/soapbox/features/chats/components/chat-window.tsx +++ b/app/soapbox/features/chats/components/chat-window.tsx @@ -10,7 +10,7 @@ import ChatSettings from './chat-settings'; /** Floating desktop chat window. */ const ChatWindow = () => { - const { chat, setChat, isOpen, isEditing, setEditing, toggleChatPane } = useChatContext(); + const { chat, setChat, isOpen, isEditing, needsAcceptance, setEditing, toggleChatPane } = useChatContext(); const inputRef = useRef(); @@ -23,6 +23,14 @@ const ChatWindow = () => { const openChatSettings = () => setEditing(true); + const secondaryAction = () => { + if (needsAcceptance) { + return undefined; + } + + return isOpen ? openChatSettings : openAndFocusChat; + }; + if (!chat) return null; if (isEditing) { @@ -58,7 +66,7 @@ const ChatWindow = () => { } - secondaryAction={isOpen ? openChatSettings : openAndFocusChat} + secondaryAction={secondaryAction()} secondaryActionIcon={isOpen ? require('@tabler/icons/info-circle.svg') : require('@tabler/icons/edit.svg')} isToggleable={!isOpen} isOpen={isOpen} diff --git a/app/soapbox/queries/chats.ts b/app/soapbox/queries/chats.ts index c8ac84651..688b28bd2 100644 --- a/app/soapbox/queries/chats.ts +++ b/app/soapbox/queries/chats.ts @@ -93,7 +93,7 @@ const useChats = () => { const useChat = (chatId: string) => { const api = useApi(); - const { setChat } = useChatContext(); + const { setChat, setEditing } = useChatContext(); const markChatAsRead = () => api.post(`/api/v1/pleroma/chats/${chatId}/read`); @@ -114,6 +114,7 @@ const useChat = (chatId: string) => { const deleteChat = useMutation(() => api.delete(`/api/v1/pleroma/chats/${chatId}`), { onSuccess(response) { setChat(null); + setEditing(false); queryClient.invalidateQueries(['chats', 'messages', chatId]); queryClient.invalidateQueries(['chats']); },