diff --git a/native/chat/sidebar-list-modal.react.js b/native/chat/sidebar-list-modal.react.js --- a/native/chat/sidebar-list-modal.react.js +++ b/native/chat/sidebar-list-modal.react.js @@ -1,7 +1,7 @@ // @flow import * as React from 'react'; -import { TextInput, FlatList, View } from 'react-native'; +import { View } from 'react-native'; import { useSearchSidebars } from 'lib/hooks/search-threads'; import type { ThreadInfo, SidebarInfo } from 'lib/types/thread-types'; @@ -9,26 +9,16 @@ import ExtendedArrow from '../components/arrow-extended.react'; import Arrow from '../components/arrow.react'; import Button from '../components/button.react'; -import Modal from '../components/modal.react'; -import Search from '../components/search.react'; import type { RootNavigationProp } from '../navigation/root-navigator.react'; import type { NavigationRoute } from '../navigation/route-names'; -import { useColors, useIndicatorStyle, useStyles } from '../themes/colors'; -import { waitForModalInputFocus } from '../utils/timers'; -import { useNavigateToThread } from './message-list-types'; +import { useColors, useStyles } from '../themes/colors'; import { SidebarItem } from './sidebar-item.react'; +import ThreadListModal from './thread-list-modal.react'; export type SidebarListModalParams = { +threadInfo: ThreadInfo, }; -function keyExtractor(sidebarInfo: SidebarInfo) { - return sidebarInfo.threadInfo.id; -} -function getItemLayout(data: ?$ReadOnlyArray, index: number) { - return { length: 24, offset: 24 * index, index }; -} - type Props = { +navigation: RootNavigationProp<'SidebarListModal'>, +route: NavigationRoute<'SidebarListModal'>, @@ -41,45 +31,13 @@ onChangeSearchInputText, } = useSearchSidebars(props.route.params.threadInfo); - const searchTextInputRef = React.useRef(); - const setSearchTextInputRef = React.useCallback( - async (textInput: ?React.ElementRef) => { - searchTextInputRef.current = textInput; - if (!textInput) { - return; - } - await waitForModalInputFocus(); - if (searchTextInputRef.current) { - searchTextInputRef.current.focus(); - } - }, - [], - ); - - const navigateToThread = useNavigateToThread(); - const onPressItem = React.useCallback( - (threadInfo: ThreadInfo) => { - setSearchState({ - text: '', - results: new Set(), - }); - if (searchTextInputRef.current) { - searchTextInputRef.current.blur(); - } - navigateToThread({ threadInfo }); - }, - [navigateToThread, setSearchState], - ); - - const styles = useStyles(unboundStyles); - - const numOfSidebarsWithExtendedArrow = React.useMemo( - () => listData.length - 1, - [listData], - ); + const numOfSidebarsWithExtendedArrow = listData.length - 1; - const renderItem = React.useCallback( - (row: { item: SidebarInfo, index: number, ... }) => { + const createRenderItem = React.useCallback( + ( + onPressItem: (threadInfo: ThreadInfo) => void, + // eslint-disable-next-line react/display-name + ) => (row: { +item: SidebarInfo, +index: number, ... }) => { let extendArrow: boolean = false; if (row.index < numOfSidebarsWithExtendedArrow) { extendArrow = true; @@ -92,29 +50,19 @@ /> ); }, - [onPressItem, numOfSidebarsWithExtendedArrow], + [numOfSidebarsWithExtendedArrow], ); - const indicatorStyle = useIndicatorStyle(); return ( - - - - + ); } @@ -177,9 +125,6 @@ position: 'absolute', top: -6, }, - search: { - marginBottom: 8, - }, sidebar: { backgroundColor: 'listBackground', paddingLeft: 0, diff --git a/native/chat/thread-list-modal.react.js b/native/chat/thread-list-modal.react.js new file mode 100644 --- /dev/null +++ b/native/chat/thread-list-modal.react.js @@ -0,0 +1,118 @@ +// @flow + +import * as React from 'react'; +import { TextInput, FlatList, StyleSheet } from 'react-native'; + +import type { ThreadSearchState } from 'lib/hooks/search-threads'; +import type { ChatThreadItem } from 'lib/selectors/chat-selectors'; +import type { SetState } from 'lib/types/hook-types'; +import type { ThreadInfo, SidebarInfo } from 'lib/types/thread-types'; + +import Modal from '../components/modal.react'; +import Search from '../components/search.react'; +import { useIndicatorStyle } from '../themes/colors'; +import { waitForModalInputFocus } from '../utils/timers'; +import { useNavigateToThread } from './message-list-types'; + +function keyExtractor(sidebarInfo: SidebarInfo | ChatThreadItem) { + return sidebarInfo.threadInfo.id; +} +function getItemLayout( + data: ?$ReadOnlyArray, + index: number, +) { + return { length: 24, offset: 24 * index, index }; +} + +type Props = { + +threadInfo: ThreadInfo, + +createRenderItem: ( + onPressItem: (threadInfo: ThreadInfo) => void, + ) => (row: { + +item: U, + +index: number, + ... + }) => React.Node, + +listData: $ReadOnlyArray, + +searchState: ThreadSearchState, + +setSearchState: SetState, + +onChangeSearchInputText: (text: string) => mixed, + +searchPlaceholder: string, +}; +function ThreadListModal( + props: Props, +): React.Node { + const { + searchState, + setSearchState, + onChangeSearchInputText, + listData, + createRenderItem, + searchPlaceholder, + } = props; + + const searchTextInputRef = React.useRef(); + const setSearchTextInputRef = React.useCallback( + async (textInput: ?React.ElementRef) => { + searchTextInputRef.current = textInput; + if (!textInput) { + return; + } + await waitForModalInputFocus(); + if (searchTextInputRef.current) { + searchTextInputRef.current.focus(); + } + }, + [], + ); + + const navigateToThread = useNavigateToThread(); + const onPressItem = React.useCallback( + (threadInfo: ThreadInfo) => { + setSearchState({ + text: '', + results: new Set(), + }); + if (searchTextInputRef.current) { + searchTextInputRef.current.blur(); + } + navigateToThread({ threadInfo }); + }, + [navigateToThread, setSearchState], + ); + + const renderItem = React.useMemo(() => createRenderItem(onPressItem), [ + createRenderItem, + onPressItem, + ]); + + const indicatorStyle = useIndicatorStyle(); + return ( + + + + + ); +} + +const styles = StyleSheet.create({ + search: { + marginBottom: 8, + }, +}); + +export default ThreadListModal;