diff options
Diffstat (limited to 'src/screens/Messages/Conversation/MessagesList.tsx')
-rw-r--r-- | src/screens/Messages/Conversation/MessagesList.tsx | 180 |
1 files changed, 61 insertions, 119 deletions
diff --git a/src/screens/Messages/Conversation/MessagesList.tsx b/src/screens/Messages/Conversation/MessagesList.tsx index 25aaf28c4..ca32a6d68 100644 --- a/src/screens/Messages/Conversation/MessagesList.tsx +++ b/src/screens/Messages/Conversation/MessagesList.tsx @@ -1,24 +1,15 @@ -import React, {useCallback, useMemo, useRef, useState} from 'react' +import React, {useCallback, useMemo, useRef} from 'react' import {FlatList, View, ViewToken} from 'react-native' -import {Alert} from 'react-native' import {KeyboardAvoidingView} from 'react-native-keyboard-controller' -import {isWeb} from '#/platform/detection' +import {useChat} from '#/state/messages' +import {ChatProvider} from '#/state/messages' +import {ConvoItem, ConvoStatus} from '#/state/messages/convo' +import {isWeb} from 'platform/detection' import {MessageInput} from '#/screens/Messages/Conversation/MessageInput' import {MessageItem} from '#/screens/Messages/Conversation/MessageItem' -import { - useChat, - useChatLogQuery, - useSendMessageMutation, -} from '#/screens/Messages/Temp/query/query' import {Loader} from '#/components/Loader' import {Text} from '#/components/Typography' -import * as TempDmChatDefs from '#/temp/dm/defs' - -type MessageWithNext = { - message: TempDmChatDefs.MessageView | TempDmChatDefs.DeletedMessage - next: TempDmChatDefs.MessageView | TempDmChatDefs.DeletedMessage | null -} function MaybeLoader({isLoading}: {isLoading: boolean}) { return ( @@ -34,47 +25,43 @@ function MaybeLoader({isLoading}: {isLoading: boolean}) { ) } -function renderItem({item}: {item: MessageWithNext}) { - if (TempDmChatDefs.isMessageView(item.message)) - return <MessageItem item={item.message} next={item.next} /> - - if (TempDmChatDefs.isDeletedMessage(item)) return <Text>Deleted message</Text> +function renderItem({item}: {item: ConvoItem}) { + if (item.type === 'message') { + return <MessageItem item={item.message} next={item.nextMessage} /> + } else if (item.type === 'deleted-message') { + return <Text>Deleted message</Text> + } else if (item.type === 'pending-message') { + return <Text>{item.message.text}</Text> + } return null } -// TODO rm -// TEMP: This is a temporary function to generate unique keys for mutation placeholders -const generateUniqueKey = () => `_${Math.random().toString(36).substr(2, 9)}` - function onScrollToEndFailed() { // Placeholder function. You have to give FlatList something or else it will error. } -export function MessagesList({chatId}: {chatId: string}) { - const flatListRef = useRef<FlatList>(null) - - // Whenever we reach the end (visually the top), we don't want to keep calling it. We will set `isFetching` to true - // once the request for new posts starts. Then, we will change it back to false after the content size changes. - const isFetching = useRef(false) +export function MessagesList({convoId}: {convoId: string}) { + return ( + <ChatProvider convoId={convoId}> + <MessagesListInner /> + </ChatProvider> + ) +} +export function MessagesListInner() { + const chat = useChat() + const flatListRef = useRef<FlatList>(null) // We use this to know if we should scroll after a new clop is added to the list const isAtBottom = useRef(false) // Because the viewableItemsChanged callback won't have access to the updated state, we use a ref to store the // total number of clops // TODO this needs to be set to whatever the initial number of messages is - const totalMessages = useRef(10) + // const totalMessages = useRef(10) // TODO later - const [_, setShowSpinner] = useState(false) - - // Query Data - const {data: chat} = useChat(chatId) - const {mutate: sendMessage} = useSendMessageMutation(chatId) - useChatLogQuery() - const [onViewableItemsChanged, viewabilityConfig] = useMemo(() => { return [ (info: {viewableItems: Array<ViewToken>; changed: Array<ViewToken>}) => { @@ -93,23 +80,11 @@ export function MessagesList({chatId}: {chatId: string}) { if (isAtBottom.current) { flatListRef.current?.scrollToOffset({offset: 0, animated: true}) } - - isFetching.current = false - setShowSpinner(false) }, []) const onEndReached = useCallback(() => { - if (isFetching.current) return - isFetching.current = true - setShowSpinner(true) - - // Eventually we will add more here when we hit the top through RQuery - // We wouldn't actually use a timeout, but there would be a delay while loading - setTimeout(() => { - // Do something - setShowSpinner(false) - }, 1000) - }, []) + chat.service.fetchMessageHistory() + }, [chat]) const onInputFocus = useCallback(() => { if (!isAtBottom.current) { @@ -117,84 +92,51 @@ export function MessagesList({chatId}: {chatId: string}) { } }, []) - const onSendMessage = useCallback( - async (message: string) => { - if (!message) return - - try { - sendMessage({ - message, - tempId: generateUniqueKey(), - }) - } catch (e: any) { - Alert.alert(e.toString()) - } - }, - [sendMessage], - ) - const onInputBlur = useCallback(() => {}, []) - const messages = useMemo(() => { - if (!chat) return [] - - const filtered = chat.messages - .filter( - ( - message, - ): message is - | TempDmChatDefs.MessageView - | TempDmChatDefs.DeletedMessage => { - return ( - TempDmChatDefs.isMessageView(message) || - TempDmChatDefs.isDeletedMessage(message) - ) - }, - ) - .reduce((acc, message) => { - // convert [n1, n2, n3, ...] to [{message: n1, next: n2}, {message: n2, next: n3}, {message: n3, next: n4}, ...] - - return [...acc, {message, next: acc.at(-1)?.message ?? null}] - }, [] as MessageWithNext[]) - totalMessages.current = filtered.length - - return filtered - }, [chat]) - return ( <KeyboardAvoidingView style={{flex: 1, marginBottom: isWeb ? 20 : 85}} behavior="padding" keyboardVerticalOffset={70} contentContainerStyle={{flex: 1}}> - <FlatList - data={messages} - keyExtractor={item => item.message.id} - renderItem={renderItem} - contentContainerStyle={{paddingHorizontal: 10}} - inverted={true} - // In the future, we might want to adjust this value. Not very concerning right now as long as we are only - // dealing with text. But whenever we have images or other media and things are taller, we will want to lower - // this...probably. - initialNumToRender={20} - // Same with the max to render per batch. Let's be safe for now though. - maxToRenderPerBatch={25} - removeClippedSubviews={true} - onEndReached={onEndReached} - onScrollToIndexFailed={onScrollToEndFailed} - onContentSizeChange={onContentSizeChange} - onViewableItemsChanged={onViewableItemsChanged} - viewabilityConfig={viewabilityConfig} - maintainVisibleContentPosition={{ - minIndexForVisible: 1, - }} - ListFooterComponent={<MaybeLoader isLoading={false} />} - ref={flatListRef} - keyboardDismissMode="none" - /> + {chat.state.status === ConvoStatus.Ready && ( + <FlatList + data={chat.state.items} + keyExtractor={item => item.key} + renderItem={renderItem} + contentContainerStyle={{paddingHorizontal: 10}} + // In the future, we might want to adjust this value. Not very concerning right now as long as we are only + // dealing with text. But whenever we have images or other media and things are taller, we will want to lower + // this...probably. + initialNumToRender={20} + // Same with the max to render per batch. Let's be safe for now though. + maxToRenderPerBatch={25} + inverted={true} + onEndReached={onEndReached} + onScrollToIndexFailed={onScrollToEndFailed} + onContentSizeChange={onContentSizeChange} + onViewableItemsChanged={onViewableItemsChanged} + viewabilityConfig={viewabilityConfig} + maintainVisibleContentPosition={{ + minIndexForVisible: 0, + }} + ListFooterComponent={ + <MaybeLoader isLoading={chat.state.isFetchingHistory} /> + } + removeClippedSubviews={true} + ref={flatListRef} + keyboardDismissMode="none" + /> + )} + <View style={{paddingHorizontal: 10}}> <MessageInput - onSendMessage={onSendMessage} + onSendMessage={text => { + chat.service.sendMessage({ + text, + }) + }} onFocus={onInputFocus} onBlur={onInputBlur} /> |