diff --git a/web/chat/chat-thread-list-item.react.js b/web/chat/chat-thread-list-item.react.js index 61add2f33..7d007c2d6 100644 --- a/web/chat/chat-thread-list-item.react.js +++ b/web/chat/chat-thread-list-item.react.js @@ -1,85 +1,75 @@ // @flow -import { - type ChatThreadItem, - chatThreadItemPropType, -} from 'lib/selectors/chat-selectors'; -import type { Dispatch } from 'lib/types/redux-types'; -import { - type NavInfo, - navInfoPropType, - updateNavInfoActionType, -} from '../redux/redux-setup'; +import type { ChatThreadItem } from 'lib/selectors/chat-selectors'; +import { updateNavInfoActionType } from '../redux/redux-setup'; import * as React from 'react'; import classNames from 'classnames'; -import PropTypes from 'prop-types'; +import { useDispatch } from 'react-redux'; import { shortAbsoluteDate } from 'lib/utils/date-utils'; import css from './chat-thread-list.css'; import MessagePreview from './message-preview.react'; import ChatThreadListItemMenu from './chat-thread-list-item-menu.react'; +import { useSelector } from '../redux/redux-utils'; type Props = {| +item: ChatThreadItem, - +active: boolean, - +navInfo: NavInfo, - +timeZone: ?string, - +dispatch: Dispatch, |}; -class ChatThreadListItem extends React.PureComponent { - static propTypes = { - item: chatThreadItemPropType.isRequired, - active: PropTypes.bool.isRequired, - navInfo: navInfoPropType.isRequired, - timeZone: PropTypes.string, - dispatch: PropTypes.func.isRequired, - }; +function ChatThreadListItem(props: Props) { + const { item } = props; + const threadID = item.threadInfo.id; - render() { - const { item, timeZone } = this.props; - const lastActivity = shortAbsoluteDate(item.lastUpdatedTime, timeZone); - const colorSplotchStyle = { backgroundColor: `#${item.threadInfo.color}` }; - const unread = item.threadInfo.currentUser.unread; - const activeStyle = this.props.active ? css.activeThread : null; - return ( -
- -
-
{item.threadInfo.uiName}
-
-
-
- -
- {lastActivity} -
-
-
- -
- ); - } + const navInfo = useSelector((state) => state.navInfo); + const dispatch = useDispatch(); + const onClick = React.useCallback( + (event: SyntheticEvent) => { + event.preventDefault(); + dispatch({ + type: updateNavInfoActionType, + payload: { + ...navInfo, + activeChatThreadID: threadID, + }, + }); + }, + [dispatch, navInfo, threadID], + ); + + const timeZone = useSelector((state) => state.timeZone); + const lastActivity = shortAbsoluteDate(item.lastUpdatedTime, timeZone); - onClick = (event: SyntheticEvent) => { - event.preventDefault(); - this.props.dispatch({ - type: updateNavInfoActionType, - payload: { - ...this.props.navInfo, - activeChatThreadID: this.props.item.threadInfo.id, - }, - }); - }; + const active = threadID === navInfo.activeChatThreadID; + const activeStyle = active ? css.activeThread : null; + + const colorSplotchStyle = { backgroundColor: `#${item.threadInfo.color}` }; + const unread = item.threadInfo.currentUser.unread; + return ( +
+ + + ); } export default ChatThreadListItem; diff --git a/web/chat/chat-thread-list.react.js b/web/chat/chat-thread-list.react.js index d11b2b035..5b3e44755 100644 --- a/web/chat/chat-thread-list.react.js +++ b/web/chat/chat-thread-list.react.js @@ -1,82 +1,34 @@ // @flow -import { type NavInfo, navInfoPropType } from '../redux/redux-setup'; -import type { Dispatch } from 'lib/types/redux-types'; -import { - type ChatThreadItem, - chatThreadItemPropType, -} from 'lib/selectors/chat-selectors'; import type { ThreadInfo } from 'lib/types/thread-types'; import * as React from 'react'; -import PropTypes from 'prop-types'; -import { useDispatch } from 'react-redux'; import { webChatListData } from '../selectors/chat-selectors'; import { useSelector } from '../redux/redux-utils'; import ChatThreadListItem from './chat-thread-list-item.react'; -type BaseProps = {| +type Props = {| +filterThreads: (threadItem: ThreadInfo) => boolean, +emptyItem?: React.ComponentType<{||}>, |}; -type Props = {| - ...BaseProps, - // Redux state - +chatListData: $ReadOnlyArray, - +navInfo: NavInfo, - +timeZone: ?string, - // Redux dispatch functions - +dispatch: Dispatch, -|}; -class ChatThreadList extends React.PureComponent { - static propTypes = { - filterThreads: PropTypes.func.isRequired, - emptyItem: PropTypes.elementType, - chatListData: PropTypes.arrayOf(chatThreadItemPropType).isRequired, - navInfo: navInfoPropType.isRequired, - timeZone: PropTypes.string, - dispatch: PropTypes.func.isRequired, - }; - - render() { - const threads: React.Node[] = this.props.chatListData - .filter((item) => this.props.filterThreads(item.threadInfo)) +function ChatThreadList(props: Props) { + const { filterThreads, emptyItem } = props; + const chatListData = useSelector(webChatListData); + const listData: React.Node[] = React.useMemo(() => { + const threads = chatListData + .filter((item) => filterThreads(item.threadInfo)) .map((item) => ( - + )); - - if (threads.length === 0 && this.props.emptyItem) { - const EmptyItem = this.props.emptyItem; + if (threads.length === 0 && emptyItem) { + const EmptyItem = emptyItem; threads.push(); } - - return
{threads}
; - } + return threads; + }, [chatListData, filterThreads, emptyItem]); + return
{listData}
; } -export default React.memo(function ConnectedChatThreadList( - props: BaseProps, -) { - const chatListData = useSelector(webChatListData); - const navInfo = useSelector((state) => state.navInfo); - const timeZone = useSelector((state) => state.timeZone); - const dispatch = useDispatch(); - return ( - - ); -}); +export default ChatThreadList;