clean up logic for showing request buttons (#7964)

This commit is contained in:
Samuel Newman
2025-03-11 20:12:49 +00:00
committed by Hailey
parent d155b718b5
commit 87569e206f
@@ -1,4 +1,4 @@
import React, {useCallback, useRef} from 'react' import {useCallback, useEffect, useRef, useState} from 'react'
import {LayoutChangeEvent, View} from 'react-native' import {LayoutChangeEvent, View} from 'react-native'
import {useKeyboardHandler} from 'react-native-keyboard-controller' import {useKeyboardHandler} from 'react-native-keyboard-controller'
import Animated, { import Animated, {
@@ -25,8 +25,12 @@ import {
import {logger} from '#/logger' import {logger} from '#/logger'
import {isNative} from '#/platform/detection' import {isNative} from '#/platform/detection'
import {isWeb} from '#/platform/detection' import {isWeb} from '#/platform/detection'
import {isConvoActive, useConvoActive} from '#/state/messages/convo' import {
import {ConvoItem, ConvoStatus} from '#/state/messages/convo/types' ActiveConvoStates,
isConvoActive,
useConvoActive,
} from '#/state/messages/convo'
import {ConvoItem, ConvoState, ConvoStatus} from '#/state/messages/convo/types'
import {useGetPost} from '#/state/queries/post' import {useGetPost} from '#/state/queries/post'
import {useAgent} from '#/state/session' import {useAgent} from '#/state/session'
import {useShellLayout} from '#/state/shell/shell-layout' import {useShellLayout} from '#/state/shell/shell-layout'
@@ -100,16 +104,15 @@ export function MessagesList({
const flatListRef = useAnimatedRef<ListMethods>() const flatListRef = useAnimatedRef<ListMethods>()
const [newMessagesPill, setNewMessagesPill] = React.useState({ const [newMessagesPill, setNewMessagesPill] = useState({
show: false, show: false,
startContentOffset: 0, startContentOffset: 0,
}) })
const [emojiPickerState, setEmojiPickerState] = const [emojiPickerState, setEmojiPickerState] = useState<EmojiPickerState>({
React.useState<EmojiPickerState>({ isOpen: false,
isOpen: false, pos: {top: 0, left: 0, right: 0, bottom: 0, nextFocusRef: null},
pos: {top: 0, left: 0, right: 0, bottom: 0, nextFocusRef: null}, })
})
// We need to keep track of when the scroll offset is at the bottom of the list to know when to scroll as new items // We need to keep track of when the scroll offset is at the bottom of the list to know when to scroll as new items
// are added to the list. For example, if the user is scrolled up to 1iew older messages, we don't want to scroll to // are added to the list. For example, if the user is scrolled up to 1iew older messages, we don't want to scroll to
@@ -126,8 +129,8 @@ export function MessagesList({
// -- Keep track of background state and positioning for new pill // -- Keep track of background state and positioning for new pill
const layoutHeight = useSharedValue(0) const layoutHeight = useSharedValue(0)
const didBackground = React.useRef(false) const didBackground = useRef(false)
React.useEffect(() => { useEffect(() => {
if (convoState.status === ConvoStatus.Backgrounded) { if (convoState.status === ConvoStatus.Backgrounded) {
didBackground.current = true didBackground.current = true
} }
@@ -218,7 +221,7 @@ export function MessagesList({
} }
}, [convoState, hasScrolled, layoutHeight]) }, [convoState, hasScrolled, layoutHeight])
const onScroll = React.useCallback( const onScroll = useCallback(
(e: ReanimatedScrollEvent) => { (e: ReanimatedScrollEvent) => {
'worklet' 'worklet'
layoutHeight.set(e.layoutMeasurement.height) layoutHeight.set(e.layoutMeasurement.height)
@@ -376,7 +379,7 @@ export function MessagesList({
) )
// -- List layout changes (opening emoji keyboard, etc.) // -- List layout changes (opening emoji keyboard, etc.)
const onListLayout = React.useCallback( const onListLayout = useCallback(
(e: LayoutChangeEvent) => { (e: LayoutChangeEvent) => {
layoutHeight.set(e.nativeEvent.layout.height) layoutHeight.set(e.nativeEvent.layout.height)
@@ -395,13 +398,17 @@ export function MessagesList({
], ],
) )
const scrollToEndOnPress = React.useCallback(() => { const scrollToEndOnPress = useCallback(() => {
flatListRef.current?.scrollToOffset({ flatListRef.current?.scrollToOffset({
offset: prevContentHeight.current, offset: prevContentHeight.current,
animated: true, animated: true,
}) })
}, [flatListRef]) }, [flatListRef])
const onOpenEmojiPicker = useCallback((pos: any) => {
setEmojiPickerState({isOpen: true, pos})
}, [])
return ( return (
<> <>
{/* Custom scroll provider so that we can use the `onScroll` event in our custom List implementation */} {/* Custom scroll provider so that we can use the `onScroll` event in our custom List implementation */}
@@ -440,41 +447,17 @@ export function MessagesList({
) : blocked ? ( ) : blocked ? (
footer footer
) : ( ) : (
isConvoActive(convoState) && <ConversationFooter
!convoState.isFetchingHistory && ( convoState={convoState}
<> hasAcceptOverride={hasAcceptOverride}>
{convoState.items.length === 0 ? ( <MessageInput
<> onSendMessage={onSendMessage}
<ChatEmptyPill /> hasEmbed={!!embedUri}
<MessageInput setEmbed={setEmbed}
onSendMessage={onSendMessage} openEmojiPicker={onOpenEmojiPicker}>
hasEmbed={!!embedUri} <MessageInputEmbed embedUri={embedUri} setEmbed={setEmbed} />
setEmbed={setEmbed} </MessageInput>
openEmojiPicker={pos => </ConversationFooter>
setEmojiPickerState({isOpen: true, pos})
}>
<MessageInputEmbed
embedUri={embedUri}
setEmbed={setEmbed}
/>
</MessageInput>
</>
) : convoState.convo.status === 'request' &&
!hasAcceptOverride ? (
<ChatStatusInfo convoState={convoState} />
) : (
<MessageInput
onSendMessage={onSendMessage}
hasEmbed={!!embedUri}
setEmbed={setEmbed}
openEmojiPicker={pos =>
setEmojiPickerState({isOpen: true, pos})
}>
<MessageInputEmbed embedUri={embedUri} setEmbed={setEmbed} />
</MessageInput>
)}
</>
)
)} )}
</Animated.View> </Animated.View>
@@ -490,3 +473,56 @@ export function MessagesList({
</> </>
) )
} }
type FooterState = 'loading' | 'new-chat' | 'request' | 'standard'
function getFooterState(
convoState: ActiveConvoStates,
hasAcceptOverride?: boolean,
): FooterState {
if (convoState.items.length === 0) {
if (convoState.isFetchingHistory) {
return 'loading'
} else {
return 'new-chat'
}
}
if (convoState.convo.status === 'request' && !hasAcceptOverride) {
return 'request'
}
return 'standard'
}
function ConversationFooter({
convoState,
hasAcceptOverride,
children,
}: {
convoState: ConvoState
hasAcceptOverride?: boolean
children?: React.ReactNode // message input
}) {
if (!isConvoActive(convoState)) {
return null
}
const footerState = getFooterState(convoState, hasAcceptOverride)
switch (footerState) {
case 'loading':
return null
case 'new-chat':
return (
<>
<ChatEmptyPill />
{children}
</>
)
case 'request':
return <ChatStatusInfo convoState={convoState} />
case 'standard':
return children
}
}